def detect_markers(img, marker_size, camK): width, height, _ = img.shape gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) [img_min, img_max, minLoc, maxLoc] = cv2.minMaxLoc(gray) # cv2.imshow("gray", gray) edges = cv2.Canny(gray, 50, 100) # cv2.imshow("edges", edges) # cv2.waitKey(1) contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2:] # We only keep the long enough contours min_contour_length = min(width, height) / 10 contours = [ contour for contour in contours if len(contour) > min_contour_length ] canonical_marker_coords = array( ((0, 0), (WARPED_SIZE - 1, 0), (WARPED_SIZE - 1, WARPED_SIZE - 1), (0, WARPED_SIZE - 1)), dtype='float32') # imgc = img.copy() # #cv2.drawContours(imgc, contours, -1, (0,255,0), 3) # for cidx in range(1, len(contours)): # cv2.drawContours(imgc, contours, cidx, (randint(0,255), randint(0,255), randint(0,255)), 3) # cv2.imshow("contours", imgc) # cv2.waitKey(1) markers_list = [] # polydtct_counters = [] for contour in contours: approx_curve = cv2.approxPolyDP(contour, len(contour) * 0.05, True) if not (len(approx_curve) == 4 and cv2.isContourConvex(approx_curve)): continue sorted_curve = array(cv2.convexHull(approx_curve, clockwise=False), dtype='float32') # polydtct_counters.append(cv2.convexHull(approx_curve, clockwise=False)) # wrap image persp_transf = cv2.getPerspectiveTransform(sorted_curve, canonical_marker_coords) warped_img = cv2.warpPerspective(img, persp_transf, (WARPED_SIZE, WARPED_SIZE)) warped_gray = cv2.cvtColor(warped_img, cv2.COLOR_BGR2GRAY) # check max and min pixel value in the wrapped image # reject common unified color areas [warp_min, warp_max, minLoc, maxLoc] = cv2.minMaxLoc(warped_gray) if (warp_max - warp_min) / (img_max - img_min) < 0.3: continue # get a good threshold for binary operation, # average of all pixels wraped_gray_avg = cv2.mean(warped_gray)[0] # binary image _, warped_bin = cv2.threshold(warped_gray, wraped_gray_avg, 255, cv2.THRESH_BINARY) # # reshape to one block per pixel # marker = warped_bin.reshape( # [MARKER_SIZE, WARPED_SIZE / MARKER_SIZE, MARKER_SIZE, WARPED_SIZE / MARKER_SIZE] # ) # # binary reshaped image # marker = marker.mean(axis=3).mean(axis=1) # marker[marker < 127] = 0 # marker[marker >= 127] = 1 # get better coding from sampling not reshaping patch_size = WARPED_SIZE // MARKER_SIZE patch_kenrel = np.ones( (patch_size, patch_size), np.float32) / (patch_size * patch_size) wraped_bin_filter = cv2.filter2D(warped_bin, -1, patch_kenrel, borderType=cv2.BORDER_REPLICATE) kernel_accept_thresh = 0.4 # < 0.5 marker = np.zeros((MARKER_SIZE, MARKER_SIZE)) read_marker_success = True for i in range(1, MARKER_SIZE): for j in range(1, MARKER_SIZE): # # single pixel sampling # if warped_bin[(i+0.5)*patch_size, (j+0.5)*patch_size] > 0: # marker[i,j] = 1 # kernel sampling method if wraped_bin_filter[int((i + 0.5) * patch_size), int((j + 0.5) * patch_size)] > 256 * ( 1 - kernel_accept_thresh): marker[i, j] = 1 elif wraped_bin_filter[int( (i + 0.5) * patch_size ), int((j + 0.5) * patch_size)] > 256 * kernel_accept_thresh: read_marker_success = False break if not read_marker_success: continue # cv2.imshow("bin", warped_bin) # cv2.waitKey(50) # cv2.imshow("warped_marker", rot90(warped_bin, k=0)) # cv2.waitKey(50) try: # rotate marker by checking which corner is white turn_number = validate_and_get_turn_number(marker) marker = rot90(marker, k=turn_number) # get id hamming_code = extract_hamming_code(marker) marker_id = int(decode(hamming_code), 2) except ValueError: continue # rotate corner list rotated_contour = rotate_contour(sorted_curve, persp_transf, turn_number) detected_marker = HammingMarker(id=marker_id, contours=rotated_contour, size=marker_size) # get pose and update detected marker pose_results = get_marker_pose(detected_marker, detected_marker.size, camK) if pose_results[0]: detected_marker.rvec = pose_results[1] detected_marker.tvec = pose_results[2] else: # cannot find pose using contours continue markers_list.append(detected_marker) # imgpoly = img.copy() # for cidx in range(1, len(polydtct_counters)): # cv2.drawContours(imgpoly, polydtct_counters, cidx, (randint(0,255), randint(0,255), randint(0,255)), 3) # cv2.imshow("contours poly", imgpoly) # cv2.waitKey(1) return markers_list
def detect_markers(img, marker_size, camK): width, height, _ = img.shape gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #normalize image, map brightest pixel to 255 and smalles pixel val to 0. ''' [minVal, maxVal, minLoc, maxLoc] = cv2.minMaxLoc(gray) mult = 255/(maxVal-minVal) normalized_image = gray - minVal normalized_image = np.uint8(mult * normalized_image) ''' edges = cv2.Canny(gray, 10, 100) #cv2.imshow("edges", edges) #cv2.waitKey(1) contours, hierarchy = cv2.findContours(edges.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2:] # We only keep the long enough contours min_contour_length = min(width, height) / 50 contours = [ contour for contour in contours if len(contour) > min_contour_length ] canonical_marker_coords = array( ((0, 0), (WARPED_SIZE - 1, 0), (WARPED_SIZE - 1, WARPED_SIZE - 1), (0, WARPED_SIZE - 1)), dtype='float32') markers_list = [] for contour in contours: approx_curve = cv2.approxPolyDP(contour, len(contour) * 0.01, True) if not (len(approx_curve) == 4 and cv2.isContourConvex(approx_curve)): continue sorted_curve = array(cv2.convexHull(approx_curve, clockwise=False), dtype='float32') persp_transf = cv2.getPerspectiveTransform(sorted_curve, canonical_marker_coords) warped_img = cv2.warpPerspective(img, persp_transf, (WARPED_SIZE, WARPED_SIZE)) warped_gray = cv2.cvtColor(warped_img, cv2.COLOR_BGR2GRAY) _, warped_bin = cv2.threshold(warped_gray, 127, 255, cv2.THRESH_BINARY) marker = warped_bin.reshape([ MARKER_SIZE, WARPED_SIZE // MARKER_SIZE, MARKER_SIZE, WARPED_SIZE // MARKER_SIZE ]) marker = marker.mean(axis=3).mean(axis=1) marker[marker < 127] = 0 marker[marker >= 127] = 1 try: # rotate marker by checking which corner is white turn_number = validate_and_get_turn_number(marker) marker = rot90(marker, k=turn_number) #cv2.imshow("bin", warped_bin) #cv2.waitKey(10) #cv2.imshow("warped_marker", rot90(warped_bin, k=turn_number)) #cv2.waitKey(10) # get id hamming_code = extract_hamming_code(marker) marker_id = int(decode(hamming_code), 2) except ValueError: continue # rotate corner list rotated_contour = rotate_contour(sorted_curve, persp_transf, turn_number) detected_marker = HammingMarker(id=marker_id, contours=rotated_contour, size=marker_size) # get pose and update detected marker pose_results = get_marker_pose(detected_marker, detected_marker.size, camK) if pose_results[0]: detected_marker.rvec = pose_results[1] detected_marker.tvec = pose_results[2] else: # cannot find pose using contours continue markers_list.append(detected_marker) return markers_list