def computePerspectiveTransformation(self, contours_structure, BASE_IM_GRAY, BASE_IM_red): target_dim = Dartboard.ENV['DART_BOARD_TARGET_DIMENSION'] pts1 = np.zeros((4, 2), 'int') for i in range(len(contours_structure)): cnt = contours_structure[i] M = cv2.moments(cnt) cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) #print(str(i) + " x: " + str(cx) + " y: " +str(cy)) pts1[i, 0] = cx pts1[i, 1] = cy #print(pts1) sorted_points_x = pts1[pts1[:, 0].argsort()] #print(sorted_points_x) left_column = sorted_points_x[0:2, :] right_column = sorted_points_x[2:, :] sorted_points_y_left = left_column[left_column[:, 1].argsort()] sorted_points_y_right = right_column[right_column[:, 1].argsort()] pts_src = np.asarray( np.concatenate((sorted_points_y_left, sorted_points_y_right), axis=0), "float32") #print(pts_src) pts_dest = np.float32([[0, 0], [0, target_dim[1]], [target_dim[1], 0], [target_dim[1], target_dim[1]]]) M = cv2.getPerspectiveTransform(pts_src, pts_dest) px, py = Image_Tools.getIntersection(pts_src) pts_src_corrected, ROI_bull, ROI_center = self._correctCenterOfBull( BASE_IM_GRAY, BASE_IM_red, px, py, pts_src) return M, pts_src_corrected
def computePerspectiveTransformationPts(self, PTS, BASE_IM_GRAY, BASE_IM_red): #PTS: top,bottom,left,right target_dim = Dartboard.ENV['DART_BOARD_TARGET_DIMENSION'] pts_src = np.asarray(([PTS[0][0], PTS[0][1]], [PTS[3][0], PTS[3][1]], [PTS[2][0], PTS[2][1]], [PTS[1][0], PTS[1][1]]), "float32") diag = np.sqrt(((target_dim[0] / 2) * (target_dim[0] / 2)) + ((target_dim[1] / 2) * (target_dim[1] / 2))) r = target_dim[0] / 2 offset_diag = diag - r offset = np.sqrt((offset_diag * offset_diag) / 2) #top, right,left,bottom pts_dest = np.float32([[0 + offset, 0 + offset], [0 + offset, target_dim[1] - offset], [target_dim[1] - offset, 0 + offset], [target_dim[1] - offset, target_dim[1]] - offset ]) M = cv2.getPerspectiveTransform(pts_src, pts_dest) px, py = Image_Tools.getIntersection(pts_src) pts_src_corrected, ROI_bull, ROI_center = self._correctCenterOfBull( BASE_IM_GRAY, BASE_IM_red, px, py, pts_src) return M, pts_src_corrected
def _correctCenterOfBull(self, IM_ROI_grey, IM_ROI_red, px, py, src_points): src_points = src_points.copy() offset = Dartboard.ENV["BULL_CENTER_DETECTION_SIZE"] ROI_center = IM_ROI_grey[px - offset:px + offset, py - offset:py + offset] IM_ROI_red_center = IM_ROI_red[px - offset:px + offset, py - offset:py + offset] ROI_bull = ROI_center * IM_ROI_red_center im2, contours, hierarchy = cv2.findContours(ROI_bull.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) if len(contours) == 0: return None, None, None idx = Image_Tools.getMaxContourIdx(contours) bull_contour = contours[idx] M = cv2.moments(bull_contour) cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) #scale back cx = (px - offset) + cx cy = (py - offset) + cy correction_offset_x = cx - px correction_offset_y = cy - py src_points[0, 0] += correction_offset_x src_points[3, 0] += correction_offset_x src_points[1, 1] += correction_offset_y src_points[2, 1] += correction_offset_y return src_points, ROI_bull, ROI_center
def warpWithRotation(self, IM_ROI_grey, M): target_dim = Dartboard.ENV['DART_BOARD_TARGET_DIMENSION'] IM_ROI_NORMAL = cv2.warpPerspective(IM_ROI_grey, M, (target_dim[1], target_dim[1])) IM_ROI_ROTATED = Image_Tools.rotateImage( IM_ROI_NORMAL, -1 * Dartboard.ENV['DART_BOARD_TARGET_ROTATION']) return IM_ROI_ROTATED, IM_ROI_NORMAL
def computeBaseFrame(self, IM, IM_GRAY): print("--Computing New Baseframe--") x, y, w, h, BOARD, GREEN, RED = self.dartboard_detector.detectDartboard( IM) self.BASE_IM = self.dartboard_detector.scaleROI( Image_Tools.getROI(IM, x, y, w, h)) self.BASE_IM_GRAY = self.dartboard_detector.scaleROI( Image_Tools.getROI(IM_GRAY, x, y, w, h)) self.BASE_IM_green = self.dartboard_detector.scaleROI( Image_Tools.getROI(GREEN, x, y, w, h)) self.BASE_IM_red = self.dartboard_detector.scaleROI( Image_Tools.getROI(RED, x, y, w, h)) self.BASE_IM_board = self.dartboard_detector.scaleROI( Image_Tools.getROI(BOARD, x, y, w, h)) self.ROI_x = x self.ROI_y = y self.ROI_w = w self.ROI_h = h IM_ROI_thres_color, IM_ROI_thres_color_closed, contours_structure = self.dartboard_detector.getOrientation( self.BASE_IM, self.BASE_IM_board) #GUI.show(Image_Tools.debugContours(IM_ROI_thres_color,contours_structure),"ORIENTATION") self.M, src_points = self.dartboard.computePerspectiveTransformation( contours_structure, self.BASE_IM_GRAY, self.BASE_IM_red) if src_points is None: self.reset() return px, py = Image_Tools.getIntersection(src_points) if py is None: self.reset() return self.M_corrected = self.dartboard.computePerspectiveTransformationCorrection( src_points) self.PREVIOUS_DIFFERENCE = None
def drawDartboard(self): IM = np.zeros(Dartboard.ENV['DART_BOARD_TARGET_DIMENSION'], "uint8") offset = Dartboard.ENV['DART_BOARD_TARGET_OFFSET'] center = (IM.shape[0] // 2, IM.shape[1] // 2) size_dartboard = 3400 + offset scale = IM.shape[0] / size_dartboard rad_board = int(3400 / 2 * scale) rad_bull = int(127 / 2 * scale) rad_ring = int(318 / 2 * scale) rad_double = int((3400 - 160) / 2 * scale) rad_triple = int((2140 - 160) / 2 * scale) width_rings = int(80 * scale) line_thickness = int(12 * scale) angle = 360 // 20 angle_offset = 9 #rings cv2.circle(IM, center, rad_bull, (255, 255, 255), line_thickness) cv2.circle(IM, center, rad_ring, (255, 255, 255), line_thickness) cv2.circle(IM, center, rad_double, (255, 255, 255), line_thickness) cv2.circle(IM, center, rad_double + width_rings, (255, 255, 255), line_thickness) cv2.circle(IM, center, rad_triple, (255, 255, 255), line_thickness) cv2.circle(IM, center, rad_triple + width_rings, (255, 255, 255), line_thickness) #lines line_shape = np.zeros(IM.shape, "uint8") line_shape[:, (line_shape.shape[1] // 2) - line_thickness:(line_shape.shape[1] // 2) + line_thickness] = 255 IM_temp = np.zeros(IM.shape, "uint8") for i in range(0, 360, angle): line_shape_rot = Image_Tools.rotateImage(line_shape, i + angle_offset) IM_temp = IM_temp + line_shape_rot #restore bull IM_mask = np.zeros(IM.shape, "uint8") cv2.circle(IM_mask, center, rad_board, (255, 255, 255), -1) cv2.circle(IM_mask, center, rad_ring, (0, 0, 0), -1) IM = IM + (IM_temp * IM_mask) #create Mask IM_mask = np.zeros(IM.shape, "uint8") cv2.circle(IM_mask, center, rad_board, (255, 255, 255), -1) #make color IM_color = np.repeat(IM[:, :, np.newaxis], 3, axis=2) return IM_color, IM_mask
def computeArrowOrientation(self, IM, arange, kernel): max_contour_length = 0 max_angle = 0 max_contour = 0 max_img = 0 for i in arange: kernel_rot = Image_Tools.rotateImage(kernel, i) closed = cv2.morphologyEx(IM, cv2.MORPH_CLOSE, kernel_rot) im2, contours, hierarchy = cv2.findContours( closed.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) for j in range(len(contours)): length = cv2.arcLength(contours[j], True) if length > max_contour_length: max_contour_length = length max_angle = i max_contour = contours[j] max_img = closed return max_contour_length, max_angle, max_contour, max_img
def _detectArrowLine(self, IM_closed, max_contour, xx, yy, ww, hh): # Improve with fitting line line_image = np.zeros(IM_closed.shape, "uint8") line_image_peak = np.zeros(IM_closed.shape, "uint8") # then apply fitline() function [vx, vy, x, y] = cv2.fitLine(max_contour, cv2.DIST_L2, 0, 0.01, 0.01) # Now find two extreme points on the line to draw line righty = int((-x * vy / vx) + y) lefty = int(((line_image.shape[1] - x) * vy / vx) + y) #Finally draw the line cv2.line(line_image, (line_image.shape[1] - 1, lefty), (0, righty), 255, Arrow_Detector.ENV['DETECTION_APEX_LINE_THICKNESS']) cv2.line(line_image_peak, (line_image.shape[1] - 1, lefty), (0, righty), 255, Arrow_Detector.ENV['DETECTION_APEX_LINE_THICKNESS_PEAK']) #compute orientation (h, v) = self.detectArrowState( Image_Tools.getROI(IM_closed, xx, yy, ww, hh)) if h == 'l': if v == 'u': arrow_x1 = xx + ww arrow_y1 = yy + hh else: arrow_x1 = xx + ww arrow_y1 = yy else: if v == 'u': arrow_x1 = xx arrow_y1 = yy + hh else: arrow_x1 = xx arrow_y1 = yy return arrow_x1, arrow_y1, line_image_peak, h, v
def _detectApex(self, IM_ROI2_grey, line_image_peak, arrow_x1, arrow_y1, h, v): # Isolate the apex offset = Arrow_Detector.ENV['DETECTION_APEX_OFFSET'] IM_ROI_APEX = IM_ROI2_grey[arrow_y1 - offset:arrow_y1 + offset, arrow_x1 - offset:arrow_x1 + offset] IM_ROI_LINE = line_image_peak[arrow_y1 - offset:arrow_y1 + offset, arrow_x1 - offset:arrow_x1 + offset] IM_ROI_APEX_edges = cv2.Canny(IM_ROI_APEX, 50, 100) IM_ROI_APEX_masekd = cv2.multiply(IM_ROI_LINE, IM_ROI_APEX_edges) #GUI.imShow(IM_ROI_APEX) #GUI.imShow(IM_ROI_APEX_edges) im2_line, contours_line, hierarchy_line = cv2.findContours( IM_ROI_APEX_masekd.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) if len(contours_line) == 0: return None, None, None, None, None, None, None, None, None, None max_contour_idx = Image_Tools.getMaxContourIdx(contours_line) xxx, yyy, www, hhh = cv2.boundingRect(contours_line[max_contour_idx]) #GUI.imShow(Image_Tools.debugRectangle(IM_ROI_APEX_masekd,xxx,yyy,www,hhh)) #GUI.imShow(IM_ROI_APEX_masekd) IM_ROI_APEX_clipped = np.zeros(IM_ROI_APEX_masekd.shape, "uint8") IM_ROI_APEX_clipped[yyy:yyy + hhh, xxx:xxx + www] = IM_ROI_APEX_masekd[yyy:yyy + hhh, xxx:xxx + www] IM_ROI_APEX_masekd = IM_ROI_APEX_clipped #GUI.imShow(IM_ROI_APEX_clipped) # respect orientation y, x = np.where(IM_ROI_APEX_masekd > 1) np.sort(y) #print(h) #print(v) if h == 'l': if v == 'u': arrow_y2 = y[y.shape[0] - 1] x = np.where(IM_ROI_APEX_masekd[arrow_y2, :] > 1)[0] np.sort(x) arrow_x2 = x[x.shape[0] - 1] else: arrow_y2 = y[0] x = np.where(IM_ROI_APEX_masekd[arrow_y2, :] > 1)[0] arrow_x2 = x[x.shape[0] - 1] else: if v == 'u': arrow_y2 = y[y.shape[0] - 1] x = np.where(IM_ROI_APEX_masekd[arrow_y2, :] > 1)[0] np.sort(x) arrow_x2 = x[0] #arrow_y2 = yyy #arrow_x2 = xxx else: arrow_y2 = y[0] x = np.where(IM_ROI_APEX_masekd[arrow_y2, :] > 1)[0] np.sort(x) arrow_x2 = x[0] # transform to original space arrow_y1 = (arrow_y1 - offset) + arrow_y2 arrow_x1 = (arrow_x1 - offset) + arrow_x2 return arrow_x1, arrow_y1, IM_ROI_APEX
def capture(self): video = cv2.VideoCapture() if Darty.ENV['VIDEO_INPUT_PATH']: video = cv2.VideoCapture(Darty.ENV['VIDEO_INPUT_PATH']) # Fps stuff loop_delta = 1. / Darty.ENV['FPS_LIMIT'] current_time = target_time = time.clock() frame_counter = 0 while (True): # Sleep management. Limit fps. target_time += loop_delta sleep_time = target_time - time.clock() if sleep_time > 0: time.sleep(sleep_time) print("--FPS sleep--") # Loop frequency evaluation, prints actual fps previous_time, current_time = current_time, time.clock() time_delta = current_time - previous_time current_fps = 1. / time_delta # # Read Frame # ret, new_frame = video.read() #video.set(cv2.CAP_PROP_POS_FRAMES, frame_counter) if new_frame is None: print("END OF VIDEO, BREAKING") break # no more frames to read # # Subsample over time # if frame_counter % Darty.ENV['FPS_SKIP'] == 0: print('frequency: ' + str(current_fps) + " fps_skip: " + str(Darty.ENV['FPS_SKIP'])) IM, IM_GRAY = Image_Tools.prepareImage( new_frame, (Darty.ENV['RESOLUTION_WIDTH'], Darty.ENV['RESOLUTION_HEIGHT'])) # # Compute Base Image for the first time # #print("frame: " + str(frame_counter)) if self.BASE_IM is None: self.computeBaseFrame(IM, IM_GRAY) continue # # Get ROI # IM_ROI = self.dartboard_detector.scaleROI( Image_Tools.getROI(IM, self.ROI_x, self.ROI_y, self.ROI_w, self.ROI_h)) IM_ROI_grey = self.dartboard_detector.scaleROI( Image_Tools.getROI(IM_GRAY, self.ROI_x, self.ROI_y, self.ROI_w, self.ROI_h)) GUI.show(IM, "FEED") # # Difference detection # IM_ROI_difference, IM_ROI_GRAY_NORM, IM_ROI_GRAY2_NORM, IM_ROI_GRAY_NORM_DIFF = self.difference_detector.computeDifference( self.BASE_IM_GRAY, IM_ROI_grey) difference_sum = np.sum(IM_ROI_difference) if difference_sum > Darty.ENV['DIFFERENCE_THRES_RESET']: self.computeBaseFrame(IM, IM_GRAY) continue #print("Difference: " + str(difference_sum) + "px") if difference_sum > Darty.ENV['DIFFERENCE_THRES']: # # Arrow Detection # IM_arrow_closed, arrow_x1, arrow_y1, xx, yy, ww, hh, line_image, apex_image = self.arrow_detector.detectArrow( IM_ROI_difference, IM_ROI_grey) if arrow_x1 is not None: IM_arrow_roi1 = self.arrow_detector.debugApex( IM_ROI, arrow_x1, arrow_y1, (0, 255, 0)) IM_ROI_grey = self.arrow_detector.markApex( IM_ROI_grey, arrow_x1, arrow_y1) # # Draw Dartboard # IM_ROI_ROTATED, IM_ROI_NORMAL = self.dartboard.warpWithRotation( IM_ROI_grey, self.M_corrected) cx, cy, angle, length, cross, IM_dot, IM_line = self.arrow_detector.getMetricOfArrow( IM_ROI_ROTATED) if cx is not None: score = self.dartboard.calcScore(angle, length) IM_dartboard, IM_mask = self.dartboard.drawDartboard( ) IM_dartboard_geo, IM_dartboard_error = self.dartboard.drawFinalDartboard( IM_dartboard, IM_dot, IM_ROI_ROTATED) IM_score = self.dartboard.drawScore( IM_dartboard_error, score) GUI.show(IM_score, "DARTBOARD") print("--Arrow Detected: Score was: " + str(score)) self.computeBaseFrame(IM, IM_GRAY) else: if self.PREVIOUS_DIFFERENCE is None: self.PREVIOUS_DIFFERENCE = IM_ROI_difference else: IM_ROI_difference = cv2.add(self.PREVIOUS_DIFFERENCE, IM_ROI_difference) self.PREVIOUS_DIFFERENCE = IM_ROI_difference cv2.waitKey(1) frame_counter += 1 cv2.destroyAllWindows()