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