1+ import cv2
2+ import numpy as np
3+ import copy
4+ import math
5+ from appscript import app
6+ 7+ # Environment:
8+ # OS : Mac OS EL Capitan
9+ # python: 3.5
10+ # opencv: 2.4.13
11+ 12+ # parameters
13+ cap_region_x_begin = 0.5 # start point/total width
14+ cap_region_y_end = 0.8 # start point/total width
15+ threshold = 60 # BINARY threshold
16+ blurValue = 41 # GaussianBlur parameter
17+ bgSubThreshold = 50
18+ 19+ # variables
20+ isBgCaptured = 0 # bool, whether the background captured
21+ triggerSwitch = False # if true, keyborad simulator works
22+ 23+ def printThreshold (thr ):
24+ print ("! Changed threshold to " + str (thr ))
25+ 26+ 27+ def removeBG (frame ):
28+ fgmask = bgModel .apply (frame )
29+ # kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
30+ # res = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
31+ 32+ kernel = np .ones ((3 , 3 ), np .uint8 )
33+ fgmask = cv2 .erode (fgmask , kernel , iterations = 1 )
34+ res = cv2 .bitwise_and (frame , frame , mask = fgmask )
35+ return res
36+ 37+ 38+ def calculateFingers (res ,drawing ): # -> finished bool, cnt: finger count
39+ # convexity defect
40+ hull = cv2 .convexHull (res , returnPoints = False )
41+ if len (hull ) > 3 :
42+ defects = cv2 .convexityDefects (res , hull )
43+ if type (defects ) != type (None ): # avoid crashing. (BUG not found)
44+ 45+ cnt = 0
46+ for i in range (defects .shape [0 ]): # calculate the angle
47+ s , e , f , d = defects [i ][0 ]
48+ start = tuple (res [s ][0 ])
49+ end = tuple (res [e ][0 ])
50+ far = tuple (res [f ][0 ])
51+ a = math .sqrt ((end [0 ] - start [0 ]) ** 2 + (end [1 ] - start [1 ]) ** 2 )
52+ b = math .sqrt ((far [0 ] - start [0 ]) ** 2 + (far [1 ] - start [1 ]) ** 2 )
53+ c = math .sqrt ((end [0 ] - far [0 ]) ** 2 + (end [1 ] - far [1 ]) ** 2 )
54+ angle = math .acos ((b ** 2 + c ** 2 - a ** 2 ) / (2 * b * c )) # cosine theorem
55+ if angle <= math .pi / 2 : # angle less than 90 degree, treat as fingers
56+ cnt += 1
57+ cv2 .circle (drawing , far , 8 , [211 , 84 , 0 ], - 1 )
58+ return True , cnt
59+ return False , 0
60+ 61+ 62+ # Camera
63+ camera = cv2 .VideoCapture (0 )
64+ camera .set (10 ,200 )
65+ cv2 .namedWindow ('trackbar' )
66+ cv2 .createTrackbar ('trh1' , 'trackbar' , threshold , 100 , printThreshold )
67+ 68+ 69+ while camera .isOpened ():
70+ ret , frame = camera .read ()
71+ threshold = cv2 .getTrackbarPos ('trh1' , 'trackbar' )
72+ frame = cv2 .bilateralFilter (frame , 5 , 50 , 100 ) # smoothing filter
73+ frame = cv2 .flip (frame , 1 ) # flip the frame horizontally
74+ cv2 .rectangle (frame , (int (cap_region_x_begin * frame .shape [1 ]), 0 ),
75+ (frame .shape [1 ], int (cap_region_y_end * frame .shape [0 ])), (255 , 0 , 0 ), 2 )
76+ cv2 .imshow ('original' , frame )
77+ 78+ # Main operation
79+ if isBgCaptured == 1 : # this part wont run until background captured
80+ img = removeBG (frame )
81+ img = img [0 :int (cap_region_y_end * frame .shape [0 ]),
82+ int (cap_region_x_begin * frame .shape [1 ]):frame .shape [1 ]] # clip the ROI
83+ cv2 .imshow ('mask' , img )
84+ 85+ # convert the image into binary image
86+ gray = cv2 .cvtColor (img , cv2 .COLOR_BGR2GRAY )
87+ blur = cv2 .GaussianBlur (gray , (blurValue , blurValue ), 0 )
88+ cv2 .imshow ('blur' , blur )
89+ ret , thresh = cv2 .threshold (blur , threshold , 255 , cv2 .THRESH_BINARY )
90+ cv2 .imshow ('ori' , thresh )
91+ 92+ 93+ # get the coutours
94+ thresh1 = copy .deepcopy (thresh )
95+ contours , hierarchy = cv2 .findContours (thresh1 , cv2 .RETR_TREE , cv2 .CHAIN_APPROX_SIMPLE )
96+ length = len (contours )
97+ maxArea = - 1
98+ if length > 0 :
99+ for i in range (length ): # find the biggest contour (according to area)
100+ temp = contours [i ]
101+ area = cv2 .contourArea (temp )
102+ if area > maxArea :
103+ maxArea = area
104+ ci = i
105+ 106+ res = contours [ci ]
107+ hull = cv2 .convexHull (res )
108+ drawing = np .zeros (img .shape , np .uint8 )
109+ cv2 .drawContours (drawing , [res ], 0 , (0 , 255 , 0 ), 2 )
110+ cv2 .drawContours (drawing , [hull ], 0 , (0 , 0 , 255 ), 3 )
111+ 112+ isFinishCal ,cnt = calculateFingers (res ,drawing )
113+ if triggerSwitch is True :
114+ if isFinishCal is True and cnt <= 2 :
115+ print cnt
116+ app ('System Events' ).keystroke (' ' ) # simulate pressing blank space
117+ 118+ cv2 .imshow ('output' , drawing )
119+ 120+ # Keyboard OP
121+ k = cv2 .waitKey (10 )
122+ if k == 27 : # press ESC to exit
123+ break
124+ elif k == ord ('b' ): # press 'b' to capture the background
125+ bgModel = cv2 .BackgroundSubtractorMOG2 (0 , bgSubThreshold )
126+ isBgCaptured = 1
127+ print '!!!Background Captured!!!'
128+ elif k == ord ('r' ): # press 'r' to reset the background
129+ bgModel = None
130+ triggerSwitch = False
131+ isBgCaptured = 0
132+ print '!!!Reset BackGround!!!'
133+ elif k == ord ('n' ):
134+ triggerSwitch = True
135+ print '!!!Trigger On!!!'
0 commit comments