diff --git a/HandDetection_py3.py b/HandDetection_py3.py new file mode 100644 index 0000000..7e359e7 --- /dev/null +++ b/HandDetection_py3.py @@ -0,0 +1,203 @@ +import cv2 +import numpy as np +import time + +#Open Camera object +cap = cv2.VideoCapture(0) + +#Decrease frame size +cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1080) +cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) +#cap.set(cv.CV_CAP_PROP_FRAME_WIDTH, 1000) +#cap.set(CV_CAP_PROP_FRAME_HEIGHT, 600) + +def nothing(x): + pass + +# Function to find angle between two vectors +def Angle(v1,v2): + dot = np.dot(v1,v2) + x_modulus = np.sqrt((v1*v1).sum()) + y_modulus = np.sqrt((v2*v2).sum()) + cos_angle = dot / x_modulus / y_modulus + angle = np.degrees(np.arccos(cos_angle)) + return angle + +# Function to find distance between two points in a list of lists +def FindDistance(A,B): + return np.sqrt(np.power((A[0][0]-B[0][0]),2) + np.power((A[0][1]-B[0][1]),2)) + + +# Creating a window for HSV track bars +cv2.namedWindow('HSV_TrackBar') + +# Starting with 100's to prevent error while masking +h,s,v = 100,100,100 + +# Creating track bar +cv2.createTrackbar('h', 'HSV_TrackBar',0,179,nothing) +cv2.createTrackbar('s', 'HSV_TrackBar',0,255,nothing) +cv2.createTrackbar('v', 'HSV_TrackBar',0,255,nothing) + +while(1): + + #Measure execution time + start_time = time.time() + + #Capture frames from the camera + ret, frame = cap.read() + + #Blur the image + blur = cv2.blur(frame,(3,3)) + + #Convert to HSV color space + hsv = cv2.cvtColor(blur,cv2.COLOR_BGR2HSV) + + #Create a binary image with where white will be skin colors and rest is black + mask2 = cv2.inRange(hsv,np.array([2,50,50]),np.array([15,255,255])) + + #Kernel matrices for morphological transformation + kernel_square = np.ones((11,11),np.uint8) + kernel_ellipse= cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5)) + + #Perform morphological transformations to filter out the background noise + #Dilation increase skin color area + #Erosion increase skin color area + dilation = cv2.dilate(mask2,kernel_ellipse,iterations = 1) + erosion = cv2.erode(dilation,kernel_square,iterations = 1) + dilation2 = cv2.dilate(erosion,kernel_ellipse,iterations = 1) + filtered = cv2.medianBlur(dilation2,5) + kernel_ellipse= cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(8,8)) + dilation2 = cv2.dilate(filtered,kernel_ellipse,iterations = 1) + kernel_ellipse= cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5)) + dilation3 = cv2.dilate(filtered,kernel_ellipse,iterations = 1) + median = cv2.medianBlur(dilation2,5) + ret,thresh = cv2.threshold(median,127,255,0) + + #Find contours of the filtered frame + nanika, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) + print(contours) + + #Draw Contours + # cv2.drawContours(frame, cnt, -1, (122,122,0), 3) + # #cv2.imshow('Dilation',median) + + #Find Max contour area (Assume that hand is in the frame) + max_area=100 + ci=0 + for i in range(len(contours)): + cnt=contours[i] + area = cv2.contourArea(cnt) + if(area>max_area): + max_area=area + ci=i + + #Largest area contour + print("contours: ",len(contours)) + print("ci:", ci) + if ci != 0: + cnts = contours[ci] + + #Find convex hull + hull = cv2.convexHull(cnts) + + #Find convex defects + hull2 = cv2.convexHull(cnts,returnPoints = False) + defects = cv2.convexityDefects(cnts,hull2) + + #Get defect points and draw them in the original image + FarDefect = [] + for i in range(defects.shape[0]): + s,e,f,d = defects[i,0] + start = tuple(cnts[s][0]) + end = tuple(cnts[e][0]) + far = tuple(cnts[f][0]) + FarDefect.append(far) + cv2.line(frame,start,end,[0,255,0],1) + cv2.circle(frame,far,10,[100,255,255],3) + + #Find moments of the largest contour + moments = cv2.moments(cnts) + + #Central mass of first order moments + if moments['m00']!=0: + cx = int(moments['m10']/moments['m00']) # cx = M10/M00 + cy = int(moments['m01']/moments['m00']) # cy = M01/M00 + centerMass=(cx,cy) + + #Draw center mass + cv2.circle(frame,centerMass,7,[100,0,255],2) + font = cv2.FONT_HERSHEY_SIMPLEX + cv2.putText(frame,'Center',tuple(centerMass),font,2,(255,255,255),2) + + #Distance from each finger defect(finger webbing) to the center mass + distanceBetweenDefectsToCenter = [] + for i in range(0,len(FarDefect)): + x = np.array(FarDefect[i]) + centerMass = np.array(centerMass) + distance = np.sqrt(np.power(x[0]-centerMass[0],2)+np.power(x[1]-centerMass[1],2)) + distanceBetweenDefectsToCenter.append(distance) + + #Get an average of three shortest distances from finger webbing to center mass + sortedDefectsDistances = sorted(distanceBetweenDefectsToCenter) + AverageDefectDistance = np.mean(sortedDefectsDistances[0:2]) + + #Get fingertip points from contour hull + #If points are in proximity of 80 pixels, consider as a single point in the group + finger = [] + for i in range(0,len(hull)-1): + if (np.absolute(hull[i][0][0] - hull[i+1][0][0]) > 80) or ( np.absolute(hull[i][0][1] - hull[i+1][0][1]) > 80): + if hull[i][0][1] <500 : + finger.append(hull[i][0]) + + #The fingertip points are 5 hull points with largest y coordinates + finger = sorted(finger,key=lambda x: x[1]) + fingers = finger[0:5] + + #Calculate distance of each finger tip to the center mass + fingerDistance = [] + for i in range(0,len(fingers)): + distance = np.sqrt(np.power(fingers[i][0]-centerMass[0],2)+np.power(fingers[i][1]-centerMass[0],2)) + fingerDistance.append(distance) + + #Finger is pointed/raised if the distance of between fingertip to the center mass is larger + #than the distance of average finger webbing to center mass by 130 pixels + result = 0 + for i in range(0,len(fingers)): + if fingerDistance[i] > AverageDefectDistance+130: + result = result +1 + + #Print number of pointed fingers + cv2.putText(frame,str(result),(100,100),font,2,(255,255,255),2) + + #show height raised fingers + #cv2.putText(frame,'finger1',tuple(finger[0]),font,2,(255,255,255),2) + #cv2.putText(frame,'finger2',tuple(finger[1]),font,2,(255,255,255),2) + #cv2.putText(frame,'finger3',tuple(finger[2]),font,2,(255,255,255),2) + #cv2.putText(frame,'finger4',tuple(finger[3]),font,2,(255,255,255),2) + #cv2.putText(frame,'finger5',tuple(finger[4]),font,2,(255,255,255),2) + #cv2.putText(frame,'finger6',tuple(finger[5]),font,2,(255,255,255),2) + #cv2.putText(frame,'finger7',tuple(finger[6]),font,2,(255,255,255),2) + #cv2.putText(frame,'finger8',tuple(finger[7]),font,2,(255,255,255),2) + + #Print bounding rectangle + x,y,w,h = cv2.boundingRect(cnts) + img = cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2) + + cv2.drawContours(frame,[hull],-1,(255,255,255),2) + + ##### Show final image ######## + cv2.imshow('Dilation',frame) + ############################### + + #Print execution time + #print time.time()-start_time + + #close the output video by pressing 'ESC' + k = cv2.waitKey(5) & 0xFF + if k == 27: + break + + +cap.release() +cv2.destroyAllWindows()