def contour_points(largest_contour, image): hull = cv2.convexHull(largest_contour) drawing = np.zeros(image.shape, np.uint8) cv2.drawContours(drawing, [largest_contour], 0, (0, 255, 0), 2) #cv2.drawContours(drawing, [hull], 0, (0, 0, 255), 3) hull = cv2.convexHull(largest_contour, returnPoints=False) defects = cv2.convexityDefects(largest_contour, hull) # draw furthest left,top and right point point_list = [] # detect fingers middle defects k = 1 for i in range(defects.shape[0]): s, e, f, d = defects[i, 0] start = tuple(largest_contour[s][0]) end = tuple(largest_contour[e][0]) far = tuple(largest_contour[f][0]) angle = calculateAngle(far, start, end) if d > 10000 and angle <= math.pi / 2: if (k == 1): cv2.circle(drawing, start, 8, (147, 20, 255), -1) point_list.append(start) cv2.circle(drawing, end, 8, (147, 20, 255), -1) point_list.append(far) point_list.append(end) cv2.circle(drawing, far, 5, [255, 0, 0], -1) k += 1 return drawing, point_list
def count(thresholded, segmented): # find the convex hull of the segmented hand region hull = cv2.convexHull(segmented, returnPoints=False) defects = cv2.convexityDefects(segmented, hull) # Bascially indicates how much finger is visible in screen countDefects = 0 for i in range(defects.shape[0]): # Returns start point, end point, farthest point, approximate distance to farthest point s, e, f, d = defects[i, 0] start = tuple(segmented[s][0]) end = tuple(segmented[e][0]) far = tuple(segmented[f][0]) a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2) b = math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2) c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2) # This angle is used while hand is moving around angle = (math.acos((b**2 + c**2 - a**2) / (2 * b * c)) * 180) / 3.14 # If angle < 90 degree then treat as a finger if angle <= 90: countDefects += 1 return (countDefects + 1)
def func(ImgNo, defThr=127): img = cv2.imread(impDef.select_img(ImgNo)) img1 = img.copy() imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, thr = cv2.threshold(imgray, defThr, 255, 0) contours, _ = cv2.findContours(thr, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) cnt = contours[0] # Convex Hull만을 찾기 위해 contours 1개만을 인자로 입력 hull = cv2.convexHull(cnt) cv2.drawContours(img, [hull], 0, (0, 0, 255), 2) # Convexity Defects를 찾기위해 2번째 인자로 returnPoints = False를 지정해야 함 # (cnt, returnPoints = False) 인자로 주어진 cnt를 분석하여 Convex Hull을 이루는 모든 좌표를 리턴하는 것이 아니라, # 원래 Contour와 Convex Hull이 만나는 부부의 Contour 인덱스를 리턴함. # 즉 별의 꼭지점에 해당하는 5군데를 리턴함. hull = cv2.convexHull(cnt, returnPoints=False) defects = cv2.convexityDefects(cnt, hull) for i in range(defects.shape[0]): sp, ep, fp, dist = defects[i, 0] start = tuple(cnt[sp][0]) end = tuple(cnt[ep][0]) farthest = tuple(cnt[fp][0]) cv2.circle(img, farthest, 5, (0, 255, 0), -1) cv2.imshow('defects', img) impDef.close_window()
def convexityDetectionImg(self): try: img = cv2.imread(self.filename) img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(img_gray, 127, 255, 0) contours, hierarchy = cv2.findContours(thresh, 2, 1) cnt = contours[0] hull = cv2.convexHull(cnt, returnPoints=False) defects = cv2.convexityDefects(cnt, hull) for i in range(defects.shape[0]): s, e, f, d = defects[i, 0] start = tuple(cnt[s][0]) end = tuple(cnt[e][0]) far = tuple(cnt[f][0]) cv2.line(img, start, end, [0, 255, 0], 2) cv2.circle(img, far, 5, [0, 0, 255], -1) cv2.imwrite('img/dist/disbukey.png', img, [cv2.IMWRITE_JPEG_QUALITY, 100]) cv2.waitKey(0) cv2.destroyAllWindows() except: pass
def find_second_contours(base_out, output): contours = cv2.findContours(base_out, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_TC89_KCOS) contours_map = {} for idx in range(0, len(contours[1])): area = cv2.contourArea(contours[1][idx]) contours_map[idx] = {'area': area, 'contour': contours[1][idx]} pass contours_map = sorted(contours_map.items(), key=lambda d: d[1]['area']) for idx in range(1, 3): id = -idx max_contours = contours_map[id][1]['contour'] hulls = cv2.convexHull(max_contours, returnPoints=False) pts_index = cv2.convexityDefects(contour=max_contours, convexhull=hulls) pts = [] for v in pts_index: pts.append(max_contours[v[0][0]]) pts.append(max_contours[v[0][1]]) ndpts = np.zeros((len(pts), 1, 2), np.int32) for idx in range(0, len(pts)): ndpts[idx] = pts[idx] cv2.drawContours(output, ndpts, -1, (0, 255, 0), cv2.FILLED, cv2.LINE_AA) return output
def ConvexHull_Cal(contour): IsTriangle = lambda a, b, c: a + b > c and a + c > b and b + c > a #任意两边和必须大于第三边 point_list = [] convex_angle_ls = [] concave_angle_ls = [] epsilon = 0.003 * cv2.arcLength(contour, True) contour = cv2.approxPolyDP(contour, epsilon, True) #轮廓近似,Douglas-Peucker算法 hull = cv2.convexHull(contour, returnPoints=False) defects = cv2.convexityDefects(contour, hull) _, radius = cv2.minEnclosingCircle(contour) if defects is not None: for i in range(defects.shape[0]): s, e, f, _ = defects[i, 0] sta = tuple(contour[s][0]) end = tuple(contour[e][0]) far = tuple(contour[f][0]) point_list.append([sta, far, end]) #下面的角边标示含义见文件夹里的图片说明 if len(point_list) >= 2: for it_1, it_2 in zip(point_list, point_list[1:] + point_list[:1]): CA = scfun.Eucledian_Distance(it_1[1], it_1[2]) #far to end AB = scfun.Eucledian_Distance(it_1[2], it_2[1]) #end to next far #凸包的角度 if radius <= CA + AB < 2 * radius: BC = scfun.Eucledian_Distance(it_1[1], it_2[1]) #far to 2nd far,为底边 if IsTriangle(CA, AB, BC): angle = acos((CA**2 + AB**2 - BC**2) / (2 * CA * AB)) convex_angle_ls.append(angle) #凹陷的角度 DC = scfun.Eucledian_Distance(it_1[0], it_1[1]) #sta to far if radius <= DC + CA < 2 * radius: DA = scfun.Eucledian_Distance(it_1[0], it_1[2]) #sta to end,为底边 if IsTriangle(DC, CA, DA): angle = acos((CA**2 + DC**2 - DA**2) / (2 * CA * DC)) concave_angle_ls.append(angle) convex_angle = [x for x in convex_angle_ls if pi / 18 <= x <= pi / 6] #凸包角度:10度至30度 convex_len = len(convex_angle) concave_angle = [ x for x in concave_angle_ls if pi / 18 <= x <= pi / 3.5 ] concave_len = len(concave_angle) result = [convex_len, concave_len] else: result = [0, 0] return result
def Gestures_Detect(hand, sample_list, fourier_des_ls): ndefects = 0 sign, large_cout = Find_Contour(hand, sample_list, fourier_des_ls) if sign == False: ndefects = 11 #返回contours为空的信息,只作调试用 center = tuple([a // 2 for a in reversed(hand.shape)]) #返回图像的中心坐标 return hand, ndefects, center black2 = np.ones(hand.shape, np.uint8) #创建黑色幕布 cv2.drawContours(black2, large_cout, -1, (255, 255, 255), 2) #绘制白色轮廓 cv2.imshow('large_cout', black2) hull = cv2.convexHull(large_cout, returnPoints=False) defects = cv2.convexityDefects(large_cout, hull) _, radius = cv2.minEnclosingCircle(large_cout) if defects is not None: for i in range(defects.shape[0]): s, e, f, _ = defects[i, 0] sta = tuple(large_cout[s][0]) end = tuple(large_cout[e][0]) far = tuple(large_cout[f][0]) B = scfun.Eucledian_Distance(sta, far) C = scfun.Eucledian_Distance(end, far) #过滤掉角边太短的角 if B + C > radius: A = scfun.Eucledian_Distance(sta, end) #底边 angle = acos((B**2 + C**2 - A**2) / (2 * B * C)) if angle <= pi / 2.5: ndefects += 1 else: ndefects = 12 ''' test=scfun.Fourier_Descriptor(large_cout[:,0,:],Normalize=True) similar=scfun.Eucledian_Distance(test,fourier_des_ls[0]) print('{:.5f} {:.5f}'.format(similar,log(similar))) ''' M = cv2.moments(large_cout) center = (int(M['m10'] / M['m00']), int(M['m01'] / M['m00'])) #手部的质心坐标 x, y, w, h = cv2.boundingRect(large_cout) hand = cv2.cvtColor(hand, cv2.COLOR_GRAY2BGR) #将灰度图像转换为BGR以显示绿色方框 hand = cv2.rectangle(hand, (x, y), (x + w, y + h), (0, 255, 0), 2) return hand, ndefects, center
def calculateFingers(max_contour, drawing, img): hull = cv2.convexHull(max_contour, returnPoints=False) if len(hull) > 3: defects = cv2.convexityDefects(max_contour, hull) if type(defects) != type(None): cnt = 0 for i in range(defects.shape[0]): # calculate the angle s, e, f, _ = defects[i][0] start = tuple(max_contour[s][0]) end = tuple(max_contour[e][0]) far = tuple(max_contour[f][0]) angle = calculateAngle(far, start, end) if angle <= math.pi / 2: cnt += 1 cv2.circle(drawing, far, 8, [211, 84, 0], -1) return cnt return 0
def contour_points(largest_contour, image): hull = cv2.convexHull(largest_contour) drawing = image cv2.drawContours(drawing, [hull], 0, (0, 0, 255), 3) hull = cv2.convexHull(largest_contour, returnPoints=False) defects = cv2.convexityDefects(largest_contour, hull) # draw furthest left,top and right point point_list = [] # detect fingers middle defects k = 1 deffect_count = 0 if defects is not None: for i in range(defects.shape[0]): s, e, f, d = defects[i, 0] start = tuple(largest_contour[s][0]) end = tuple(largest_contour[e][0]) far = tuple(largest_contour[f][0]) angle = calculateAngle(far, start, end) if d > 20000 and angle <= math.pi / 2: #if d > 70000 and angle <= math.pi/2: #print(d) if (k == 1): ''' cv2.circle(drawing, start, 30, (147, 20, 255), -1) point_list.append(start) cv2.circle(drawing, end, 30, (147, 20, 255), -1) cv2.circle(drawing,far,30,[255,0,0],-1) ''' cv2.circle(drawing, start, 10, (147, 20, 255), -1) point_list.append(start) cv2.circle(drawing, end, 10, (147, 20, 255), -1) cv2.circle(drawing, far, 10, [255, 0, 0], -1) k += 1 deffect_count += 1 #drawing = cv2.putText(drawing, str(deffect_count), (1800, 200), cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, 5 ,(0,0,255), 10, cv2.LINE_AA) #AVS drawing = cv2.putText(drawing, str(deffect_count), (650, 150), cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, 5, (0, 0, 255), 10, cv2.LINE_AA) return drawing, point_list, deffect_count
def detectGesture(contours, res, hull): cnt = 0 if len(hull) > 3: defects = cv.convexityDefects(res, hull) if type(defects) != type(None): # avoid crashing. (BUG not found) for i in range(defects.shape[0]): # calculate the angle s, e, f, d = defects[i][0] start = tuple(res[s][0]) end = tuple(res[e][0]) far = tuple(res[f][0]) a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2) b = math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2) c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2) angle = math.acos( (b**2 + c**2 - a**2) / (2 * b * c)) # cosine theorem if angle <= math.pi / 2: # angle less than 90 degree, treat as fingers cnt += 1 if cnt == 0: hhArea, ratio = calculateAreas(contours) if ratio > 0.9: #extra verification if hhArea < 17500: return ("fist") if hhArea > 17500: return ("palm") if ratio < 0.8 and hhArea > 22000: return ("call") else: return (cnt + 1) elif cnt == 1: hhArea, ratio = calculateAreas(contours) if ratio > 0.65 and hhArea > 23000: return ("vulcan") return (cnt + 1) elif cnt == 2: hhArea, ratio = calculateAreas(contours) if ratio < 0.7 and hhArea > 29000: return ("rock") return (cnt + 1) else: return (cnt + 1)
def compute_convex_hull(contours, max_contour_index, PATH): # Convex Hull for subdir, dirs, files in os.walk(PATH): i = 0 for file in files: file_path = subdir + os.sep + file img = cv2.imread(file_path, 1) blurred_img = apply_gaussian_blurring(img, 9, 9) grayscale_img = cv2.cvtColor(blurred_img, cv2.COLOR_BGR2GRAY) _, binary_img = cv2.threshold(src=grayscale_img, thresh=50, maxval=255, type=cv2.THRESH_BINARY) contours, hierachy = cv2.findContours(image=binary_img, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_NONE) max_contour_index = get_max_contour(contours=contours) hull = cv2.convexHull(contours[max_contour_index], returnPoints=True) if (i < 5): cv2.drawContours(img, [hull], 0, (255, 0, 0), 1) # cv2.imshow('Convex Hull_{}'.format(i), img) i += 1 # Convexity defects hull_ints = cv2.convexHull(contours[max_contour_index], returnPoints=False) hull_points = cv2.convexHull(contours[max_contour_index], returnPoints=True) defects = cv2.convexityDefects(contours[max_contour_index], hull_ints) for i in range(defects.shape[0]): s, e, f, d = defects[i, 0] start = tuple(contours[max_contour_index][s][0]) end = tuple(contours[max_contour_index][e][0]) far = tuple(contours[max_contour_index][f][0]) cv2.line(img, start, end, [0, 255, 0], 2) cv2.circle(img, far, 2, [0, 0, 255], -1) cv2.imshow('Convexity defects', img)
def calculateFingers(res, drawing): # count fingers and draw hull = cv2.convexHull( res, returnPoints=False) # find the convex hull, and get the angular point if len(hull) > 3: defects = cv2.convexityDefects(res, hull) # convexity defect if type(defects) != type(None): # avoid crashing cnt = 0 for i in range(defects.shape[0]): # calculate the angle s, e, f, d = defects[i][0] start = tuple(res[s][0]) end = tuple(res[e][0]) far = tuple(res[f][0]) a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2) b = math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2) c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2) angle = math.acos( (b**2 + c**2 - a**2) / (2 * b * c)) # compute the angle of each hull side if angle <= math.pi / 2: # if angle less than 90 degree, treat as fingers and draw cnt += 1 cv2.circle(drawing, far, 8, [211, 84, 0], -1) return True, cnt return False, 0
approx= cv2.approxPolyDP(cnt,epsilon,True) #make convex hull around hand hull = cv2.convexHull(cnt) #define area of hull and area of hand areahull = cv2.contourArea(hull) areacnt = cv2.contourArea(cnt) #find the percentage of area not covered by hand in convex hull arearatio=((areahull-areacnt)/areacnt)*100 #find the defects in convex hull with respect to hand hull = cv2.convexHull(approx, returnPoints=False) defects = cv2.convexityDefects(approx, hull) # l = no. of defects l=0 #code for finding no. of defects due to fingers for i in range(defects.shape[0]): s,e,f,d = defects[i,0] start = tuple(approx[s][0]) end = tuple(approx[e][0]) far = tuple(approx[f][0]) pt= (100,180) # find length of all sides of triangle a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2)
kernel = numpy.ones((5, 5), numpy.uint8) # erosion kernel mask = cv2.erode(silhouette, kernel, iterations=1) # mask creation by erosion contours, hierarchy = cv2.findContours( silhouette, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # find contours of silhouette contours = max( contours, key=lambda x: cv2.contourArea(x)) # pick out biggest contour hull = cv2.convexHull(contours, returnPoints=False, clockwise=True) # construct convex hull hull[::-1].sort( axis=0) # sort hull (fix for BUG in the convexHull function) defects = cv2.convexityDefects(contours, hull) # get indices of defects #---------------------------------------------------------------------------- # Finger gap detection and Affline transformations #---------------------------------------------------------------------------- cnt = 0 finger_gaps = [] for i in range( defects.shape[0]): # loop over number of rows in defects s, e, f, d = defects[i][0] start = tuple(contours[s][0]) end = tuple(contours[e][0]) far = tuple(contours[f][0]) a = numpy.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2) # distance formula
def main(): """ Main function of the program. """ # Capture the video from the default camera defaultCamera = 0 capturedVideo = cv2.VideoCapture(defaultCamera) # Initialization of the background subtractor backgroundSubtractor = cv2.createBackgroundSubtractorMOG2( detectShadows=True) if not capturedVideo.isOpened(): print('Error: Unable to open file') exit(0) # Top-left and bottom-right points of the region of interest rectangle: # Low resolution webcam regionOfInterestPoint1 = (330, 10) regionOfInterestPoint2 = (630, 310) # Medium resolution webcam # regionOfInterestPoint1 = (800, 30) # regionOfInterestPoint2 = (1250, 530) # Constant tuple with the two learning rates for the background # subtractor learningRates = (0.3, 0) # Initialization of the current learning rate currentLearningRate = learningRates[0] # Boolean that stores if the user wants to count the raised fingers or not countHandFingers = True # Boolean that stores if the user wants to detect hand gestures or not detectHandGestures = True # Boolean that stores if the user wants to draw with the index finger or not indexFingerDrawing = False # List that stores the trace of the current stroke of the drawing currentStroke = list() # List that stores the entire drawing currentDrawing = list() # Boolean that stores if the user wants to see the help info or not showHelp = True while True: # Read the data from the captured video returntErrorValue, capturedFrame = capturedVideo.read() if not returntErrorValue: print('Error: Unable to get data') exit(0) # Window showing the mirrored captured video and the region of interest # marked with a blue rectangle capturedFrame = cv2.flip(capturedFrame, 1) cv2.rectangle(capturedFrame, regionOfInterestPoint1, regionOfInterestPoint2, color=(255, 0, 0)) cv2.imshow('WebCam', capturedFrame) # Window showing the region of interest only regionOfInterest = capturedFrame[ regionOfInterestPoint1[1]:regionOfInterestPoint2[1], regionOfInterestPoint1[0]:regionOfInterestPoint2[0], :].copy() # cv2.imshow('Region of Interest', regionOfInterest) # Window showing the background subtraction applied foregroundMask = backgroundSubtractor.apply(regionOfInterest, None, currentLearningRate) # cv2.imshow('Foreground Mask', foregroundMask) # Window showing the gray threshold applied returntErrorValue, blackAndWhite = cv2.threshold( foregroundMask, 200, 255, cv2.THRESH_BINARY) cv2.imshow('Black and White', blackAndWhite) # Window showing the hand contour contours = cv2.findContours(blackAndWhite, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0] contourWindow = regionOfInterest.copy() if len(contours) > 0 and currentLearningRate != learningRates[0]: handContour = getLargerContour(contours) cv2.drawContours(contourWindow, handContour, contourIdx=-1, color=(0, 255, 0), thickness=3) else: handContour = None cv2.imshow('Contour', contourWindow) # Window showing the hand's convex hull convexHullWindow = regionOfInterest.copy() if handContour is not None: handConvexHull = cv2.convexHull(handContour) cv2.drawContours(convexHullWindow, [handConvexHull], contourIdx=0, color=(255, 0, 0), thickness=3) else: handConvexHull = None cv2.imshow('Convex Hull', convexHullWindow) # Window showing the fingers' convexity defects convexityDefectsWindow = regionOfInterest.copy() if handContour is not None: handConvexHull = cv2.convexHull(handContour, clockwise=False, returnPoints=False) tempPythonList = list(handConvexHull) tempPythonList.sort(reverse=True, key=lambda element: element[0]) handConvexHull = numpy.array(tempPythonList) handConvexityDefects = cv2.convexityDefects( handContour, handConvexHull) fingerConvexityDefects = list() if handConvexityDefects is not None: for currentConvexityDefect in range(len(handConvexityDefects)): startIndex, endIndex, farIndex, distanceToConvexHull \ = handConvexityDefects[currentConvexityDefect][0] startPoint = tuple(handContour[startIndex][0]) endPoint = tuple(handContour[endIndex][0]) farPoint = tuple(handContour[farIndex][0]) depth = distanceToConvexHull / 256.0 if depth > 80.0: # angleOfCurrentConvexityDefect = angle( # startPoint, endPoint, farPoint) cv2.line(convexityDefectsWindow, startPoint, endPoint, color=(255, 0, 0), thickness=2) cv2.circle(convexityDefectsWindow, farPoint, radius=5, color=(0, 0, 255), thickness=-1) fingerConvexityDefects.append( (startPoint, endPoint, farPoint)) else: handConvexHull = None handConvexityDefects = None cv2.imshow('Convexity Defects', convexityDefectsWindow) # Window showing the hand's bounding rectangle boundingRectangleWindow = regionOfInterest.copy() if handContour is not None: handBoundingRectangle = cv2.boundingRect(handContour) boundingRectanglePoint1 = (handBoundingRectangle[0], handBoundingRectangle[1]) boundingRectanglePoint2 = (handBoundingRectangle[0] + handBoundingRectangle[2], handBoundingRectangle[1] + handBoundingRectangle[3]) cv2.rectangle(boundingRectangleWindow, boundingRectanglePoint1, boundingRectanglePoint2, color=(0, 0, 255), thickness=3) else: handBoundingRectangle = None boundingRectanglePoint1 = None boundingRectanglePoint2 = None cv2.imshow('Bounding Rectangle', boundingRectangleWindow) # Window showing the user side functionalities mainWindow = regionOfInterest.copy() if handContour is not None: numberOfFingers = countFingers(fingerConvexityDefects, handBoundingRectangle) if countHandFingers: mainWindow = printFingers(numberOfFingers, mainWindow) if detectHandGestures: handGesture = detectHandGesture(numberOfFingers, fingerConvexityDefects, handBoundingRectangle) mainWindow = printGestures(handGesture, mainWindow) if indexFingerDrawing: currentStroke = fingerDrawing(currentStroke, handContour, mainWindow) mainWindow = printStroke(currentStroke, mainWindow) for stroke in currentDrawing: mainWindow = printStroke(stroke, mainWindow) if showHelp: mainWindow = printHelp(mainWindow) if currentLearningRate == learningRates[0]: mainWindow = printLearning(mainWindow) cv2.imshow('Main Window', mainWindow) keyboard = cv2.waitKey(1) # Key used for swaping between the two learning rates if keyboard & 0xFF == ord('s'): currentLearningRate = swapLearningRate(currentLearningRate, learningRates) # Key used for swaping between counting the raised fingers or not if keyboard & 0xFF == ord('f'): countHandFingers = not countHandFingers # Key used for swaping between detecting hand gestures or not if keyboard & 0xFF == ord('g'): detectHandGestures = not detectHandGestures # Key used for swaping between drawing with the index finger or not if keyboard & 0xFF == ord('d'): indexFingerDrawing = not indexFingerDrawing if not indexFingerDrawing: currentDrawing.append(currentStroke[:]) currentStroke.clear() # Key used for cleaning the last stroke if keyboard & 0xFF == ord('c'): currentDrawing.pop() # Key used for cleaning the entire drawing if keyboard & 0xFF == ord('x'): currentDrawing.clear() # Key used for swaping between showing the help info or not if keyboard & 0xFF == ord('h'): showHelp = not showHelp # Key used for finishing the program execution if keyboard & 0xFF == ord('q'): break capturedVideo.release() cv2.destroyAllWindows()
contours, key=lambda x: cv2.contourArea(x)) #find contour with max ar x, y, w, h = cv2.boundingRect( contour) #make boundry rectangle arnd the contour cv2.rectangle(crop_img, (x, y), (x + w, y + h), (0, 0, 255), 0) hull = cv2.convexHull(contour) #convex hull find draw = np.zeros(crop_img, np.uint8) #draw the contour cv2.drawContours(draw, [contour], -1, (0, 255, 0), 0) cv2.drawContours(draw[hull], -1, (0, 0, 255), 0) hull = cv2.convexHull(contour, returnPoints=False) #find convexity defects defects = cv2.convexityDefects(contour, hull) count_defects = 0 #using cosine rule to find the change in angle if hand is moved,from start to end point. for i in range(defects.shape[0]): s, e, f, d = defects[i, 0] start = tuple(contour[s][0]) end = tuple(contour[e][0]) far = tuple(contour[f][0]) a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2) b = math.sqrt((end[0] - start[0])**2 + (far[1] - start[1])**2) c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2) angle = (math.acos( (b**2 + c**2 - a**2) / (2 * b * c)) * 180) / 3.14
# coding: utf-8 import numpy as np from cv2 import cv2 import matplotlib.pyplot as plt img = cv2.imread(r'pictures\star.jpg') img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(img_gray, 127, 255, 0) contours, hierarchy = cv2.findContours(thresh, 2, 1) cnt = contours[0] hull = cv2.convexHull(cnt, returnPoints=False) # Remember we have to pass returnPoints = False while finding convex hull, in order to find convexity defects. defects = cv2.convexityDefects(cnt, hull) # It returns an array where each row contains these values - [ start point, end point, farthest point, approximate distance to farthest point ]. dist = cv2.pointPolygonTest(cnt, (50, 50), True) # This function finds the shortest distance between a point (50, 50) in the image and a contour. It returns the distance which is negative when point is outside the contour, positive when point is inside and zero if point is on the contour. # In the function, third argument is measureDist. If it is True, it finds the signed distance. If False, it finds whether the point is inside or outside or on the contour (it returns +1, -1, 0 respectively). Making it False gives about 2-3X speedup. for i in range(defects.shape[0]): s, e, f, d = defects[i, 0] start = tuple(cnt[s][0]) end = tuple(cnt[e][0]) far = tuple(cnt[f][0]) cv2.line(img, start, end, [0, 255, 0], 2) cv2.circle(img, far, 5, [0, 0, 255], -1) cv2.namedWindow("img", 0) cv2.imshow('img', img) cv2.waitKey(0)
def getContours(imgCon, imgMatch): contours, _ = cv2.findContours(imgCon, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) imgCon = cv2.cvtColor(imgCon, cv2.COLOR_GRAY2BGR) bigCon = 0 myCounter = 0 data = 0 myPos = np.zeros(4) for cnt in contours: area = cv2.contourArea(cnt) if (area > 1000): cv2.drawContours(imgCon, cnt, -1, (255, 0, 255), 3) cv2.drawContours(imgMatch, cnt, -1, (255, 0, 255), 3) peri = cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt, 0.02 * peri, True) # APPROXIMATED BOUNDING BOX x, y, w, h = cv2.boundingRect(approx) ex = 10 cv2.rectangle(imgCon, (x - ex, y - ex), (x + w + ex, y + h + ex), (0, 255, 0), 5) # CONVEX HULL & CONVEXITY DEFECTS OF THE HULL hull = cv2.convexHull(cnt, returnPoints=False) defects = cv2.convexityDefects(cnt, hull) bigCon += 1 for i in range(defects.shape[0]): # calculate the angle s, e, f, _ = defects[i][0] start = tuple(cnt[s][0]) end = tuple(cnt[e][0]) far = tuple(cnt[f][0]) a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2) b = math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2) c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2) angle = math.acos( (b**2 + c**2 - a**2) / (2 * b * c)) # cosine theorem if angle <= math.pi // 1.7: # angle less than degree, treat as fingers myPos[myCounter] = far[0] myCounter += 1 cv2.circle(imgCon, far, 5, [0, 255, 0], -1) cv2.circle(imgMatch, far, 5, [0, 255, 0], -1) # SENDING COMMANDS BASED ON FINGERS if (myCounter == 4): FingerCount = "Five" data = 5 elif (myCounter == 3): FingerCount = "Four" data = 4 elif (myCounter == 2): FingerCount = "Three" data = 3 elif (myCounter == 1): FingerCount = "Two" data = 2 elif (myCounter == 0): aspectRatio = w / h if aspectRatio < 0.6: FingerCount = "One" data = 1 else: FingerCount = "Zero" data = 0 cv2.putText(imgMatch, FingerCount, (50, 50), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255), 2) return imgCon, imgMatch, data
def gestos_mano(): cap = cv2.VideoCapture(0) # cap = cv2.VideoCapture(1) bg = None # COLORES PARA VISUALIZACIÓN color_start = (204, 204, 0) color_end = (204, 0, 204) color_far = (255, 0, 0) color_start_far = (204, 204, 0) color_far_end = (204, 0, 204) color_start_end = (0, 255, 255) color_contorno = (0, 255, 0) color_ymin = (0, 130, 255) # Punto más alto del contorno # color_angulo = (0,255,255) # color_d = (0,255,255) color_fingers = (0, 255, 255) while True: ret, frame = cap.read() if ret == False: break # Redimensionar la imagen para que tenga un ancho de 640 frame = imutils.resize(frame, width=640) frame = cv2.flip(frame, 1) frameAux = frame.copy() if bg is not None: # Determinar la región de interés ROI = frame[50:300, 380:600] cv2.rectangle(frame, (380 - 2, 50 - 2), (600 + 2, 300 + 2), color_fingers, 1) grayROI = cv2.cvtColor(ROI, cv2.COLOR_BGR2GRAY) # Región de interés del fondo de la imagen bgROI = bg[50:300, 380:600] # Determinar la imagen binaria (background vs foreground) dif = cv2.absdiff(grayROI, bgROI) _, th = cv2.threshold(dif, 30, 255, cv2.THRESH_BINARY) th = cv2.medianBlur(th, 7) # Encontrando los contornos de la imagen binaria cnts, _ = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:1] for cnt in cnts: # Encontrar el centro del contorno M = cv2.moments(cnt) if M["m00"] == 0: M["m00"] = 1 x = int(M["m10"] / M["m00"]) y = int(M["m01"] / M["m00"]) cv2.circle(ROI, tuple([x, y]), 5, (0, 255, 0), -1) # Punto más alto del contorno ymin = cnt.min(axis=1) cv2.circle(ROI, tuple(ymin[0]), 5, color_ymin, -1) # Contorno encontrado a través de cv2.convexHull hull1 = cv2.convexHull(cnt) cv2.drawContours(ROI, [hull1], 0, color_contorno, 2) # Defectos convexos hull2 = cv2.convexHull(cnt, returnPoints=False) defects = cv2.convexityDefects(cnt, hull2) # Seguimos con la condición si es que existen defectos convexos if defects is not None: inicio = [ ] # Contenedor en donde se almacenarán los puntos iniciales de los defectos convexos fin = [ ] # Contenedor en donde se almacenarán los puntos finales de los defectos convexos fingers = 0 # Contador para el número de dedos levantados for i in range(defects.shape[0]): s, e, f, d = defects[i, 0] start = cnt[s][0] end = cnt[e][0] far = cnt[f][0] # Encontrar el triángulo asociado a cada defecto convexo para determinar ángulo a = np.linalg.norm(far - end) b = np.linalg.norm(far - start) c = np.linalg.norm(start - end) angulo = np.arccos( (np.power(a, 2) + np.power(b, 2) - np.power(c, 2)) / (2 * a * b)) angulo = np.degrees(angulo) angulo = int(angulo) # Se descartarán los defectos convexos encontrados de acuerdo a la distnacia # entre los puntos inicial, final y más alelago, por el ángulo y d if np.linalg.norm(start - end ) > 20 and angulo < 90 and d > 12000: # Almacenamos todos los puntos iniciales y finales que han sido # obtenidos inicio.append(start) fin.append(end) # Visualización de distintos datos obtenidos # cv2.putText(ROI,'{}'.format(angulo),tuple(far), 1, 1.5,color_angulo,2,cv2.LINE_AA) # cv2.putText(ROI,'{}'.format(d),tuple(far), 1, 1.1,color_d,1,cv2.LINE_AA) cv2.circle(ROI, tuple(start), 5, color_start, 2) cv2.circle(ROI, tuple(end), 5, color_end, 2) cv2.circle(ROI, tuple(far), 7, color_far, -1) # cv2.line(ROI,tuple(start),tuple(far),color_start_far,2) # cv2.line(ROI,tuple(far),tuple(end),color_far_end,2) # cv2.line(ROI,tuple(start),tuple(end),color_start_end,2) # Si no se han almacenado puntos de inicio (o fin), puede tratarse de # 0 dedos levantados o 1 dedo levantado if len(inicio) == 0: minY = np.linalg.norm(ymin[0] - [x, y]) if minY >= 110: fingers = fingers + 1 cv2.putText(ROI, '{}'.format(fingers), tuple(ymin[0]), 1, 1.7, (color_fingers), 1, cv2.LINE_AA) # Si se han almacenado puntos de inicio, se contará el número de dedos levantados for i in range(len(inicio)): fingers = fingers + 1 cv2.putText(ROI, '{}'.format(fingers), tuple(inicio[i]), 1, 1.7, (color_fingers), 1, cv2.LINE_AA) if i == len(inicio) - 1: fingers = fingers + 1 cv2.putText(ROI, '{}'.format(fingers), tuple(fin[i]), 1, 1.7, (color_fingers), 1, cv2.LINE_AA) # Se visualiza el número de dedos levantados en el rectángulo izquierdo if fingers == 0: cv2.putText(frame, 'Auxilio', (390, 45), 1, 2, (color_fingers), 2, cv2.LINE_AA) else: if fingers == 1: cv2.putText(frame, 'Estoy bien!', (390, 45), 1, 2, (color_fingers), 2, cv2.LINE_AA) else: if fingers == 2: if angulo > 60: cv2.putText(frame, 'Tengo hambre', (390, 45), 1, 2, (color_fingers), 2, cv2.LINE_AA) else: if angulo < 40: cv2.putText(frame, 'Tengo sueño', (390, 45), 1, 2, (color_fingers), 2, cv2.LINE_AA) else: if fingers == 3: cv2.putText(frame, 'Te quiero', (390, 45), 1, 2, (color_fingers), 2, cv2.LINE_AA) else: if fingers == 4: cv2.putText(frame, 'Gesto desconocido', (300, 45), 1, 2, (color_fingers), 2, cv2.LINE_AA) else: cv2.putText(frame, 'Hola mundo!', (300, 45), 1, 2, (color_fingers), 2, cv2.LINE_AA) cv2.imshow('th', th) cv2.imshow('Frame', frame) k = cv2.waitKey(20) if k == ord('i'): bg = cv2.cvtColor(frameAux, cv2.COLOR_BGR2GRAY) if k == 27: break cap.release() cv2.destroyAllWindows()