Add 'car/' from commit 'eee0e8dc445691e600680f4abc77f2814b20b054'
git-subtree-dir: car git-subtree-mainline:1d29a5526cgit-subtree-split:eee0e8dc44
This commit is contained in:
121
car/GestureRecognition/HandRecHSV.py
Normal file
121
car/GestureRecognition/HandRecHSV.py
Normal file
@@ -0,0 +1,121 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Thu Nov 22 10:51:21 2018
|
||||
|
||||
@author: pivatom
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
||||
img = cv2.imread('H:\car\GestureRecognition\IMG_0825.jpg', 1)
|
||||
# img = cv2.imread('H:\car\GestureRecognition\IMG_0818.png', 1)
|
||||
|
||||
# Downscale the image
|
||||
img = cv2.resize(img, None, fx=0.1, fy=0.1, interpolation = cv2.INTER_AREA)
|
||||
|
||||
e1 = cv2.getTickCount()
|
||||
|
||||
# Hand Localization... possibly with YOLOv3? v2 is faster though...
|
||||
|
||||
|
||||
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
|
||||
|
||||
# Need to shift red pixels so they can be 0-20 rather than 250-~20
|
||||
img_hsv[:,:,0] = img_hsv[:,:,0] + 30
|
||||
img_hsv[:,:,0] = np.where(img_hsv[:,:,0] > 179, img_hsv[:,:,0] - 179, img_hsv[:,:,0])
|
||||
|
||||
img_hsv = cv2.GaussianBlur(img_hsv,(5,5),0)
|
||||
|
||||
lower_skin = (0, 0, 153)
|
||||
upper_skin = (45, 153, 255)
|
||||
|
||||
# Only need mask, as we can just use this to do the hand segmentation.
|
||||
mask = cv2.inRange(img_hsv, lower_skin, upper_skin)
|
||||
|
||||
# This takes a whole millisecond (approx), and does not seem very worth the cost.
|
||||
blur = cv2.GaussianBlur(mask,(5,5),0)
|
||||
ret, img_thresh = cv2.threshold(blur, 50, 255, cv2.THRESH_BINARY)
|
||||
|
||||
# Uncomment if not using blur and threshold.
|
||||
# img_thresh = mask
|
||||
|
||||
k = np.sum(img_thresh) / 255
|
||||
|
||||
# Taking indices for num of rows.
|
||||
x_ind = np.arange(0,img_thresh.shape[1])
|
||||
y_ind = np.arange(0,img_thresh.shape[0])
|
||||
coords_x = np.zeros((img_thresh.shape[0], img_thresh.shape[1]))
|
||||
coords_y = np.zeros((img_thresh.shape[0], img_thresh.shape[1]))
|
||||
coords_x[:,:] = x_ind
|
||||
|
||||
|
||||
# Even this is extremely quick as it goes through rows in the numpy array, which in python is much faster than columns
|
||||
for element in y_ind:
|
||||
coords_y[element,:] = element
|
||||
|
||||
# Now need to get the average x value and y value for centre of gravity
|
||||
xb = int(np.sum(coords_x[img_thresh == 255])/k)
|
||||
yb = int(np.sum(coords_y[img_thresh == 255])/k)
|
||||
|
||||
centre = (int(np.sum(coords_x[img_thresh == 255])/k), int(np.sum(coords_y[img_thresh == 255])/k))
|
||||
|
||||
# Calculate radius of circle:
|
||||
# May need to calculate diameter as well.
|
||||
# Just take min/max x values and y values
|
||||
x_min = np.min(coords_x[img_thresh == 255])
|
||||
x_max = np.max(coords_x[img_thresh == 255])
|
||||
y_min = np.min(coords_y[img_thresh == 255])
|
||||
y_max = np.max(coords_y[img_thresh == 255])
|
||||
|
||||
candidate_pts = [(x_min, y_min), (x_min, y_max), (x_max, y_min), (x_max, y_max)]
|
||||
radius = 0
|
||||
|
||||
# Check with each point to see which is furthest from the centre.
|
||||
for pt in candidate_pts:
|
||||
# Calculate Euclydian Distance
|
||||
new_distance = ((pt[0] - centre[0])**2 + (pt[1] - centre[1])**2)**(1/2)
|
||||
if new_distance > radius:
|
||||
radius = new_distance
|
||||
|
||||
radius = int(radius * 0.52)
|
||||
|
||||
# 140 needs to be replaced with a predicted value. i.e. not be a magic number.
|
||||
# cv2.circle(img_thresh, centre, radius, (120,0,0), 3)
|
||||
|
||||
def calc_pos_y(x):
|
||||
return int((radius**2 - (x - centre[0])**2)**(1/2) + centre[1])
|
||||
|
||||
# Now go around the circle to calculate num of times going 0->255 or vice-versa.
|
||||
# First just do it the naive way with loops.
|
||||
# Equation of the circle:
|
||||
# y = sqrt(r2 - (x-c)2) + c
|
||||
# Will just increment x to check, no need to loop y as well.
|
||||
# This is extremely slow, need to speed it up by removing for loop.
|
||||
# Brings speed down to 20 fps.
|
||||
# This is actually fast, it was just the print debug statements that made it slow, takes just 6ms...
|
||||
# Could try a kerel method?
|
||||
prev_x = centre[0] - radius
|
||||
prev_y = [calc_pos_y(centre[0] - radius), calc_pos_y(centre[0] - radius)]
|
||||
num_change = 0
|
||||
for x in range(centre[0] - radius + 1, centre[0] + radius):
|
||||
ypos = calc_pos_y(x)
|
||||
y = [ypos, centre[1] - (ypos-centre[1])]
|
||||
if(img_thresh[y[0], x] != img_thresh[prev_y[0], prev_x]):
|
||||
num_change += 1
|
||||
if img_thresh[y[1], x] != img_thresh[prev_y[1], prev_x] and y[0] != y[1]:
|
||||
num_change += 1
|
||||
prev_x = x
|
||||
prev_y = y
|
||||
|
||||
fingers = num_change / 2 - 1
|
||||
|
||||
print("Num Fingers: " + str(fingers))
|
||||
|
||||
e2 = cv2.getTickCount()
|
||||
t = (e2 - e1)/cv2.getTickFrequency()
|
||||
print( t )
|
||||
|
||||
cv2.imshow("Threshold", img_thresh)
|
||||
cv2.waitKey(0)
|
||||
cv2.destroyAllWindows()
|
||||
49
car/GestureRecognition/HandRecV2.py
Normal file
49
car/GestureRecognition/HandRecV2.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Thu Nov 22 09:21:04 2018
|
||||
|
||||
@author: pivatom
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
||||
min_seg_threshold = 1.05
|
||||
max_seg_threshold = 4
|
||||
|
||||
def calcSkinSample(event, x, y, flags, param):
|
||||
if event == cv2.EVENT_FLAG_LBUTTON:
|
||||
sample = img[x:x+10, y:y+10]
|
||||
min = 255
|
||||
max = 0
|
||||
for line in sample:
|
||||
avg = np.sum(line)/10
|
||||
if avg < min:
|
||||
min = avg
|
||||
if avg > max:
|
||||
max = avg
|
||||
min_seg_threshold = min
|
||||
max_seg_threshold = max
|
||||
|
||||
def draw_rect(event, x, y, flags, param):
|
||||
if event == cv2.EVENT_FLAG_LBUTTON:
|
||||
print("LbuttonClick")
|
||||
cv2.rectangle(img, (x,y), (x+10, y+10), (0,0,255), 3)
|
||||
|
||||
img = cv2.imread('H:\car\GestureRecognition\IMG_0818.png', 1)
|
||||
|
||||
# Downscale the image
|
||||
img = cv2.resize(img, None, fx=0.1, fy=0.1, interpolation = cv2.INTER_AREA)
|
||||
|
||||
cv2.namedWindow("Hand")
|
||||
cv2.setMouseCallback("Hand", draw_rect)
|
||||
|
||||
# prevent divide by zero, by just forcing pixel to be ignored.
|
||||
#np.where(img[:,:,1] == 0, 0, img[:,:,1])
|
||||
#img[(img[:,:,2]/img[:,:,1] > min_seg_threshold) & (img[:,:,2]/img[:,:,1] < max_seg_threshold)] = [255,255,255]
|
||||
|
||||
while(1):
|
||||
cv2.imshow("Hand", img)
|
||||
if cv2.waitKey(0):
|
||||
break
|
||||
cv2.destroyAllWindows()
|
||||
BIN
car/GestureRecognition/IMG_0818.png
Normal file
BIN
car/GestureRecognition/IMG_0818.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 MiB |
BIN
car/GestureRecognition/IMG_0825.jpg
Normal file
BIN
car/GestureRecognition/IMG_0825.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
BIN
car/GestureRecognition/Neural Network hand Tracking.pdf
Normal file
BIN
car/GestureRecognition/Neural Network hand Tracking.pdf
Normal file
Binary file not shown.
381
car/GestureRecognition/SimpleHandRecogniser.py
Normal file
381
car/GestureRecognition/SimpleHandRecogniser.py
Normal file
@@ -0,0 +1,381 @@
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
||||
from GestureRecognition.handrecogniser import HandRecogniser
|
||||
|
||||
class SimpleHandRecogniser(HandRecogniser):
|
||||
def __init__(self, frame):
|
||||
self.img = frame
|
||||
self.graph = None
|
||||
self.sess = None
|
||||
self.img_cut = None
|
||||
|
||||
def __calc_pos_y(self, x, radius, centre):
|
||||
"""
|
||||
Calculates the position of y on a given circle radius and centre, given coordinate x.
|
||||
"""
|
||||
return int((radius**2 - (x - centre[0])**2)**(1/2) + centre[1])
|
||||
|
||||
def __segment_image(self):
|
||||
"""
|
||||
Segments the hand from the rest of the image to get a threshold.
|
||||
"""
|
||||
self.img_cut = cv2.GaussianBlur(self.img_cut, (5, 5), 0)
|
||||
|
||||
lower_skin = (0, 0, 153)
|
||||
upper_skin = (45, 153, 255)
|
||||
|
||||
# Only need mask, as we can just use this to do the hand segmentation.
|
||||
self.img_cut = cv2.inRange(self.img_cut, lower_skin, upper_skin)
|
||||
|
||||
# Apply another blur to rmeove any small holes/noise
|
||||
self.img_cut = self.__denoise(self.img_cut)
|
||||
_, self.img_cut = cv2.threshold(self.img_cut, 50, 255, cv2.THRESH_BINARY)
|
||||
|
||||
def __denoise(self, image):
|
||||
"""
|
||||
Applies a 5x5 gaussian blur to remove noise from the image.
|
||||
"""
|
||||
return cv2.GaussianBlur(image, (5, 5), 0)
|
||||
|
||||
def __calc_circle(self, image, radius_percent=0.6):
|
||||
"""
|
||||
Calculates the equation of the circle (radius, centre) from a given
|
||||
threshold image, so that the circle is the center of gravity of the
|
||||
given threshold pixels, and the radius is by default 55% of the total
|
||||
size.
|
||||
"""
|
||||
k = np.sum(self.img_cut) / 255
|
||||
|
||||
# Taking indices for num of rows.
|
||||
x_ind = np.arange(0, self.img_cut.shape[1])
|
||||
y_ind = np.arange(0, self.img_cut.shape[0])
|
||||
coords_x = np.zeros((self.img_cut.shape[0], self.img_cut.shape[1]))
|
||||
coords_y = np.zeros((self.img_cut.shape[0], self.img_cut.shape[1]))
|
||||
coords_x[:, :] = x_ind
|
||||
|
||||
# Even this is extremely quick as it goes through rows in the numpy array,
|
||||
# which in python is much faster than columns
|
||||
for element in y_ind:
|
||||
coords_y[element, :] = element
|
||||
|
||||
# Now need to get the average x value and y value for centre of gravity
|
||||
centre = (int(np.sum(coords_x[self.img_cut == 255])/k), int(np.sum(coords_y[self.img_cut == 255])/k))
|
||||
|
||||
# Calculate radius of circle:
|
||||
# May need to calculate diameter as well.
|
||||
# Just take min/max x values and y values
|
||||
x_min = np.min(coords_x[self.img_cut == 255])
|
||||
x_max = np.max(coords_x[self.img_cut == 255])
|
||||
y_min = np.min(coords_y[self.img_cut == 255])
|
||||
y_max = np.max(coords_y[self.img_cut == 255])
|
||||
|
||||
candidate_pts = [(x_min, y_min), (x_min, y_max), (x_max, y_min), (x_max, y_max)]
|
||||
radius = 0
|
||||
|
||||
# Check with each point to see which is furthest from the centre.
|
||||
for pt in candidate_pts:
|
||||
# Calculate Euclydian Distance
|
||||
new_distance = ((pt[0] - centre[0])**2 + (pt[1] - centre[1])**2)**(1/2)
|
||||
if new_distance > radius:
|
||||
radius = new_distance
|
||||
|
||||
radius = int(radius * radius_percent)
|
||||
|
||||
return radius, centre
|
||||
|
||||
def __calc_circles(self, image, radius_percent_range=[0.6, 0.8], step = 0.1):
|
||||
"""
|
||||
Calculates the equation of the circle (radius, centre), but with
|
||||
several radii so that we can get a more accurate estimate of from a given
|
||||
threshold image, so that the circle is the center of gravity of the
|
||||
given threshold pixels.
|
||||
"""
|
||||
k = np.sum(self.img_cut) / 255
|
||||
|
||||
# Taking indices for num of rows.
|
||||
x_ind = np.arange(0,self.img_cut.shape[1])
|
||||
y_ind = np.arange(0,self.img_cut.shape[0])
|
||||
coords_x = np.zeros((self.img_cut.shape[0], self.img_cut.shape[1]))
|
||||
coords_y = np.zeros((self.img_cut.shape[0], self.img_cut.shape[1]))
|
||||
coords_x[:,:] = x_ind
|
||||
|
||||
# Even this is extremely quick as it goes through rows in the numpy array, which in python is much faster than columns
|
||||
for element in y_ind:
|
||||
coords_y[element,:] = element
|
||||
|
||||
# Now need to get the average x value and y value for centre of gravity
|
||||
centre = (int(np.sum(coords_x[self.img_cut == 255])/k), int(np.sum(coords_y[self.img_cut == 255])/k))
|
||||
|
||||
# Calculate radius of circle:
|
||||
# May need to calculate diameter as well.
|
||||
# Just take min/max x values and y values
|
||||
x_min = np.min(coords_x[self.img_cut == 255])
|
||||
x_max = np.max(coords_x[self.img_cut == 255])
|
||||
y_min = np.min(coords_y[self.img_cut == 255])
|
||||
y_max = np.max(coords_y[self.img_cut == 255])
|
||||
|
||||
candidate_pts = [(x_min, y_min), (x_min, y_max), (x_max, y_min), (x_max, y_max)]
|
||||
radius = 0
|
||||
|
||||
# Check with each point to see which is furthest from the centre.
|
||||
for pt in candidate_pts:
|
||||
# Calculate Euclydian Distance
|
||||
new_distance = ((pt[0] - centre[0])**2 + (pt[1] - centre[1])**2)**(1/2)
|
||||
if new_distance > radius:
|
||||
radius = new_distance
|
||||
|
||||
radii = []
|
||||
for i in range(radius_percent_range[0], radius_percent_range[1], step):
|
||||
radii += int(radius * i)
|
||||
|
||||
return radii, centre
|
||||
|
||||
def __shift_pixels(self, image, shift_radius):
|
||||
image[:, :, 0] = image[:, :, 0] + shift_radius
|
||||
image[:, :, 0] = np.where(image[:, :, 0] > 179, image[:, :, 0] - 179, image[:, :, 0])
|
||||
return image
|
||||
|
||||
def set_frame(self, frame):
|
||||
self.img = frame
|
||||
|
||||
# Source: Victor Dibia
|
||||
# Link: https://github.com/victordibia/handtracking
|
||||
# Taken the code straight from his example, as it works perfectly. This is specifically
|
||||
# from the load_inference_graph method that he wrote, and will load the graph into
|
||||
# memory if one has not already been loaded for this object.
|
||||
# def load_inference_graph(self):
|
||||
# """Loads a tensorflow model checkpoint into memory"""
|
||||
|
||||
# if self.graph != None and self.sess != None:
|
||||
# # Don't load more than once, to save time...
|
||||
# return
|
||||
|
||||
# PATH_TO_CKPT = '/Users/piv/Documents/Projects/car/GestureRecognition/frozen_inference_graph.pb'
|
||||
# # load frozen tensorflow model into memory
|
||||
# detection_graph = tf.Graph()
|
||||
# with detection_graph.as_default():
|
||||
# od_graph_def = tf.GraphDef()
|
||||
# with tf.gfile.GFile(PATH_TO_CKPT, 'rb') as fid:
|
||||
# serialized_graph = fid.read()
|
||||
# od_graph_def.ParseFromString(serialized_graph)
|
||||
# tf.import_graph_def(od_graph_def, name='')
|
||||
# sess = tf.Session(graph=detection_graph)
|
||||
# self.graph = detection_graph
|
||||
# self.sess = sess
|
||||
|
||||
|
||||
# Source: Victor Dibia
|
||||
# Link: https://github.com/victordibia/handtracking
|
||||
# Taken the code straight from his example, as it works perfectly. This is specifically
|
||||
# from the detect_hand method that he wrote, as other processing is required for the
|
||||
# hand recognition to work correctly.
|
||||
# def detect_hand_tensorflow(self, detection_graph, sess):
|
||||
# """ Detects hands in a frame using a CNN
|
||||
|
||||
# detection_graph -- The CNN to use to detect the hand.
|
||||
# sess -- THe tensorflow session for the given graph
|
||||
# """
|
||||
|
||||
# image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')
|
||||
|
||||
# detection_boxes = detection_graph.get_tensor_by_name('detection_boxes:0')
|
||||
|
||||
# detection_scores = detection_graph.get_tensor_by_name('detection_scores:0')
|
||||
|
||||
# detection_classes = detection_graph.get_tensor_by_name('detection_classes:0')
|
||||
|
||||
# num_detections = detection_graph.get_tensor_by_name('num_detections:0')
|
||||
|
||||
# img_expanded = np.expand_dims(self.img, axis=0)
|
||||
|
||||
# (boxes, scores, classes, num) = sess.run(
|
||||
# [detection_boxes, detection_scores, detection_classes, num_detections],
|
||||
# feed_dict={image_tensor: img_expanded})
|
||||
# print('finished detection')
|
||||
# return np.squeeze(boxes), np.squeeze(scores)
|
||||
|
||||
def load_cv_net(self, graph_path, names_path):
|
||||
"""Loads a tensorflow neural object detection network using openCV
|
||||
|
||||
Arguments
|
||||
graph_path: Path to the tensorflow frozen inference graph (something.pb)
|
||||
names_path: Path to the tensorflow (something.pbtext) file.
|
||||
"""
|
||||
self.net = cv2.dnn.readNetFromTensorflow(graph_path, names_path)
|
||||
|
||||
def detect_hand_opencv(self):
|
||||
"""Performs hand detection using a CNN from tensorflow using opencv.
|
||||
|
||||
detection_graph -- The CNN to use to detect the hand.
|
||||
sess -- THe tensorflow session for the given graph
|
||||
"""
|
||||
if self.img is None:
|
||||
return
|
||||
|
||||
rows = self.img.shape[0]
|
||||
cols = self.img.shape[1]
|
||||
|
||||
self.net.setInput(cv2.dnn.blobFromImage(self.img, size=(300, 300), swapRB=True, crop=False))
|
||||
cv_out = self.net.forward()
|
||||
|
||||
boxes = []
|
||||
scores = []
|
||||
|
||||
for detection in cv_out[0, 0, :, :]:
|
||||
score = float(detection[2])
|
||||
# TODO: Need to make this the confidence threshold...
|
||||
if score > 0.6:
|
||||
left = detection[3] * cols
|
||||
top = detection[4] * rows
|
||||
right = detection[5] * cols
|
||||
bottom = detection[6] * rows
|
||||
boxes.append((left, top, right, bottom))
|
||||
scores.append(score)
|
||||
else:
|
||||
# Scores are in descending order...
|
||||
break
|
||||
|
||||
return boxes, scores
|
||||
|
||||
def get_best_hand(self, boxes, scores, conf_thresh, nms_thresh):
|
||||
"""
|
||||
Gets the best hand bounding box by inspecting confidence scores and overlapping
|
||||
boxes, as well as the overall size of each box to determine which hand (if multiple present)
|
||||
should be tested to recognise.
|
||||
"""
|
||||
print(scores)
|
||||
boxes = boxes[scores > conf_thresh]
|
||||
scores = scores[scores > conf_thresh]
|
||||
# Use NMS to get rid of heavily overlapping boxes.
|
||||
# This wasn't used in the tensorflow example that was found, however probably a
|
||||
# good idea to use it just in case.
|
||||
print(boxes.shape)
|
||||
if boxes.shape[0] == 0:
|
||||
print("No good boxes found")
|
||||
return None
|
||||
elif boxes.shape[0] == 1:
|
||||
print("Only one good box!")
|
||||
box = boxes[0]
|
||||
box[0] = box[0] * self.img.shape[0]
|
||||
box[1] = box[1] * self.img.shape[1]
|
||||
box[2] = box[2] * self.img.shape[0]
|
||||
box[3] = box[3] * self.img.shape[1]
|
||||
return box.astype(int)
|
||||
else:
|
||||
boxes[:][2] = ((boxes[:][2] - boxes[:][0]) * self.img.shape[0]).astype(int)
|
||||
boxes[:][3] = ((boxes[:][3] - boxes[:][1]) * self.img.shape[1]).astype(int)
|
||||
boxes[:][0] = (boxes[:][0] * self.img.shape[0]).astype(int)
|
||||
boxes[:][1] = (boxes[:][1] * self.img.shape[1]).astype(int)
|
||||
|
||||
# Can't seem to get this to work...
|
||||
# indices = cv2.dnn.NMSBoxes(boxes, scores, conf_thresh, nms_thresh)
|
||||
|
||||
print("Num boxes: %s" % boxes.shape[0])
|
||||
# Finally calculate area of each box to determine which hand is clearest (biggest in image)
|
||||
# Just does the most confident for now.
|
||||
best_box = boxes[0]
|
||||
best_index = None
|
||||
i = 0
|
||||
for box in boxes:
|
||||
if box[2] * box[3] > best_box[2] * best_box[3]:
|
||||
best_box = box
|
||||
best_index = i
|
||||
i += 1
|
||||
return boxes[i - 1]
|
||||
|
||||
def get_gesture(self):
|
||||
"""
|
||||
Calculates the actual gesture, returning the number of fingers
|
||||
seen in the image.
|
||||
"""
|
||||
print('Getting Gesture')
|
||||
if self.img is None:
|
||||
print('There is no image')
|
||||
return -1
|
||||
# First cut out the frame using the neural network.
|
||||
# self.load_inference_graph()
|
||||
# print("loaded inference graph")
|
||||
# detections, scores = self.detect_hand_tensorflow(self.graph, self.sess)
|
||||
|
||||
print('Loading openCV net')
|
||||
self.load_cv_net('/Users/piv/Documents/Projects/car/GestureRecognition/frozen_inference_graph.pb',
|
||||
'/Users/piv/Documents/Projects/car/GestureRecognition/graph.pbtxt')
|
||||
|
||||
detections, scores = self.detect_hand_opencv()
|
||||
|
||||
# print("Getting best hand")
|
||||
# best_hand = self.get_best_hand(detections, scores, 0.7, 0.5)
|
||||
# if best_hand is not None:
|
||||
# self.img = self.img[best_hand[0] - 30:best_hand[2] + 30, best_hand[1] - 30:best_hand[3] + 30]
|
||||
|
||||
if len(detections) > 0:
|
||||
print("Cutting out the hand!")
|
||||
self.img_cut = self.img[detections[0] - 30:detections[2] + 30, detections[1] - 30:detections[3] + 30]
|
||||
else:
|
||||
self.img_cut = self.img
|
||||
|
||||
print('Attempting to use pure hand recognition')
|
||||
self.img_cut = cv2.cvtColor(self.img_cut, cv2.COLOR_BGR2HSV)
|
||||
|
||||
# Need to shift red pixels so they can be 0-20 rather than 250-~20
|
||||
self.img_cut = self.__shift_pixels(self.img_cut, 30)
|
||||
|
||||
self.img_cut = self.__denoise(self.img_cut)
|
||||
self.__segment_image()
|
||||
|
||||
print('calculating circle')
|
||||
# Could calculate multiple circles to get probability
|
||||
# for each gesture (i.e. calc num of each gesture recongised and take percentage
|
||||
# as the probability).
|
||||
radius, centre = self.__calc_circle(self.img_cut)
|
||||
print('Got circle')
|
||||
|
||||
# Now go around the circle to calculate num of times going 0->255 or vice-versa.
|
||||
# First just do it the naive way with loops.
|
||||
# Equation of the circle:
|
||||
# y = sqrt(r2 - (x-c)2) + c
|
||||
prev_x = centre[0] - radius
|
||||
prev_y = [self.__calc_pos_y(centre[0] - radius, radius, centre),
|
||||
self.__calc_pos_y(centre[0] - radius, radius, centre)]
|
||||
num_change = 0
|
||||
|
||||
# Make sure x is also within bounds.
|
||||
x_start = centre[0] - radius + 1
|
||||
if x_start < 0:
|
||||
x_start = 0
|
||||
|
||||
x_end = centre[0] + radius
|
||||
if x_end >= self.img_cut.shape[1]:
|
||||
x_end = self.img_cut.shape[1] - 1
|
||||
|
||||
for x in range(x_start, x_end):
|
||||
# Need to check circle is inside the bounds.
|
||||
ypos = self.__calc_pos_y(x, radius, centre)
|
||||
# y above centre (ypos) and y below radius)
|
||||
y = [ypos, centre[1] - (ypos-centre[1])]
|
||||
|
||||
if y[0] < 0:
|
||||
y[0] = 0
|
||||
if y[0] >= self.img_cut.shape[0]:
|
||||
y[0] = self.img_cut.shape[0] - 1
|
||||
if y[1] < 0:
|
||||
y[1] = 0
|
||||
if y[1] >= self.img_cut.shape[0]:
|
||||
y[1] = self.img_cut.shape[0] - 1
|
||||
if(self.img_cut[y[0], x] != self.img_cut[prev_y[0], prev_x]):
|
||||
num_change += 1
|
||||
if self.img_cut[y[1], x] != self.img_cut[prev_y[1], prev_x] and y[0] != y[1]:
|
||||
num_change += 1
|
||||
prev_x = x
|
||||
prev_y = y
|
||||
|
||||
print('Finished calculating, returning')
|
||||
print(num_change)
|
||||
return int(num_change / 2 - 1), self.img
|
||||
|
||||
def get_gesture_multiple_radii(self):
|
||||
pass
|
||||
|
||||
def calc_hand_batch(self, batch):
|
||||
pass
|
||||
0
car/GestureRecognition/__init__.py
Normal file
0
car/GestureRecognition/__init__.py
Normal file
BIN
car/GestureRecognition/frozen_inference_graph.pb
Normal file
BIN
car/GestureRecognition/frozen_inference_graph.pb
Normal file
Binary file not shown.
3146
car/GestureRecognition/graph.pbtxt
Normal file
3146
car/GestureRecognition/graph.pbtxt
Normal file
File diff suppressed because it is too large
Load Diff
15
car/GestureRecognition/handrecogniser.py
Normal file
15
car/GestureRecognition/handrecogniser.py
Normal file
@@ -0,0 +1,15 @@
|
||||
class HandRecogniser:
|
||||
"""
|
||||
Interface for Recognising simple hand gestures from an image (or frame of a video)
|
||||
"""
|
||||
def load_image(self, image_path = ""):
|
||||
"""
|
||||
Loads the given image, can be lazy loading.
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_gesture(self):
|
||||
"""
|
||||
Gets a the gesture recognised in the image.
|
||||
"""
|
||||
pass
|
||||
73
car/GestureRecognition/kaleidoscope.py
Normal file
73
car/GestureRecognition/kaleidoscope.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
||||
def make_triangle(start_img):
|
||||
h, w, d = start_img.shape
|
||||
|
||||
#crop square
|
||||
inset = int((max(w,h) - min(w,h)) / 2)
|
||||
# sqrimg = start_img.crop(inset, inset, h-inset, w-inset)
|
||||
insetW = inset if w > h else 0
|
||||
insetH = inset if h > w else 0
|
||||
sqrimg = start_img[insetH:h-insetH, insetW:w-insetW]
|
||||
|
||||
#solve equilateral triangle
|
||||
w, h, d = sqrimg.shape
|
||||
print((w,h))
|
||||
|
||||
mask = np.zeros((w,h,d))
|
||||
|
||||
t_height = w/2 * np.tan(60)
|
||||
pts = np.array([[0,w],[h/2,t_height],[h,w]], np.int32)
|
||||
pts = pts.reshape((-1,1,2))
|
||||
mask = cv2.fillPoly(mask, [pts], (255,0,0))
|
||||
|
||||
# With mask, get the triangle from the original image.
|
||||
sqrimg[:,:,0] = np.where(mask[:,:,0] == 255, sqrimg[:,:,0], 0)
|
||||
sqrimg[:,:,1] = np.where(mask[:,:,0] == 255, sqrimg[:,:,1], 0)
|
||||
sqrimg[:,:,2] = np.where(mask[:,:,0] == 255, sqrimg[:,:,2], 0)
|
||||
return sqrimg
|
||||
|
||||
def rotate(im, rotation):
|
||||
M = cv2.getRotationMatrix2D((im.shape[1]/2,im.shape[0]/2),rotation,1)
|
||||
im[:,:,0] = cv2.warpAffine(im[:,:,0],M,(im.shape[1],im.shape[0]))
|
||||
im[:,:,1] = cv2.warpAffine(im[:,:,1],M,(im.shape[1],im.shape[0]))
|
||||
im[:,:,2] = cv2.warpAffine(im[:,:,2],M,(im.shape[1],im.shape[0]))
|
||||
return im
|
||||
|
||||
def make_kaleidoscope(img):
|
||||
triangle = make_triangle(img)
|
||||
|
||||
def make_trapezoid(triangle, save=False):
|
||||
|
||||
w, h = triangle.size
|
||||
can_w, can_h = w*3, h
|
||||
output = np.array((can_w, can_h, 3))
|
||||
output = Image.new('RGBA', (can_w, can_h), color=255)
|
||||
|
||||
def mirror_paste(last_img, coords):
|
||||
mirror = rotate(cv2.flip(last_img, 1), 60)
|
||||
output.paste(mirror, (coords), mirror)
|
||||
return mirror, coords
|
||||
|
||||
#paste in bottom left corner
|
||||
output.paste(triangle,(0, can_h-h), triangle)
|
||||
|
||||
last_img, coords = mirror_paste(triangle, (int(w/4.4), -int(h/2.125)))
|
||||
last_img, coords = mirror_paste(rotateIm(last_img, 120), (int(can_w/7.3), -228))
|
||||
|
||||
output = output.crop((0,15, w*2-22, h))
|
||||
if save:
|
||||
path = 'output/trapezoid_{}'.format(filename.split('/')[1])
|
||||
output.save(path)
|
||||
return output, path
|
||||
return output
|
||||
|
||||
if __name__ == "__main__":
|
||||
img = cv2.imread("/Users/piv/Documents/Projects/car/GestureRecognition/IMG_0818.png")
|
||||
triangle = make_triangle(img)
|
||||
triangle = cv2.resize(triangle, None, fx=0.3, fy=0.3, interpolation = cv2.INTER_AREA)
|
||||
triangle = rotate(triangle, 180)
|
||||
cv2.imshow("", triangle)
|
||||
cv2.waitKey(0)
|
||||
cv2.destroyAllWindows()
|
||||
28
car/GestureRecognition/keras_ex.py
Normal file
28
car/GestureRecognition/keras_ex.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import time
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
|
||||
os.environ["KERAS_BACKEND"] = "plaidml.keras.backend"
|
||||
|
||||
import keras
|
||||
import keras.applications as kapp
|
||||
from keras.datasets import cifar10
|
||||
|
||||
(x_train, y_train_cats), (x_test, y_test_cats) = cifar10.load_data()
|
||||
batch_size = 8
|
||||
x_train = x_train[:batch_size]
|
||||
x_train = np.repeat(np.repeat(x_train, 7, axis=1), 7, axis=2)
|
||||
model = kapp.VGG19()
|
||||
model.compile(optimizer='sgd', loss='categorical_crossentropy',
|
||||
metrics=['accuracy'])
|
||||
|
||||
print("Running initial batch (compiling tile program)")
|
||||
y = model.predict(x=x_train, batch_size=batch_size)
|
||||
|
||||
# Now start the clock and run 10 batches
|
||||
print("Timing inference...")
|
||||
start = time.time()
|
||||
for i in range(10):
|
||||
y = model.predict(x=x_train, batch_size=batch_size)
|
||||
print("Ran in {} seconds".format(time.time() - start))
|
||||
23
car/GestureRecognition/opencvtensorflowex.py
Normal file
23
car/GestureRecognition/opencvtensorflowex.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import cv2 as cv
|
||||
|
||||
cvNet = cv.dnn.readNetFromTensorflow('frozen_inference_graph.pb', 'graph.pbtxt')
|
||||
|
||||
img = cv.imread('IMG_0825.jpg')
|
||||
img = cv.resize(img, None, fx=0.1, fy=0.1, interpolation = cv.INTER_AREA)
|
||||
rows = img.shape[0]
|
||||
cols = img.shape[1]
|
||||
print(str(rows) + " " + str(cols))
|
||||
cvNet.setInput(cv.dnn.blobFromImage(img, size=(300, 300), swapRB=True, crop=False))
|
||||
cvOut = cvNet.forward()
|
||||
|
||||
for detection in cvOut[0,0,:,:]:
|
||||
score = float(detection[2])
|
||||
if score > 0.6:
|
||||
left = detection[3] * cols
|
||||
top = detection[4] * rows
|
||||
right = detection[5] * cols
|
||||
bottom = detection[6] * rows
|
||||
cv.rectangle(img, (int(left), int(top)), (int(right), int(bottom)), (23, 230, 210), thickness=2)
|
||||
|
||||
cv.imshow('img', img)
|
||||
cv.waitKey()
|
||||
58
car/GestureRecognition/starkaleid.py
Normal file
58
car/GestureRecognition/starkaleid.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
||||
def make_triangle(img, num_triangles):
|
||||
print(img.shape)
|
||||
y,x = (img.shape[0]//2, img.shape[1]//2)
|
||||
angles = 2 * np.pi/num_triangles
|
||||
print(angles/2)
|
||||
w,h,d = img.shape
|
||||
print(np.tan(angles/2))
|
||||
z = int(np.tan(angles/2) * (h/2))
|
||||
print(z)
|
||||
print(h)
|
||||
u = (x + z, y + h/2)
|
||||
v = (x - z, y + h/2)
|
||||
mask = np.zeros((w,h,d))
|
||||
|
||||
pts = np.array([v,(x,y),u], np.int32)
|
||||
pts = pts.reshape((-1,1,2))
|
||||
mask = cv2.fillPoly(mask, [pts], (255,0,0))
|
||||
|
||||
# With mask, get the triangle from the original image.
|
||||
img[:,:,0] = np.where(mask[:,:,0] == 255, img[:,:,0], 0)
|
||||
img[:,:,1] = np.where(mask[:,:,0] == 255, img[:,:,1], 0)
|
||||
img[:,:,2] = np.where(mask[:,:,0] == 255, img[:,:,2], 0)
|
||||
return img
|
||||
|
||||
def rotate(im, rotation):
|
||||
M = cv2.getRotationMatrix2D((im.shape[1]/2,im.shape[0]/2), rotation, 1)
|
||||
im[:,:,0] = cv2.warpAffine(im[:,:,0],M,(im.shape[1],im.shape[0]))
|
||||
im[:,:,1] = cv2.warpAffine(im[:,:,1],M,(im.shape[1],im.shape[0]))
|
||||
im[:,:,2] = cv2.warpAffine(im[:,:,2],M,(im.shape[1],im.shape[0]))
|
||||
return im
|
||||
|
||||
def _stitch(img, to_stitch):
|
||||
img[:,:,0] = np.where((img[:,:,0] == 0) & (to_stitch[:,:,0] != 0), to_stitch[:,:,0], img[:,:,0])
|
||||
img[:,:,1] = np.where((img[:,:,1] == 0) & (to_stitch[:,:,1] != 0), to_stitch[:,:,1], img[:,:,1])
|
||||
img[:,:,2] = np.where((img[:,:,2] == 0) & (to_stitch[:,:,2] != 0), to_stitch[:,:,2], img[:,:,2])
|
||||
|
||||
def make_kaleidoscope(img, num):
|
||||
triangle = make_triangle(img, num)
|
||||
iters = num
|
||||
while iters > 0:
|
||||
new_triangle = np.copy(triangle)
|
||||
new_triangle = cv2.flip(new_triangle, 1) if iters % 2 != 0 else new_triangle
|
||||
rotate(new_triangle, 360/num * iters)
|
||||
_stitch(triangle, new_triangle)
|
||||
iters -= 1
|
||||
return triangle
|
||||
|
||||
if __name__ == "__main__":
|
||||
img = cv2.imread("/Users/piv/Documents/Projects/car/GestureRecognition/IMG_0818.png")
|
||||
img = cv2.resize(img, None, fx=0.3, fy=0.3, interpolation = cv2.INTER_AREA)
|
||||
num = 12
|
||||
kaleid = make_kaleidoscope(img, num)
|
||||
cv2.imshow("", kaleid)
|
||||
cv2.waitKey(0)
|
||||
cv2.destroyAllWindows()
|
||||
Reference in New Issue
Block a user