├── project_ppt.pptx ├── README.md └── main.py /project_ppt.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarshNaik/Hand-Detection-Finger-Counting/HEAD/project_ppt.pptx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hand-Detection-Finger-Counting 2 | ### Detect Hand and count number of fingers using Convex Hull algorithm in OpenCV lib in Python 3 | 4 | 5 | 6 | To run the program on primary camera change line 4 to : 7 | ```python 8 | cap = cv2.VideoCapture(0) 9 | ``` 10 | 11 | run the code on command line : 12 | ```command line 13 | python main.py 14 | ``` 15 | 16 | 17 | _"project_ppt.pptx" shows how the program works_ 18 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import math 4 | cap = cv2.VideoCapture(2) 5 | 6 | 7 | while(1): 8 | 9 | try: #an error comes if it does not find anything in window as it cannot find contour of max area 10 | #therefore this try error statement 11 | 12 | ret, frame = cap.read() 13 | frame=cv2.flip(frame,1) 14 | kernel = np.ones((3,3),np.uint8) 15 | 16 | #define roi which is a small square on screen 17 | roi=frame[100:300, 100:300] 18 | 19 | 20 | cv2.rectangle(frame,(100,100),(300,300),(0,255,0),0) 21 | hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) 22 | 23 | 24 | 25 | # range of the skin colour is defined 26 | lower_skin = np.array([0,20,70], dtype=np.uint8) 27 | upper_skin = np.array([20,255,255], dtype=np.uint8) 28 | 29 | #extract skin colur image 30 | mask = cv2.inRange(hsv, lower_skin, upper_skin) 31 | 32 | 33 | 34 | #extrapolate the hand to fill dark spots within 35 | mask = cv2.dilate(mask,kernel,iterations = 4) 36 | 37 | #image is blurred using GBlur 38 | mask = cv2.GaussianBlur(mask,(5,5),100) 39 | 40 | 41 | 42 | #find contours 43 | _,contours,hierarchy= cv2.findContours(mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) 44 | 45 | #find contour of max area(hand) 46 | cnt = max(contours, key = lambda x: cv2.contourArea(x)) 47 | 48 | #approx the contour a little 49 | epsilon = 0.0005*cv2.arcLength(cnt,True) 50 | approx= cv2.approxPolyDP(cnt,epsilon,True) 51 | 52 | 53 | #make convex hull around hand 54 | hull = cv2.convexHull(cnt) 55 | 56 | #define area of hull and area of hand 57 | areahull = cv2.contourArea(hull) 58 | areacnt = cv2.contourArea(cnt) 59 | 60 | #find the percentage of area not covered by hand in convex hull 61 | arearatio=((areahull-areacnt)/areacnt)*100 62 | 63 | #find the defects in convex hull with respect to hand 64 | hull = cv2.convexHull(approx, returnPoints=False) 65 | defects = cv2.convexityDefects(approx, hull) 66 | 67 | # l = no. of defects 68 | l=0 69 | 70 | #code for finding no. of defects due to fingers 71 | for i in range(defects.shape[0]): 72 | s,e,f,d = defects[i,0] 73 | start = tuple(approx[s][0]) 74 | end = tuple(approx[e][0]) 75 | far = tuple(approx[f][0]) 76 | pt= (100,180) 77 | 78 | 79 | # find length of all sides of triangle 80 | a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2) 81 | b = math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2) 82 | c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2) 83 | s = (a+b+c)/2 84 | ar = math.sqrt(s*(s-a)*(s-b)*(s-c)) 85 | 86 | #distance between point and convex hull 87 | d=(2*ar)/a 88 | 89 | # apply cosine rule here 90 | angle = math.acos((b**2 + c**2 - a**2)/(2*b*c)) * 57 91 | 92 | 93 | # ignore angles > 90 and ignore points very close to convex hull(they generally come due to noise) 94 | if angle <= 90 and d>30: 95 | l += 1 96 | cv2.circle(roi, far, 3, [255,0,0], -1) 97 | 98 | #draw lines around hand 99 | cv2.line(roi,start, end, [0,255,0], 2) 100 | 101 | 102 | l+=1 103 | 104 | #display corresponding gestures which are in their ranges 105 | font = cv2.FONT_HERSHEY_SIMPLEX 106 | if l==1: 107 | if areacnt<2000: 108 | cv2.putText(frame,'Put hand in the box',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA) 109 | else: 110 | if arearatio<12: 111 | cv2.putText(frame,'0',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA) 112 | 113 | else: 114 | cv2.putText(frame,'1',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA) 115 | 116 | elif l==2: 117 | cv2.putText(frame,'2',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA) 118 | 119 | elif l==3: 120 | 121 | if arearatio<27: 122 | cv2.putText(frame,'3',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA) 123 | else: 124 | cv2.putText(frame,'ok',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA) 125 | 126 | elif l==4: 127 | cv2.putText(frame,'4',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA) 128 | 129 | elif l==5: 130 | cv2.putText(frame,'5',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA) 131 | 132 | elif l==6: 133 | cv2.putText(frame,'reposition',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA) 134 | 135 | else : 136 | cv2.putText(frame,'reposition',(10,50), font, 2, (0,0,255), 3, cv2.LINE_AA) 137 | 138 | cv2.imshow('mask',mask) 139 | cv2.imshow('frame',frame) 140 | except: 141 | pass 142 | 143 | 144 | k = cv2.waitKey(5) & 0xFF 145 | if k == 27: 146 | break 147 | 148 | cv2.destroyAllWindows() 149 | cap.release() 150 | --------------------------------------------------------------------------------