def fill_binary(image): image = np.zeros([400, 400, 3], np.uint8) image[100:300, 100:300, :] = 255 mask = np.ones([402, 402, 1], np.uint8) mask[101:301, 101:301] = 0 cv.floodFill(image, mask, (200, 200), (0, 0, 255), cv.FLOODFILL_MASK_ONLY) cv.imshow("fill_binary", image)
def fill_color_demo(image): copyImg = image.copy() h, w = image.shape[:2] mask = np.zeros([h + 2, w + 2], np.uint8) cv.floodFill(copyImg, mask, (30, 30), (0, 255, 255), (100, 100, 100), (50, 50, 50), cv.FLOODFILL_FIXED_RANGE) cv.imshow("fill_color_demo", copyImg)
def find_all_template(cls, source, target, threshold=0.8, mac_count=None): mask = None if len(target.shape) == 3 and target.shape[2] == 4: mask = target[:, :, 3] target = cv2.cvtColor(target, cv2.COLOR_BGRA2BGR) res = cv2.matchTemplate(source, target, cv2.TM_CCOEFF_NORMED, mask=mask) result = [] height, width = target.shape[:2] while True: _, max_val, _, tl = cv2.minMaxLoc(res) if max_val < threshold: break br = (tl[0] + width, tl[1] + height) mp = (int(tl[0] + width / 2), int(tl[1] + height / 2)) result.append({ 'pt': mp, 'rect': (tl, br), 'conf': max_val }) if mac_count is not None: if mac_count <= 0: break else: mac_count -= 1 cv2.floodFill(res, None, tl, (-1000,), max_val-threshold+0.1, 1, flags=cv2.FLOODFILL_FIXED_RANGE) return result
def get_rm(img, vp, roi, config): rm_type = config['rm'].getint('type') if rm_type == 0: rm_mask = rm_static_noshade(img, roi, config) elif rm_type == 1: rm_mask = rm_static_sunshade(img, roi, config) elif rm_type == 2: rm_mask = rm_otsu_noshade(img, roi, config) elif rm_type == 3: rm_mask = rm_otsu_sunshade(img, roi, config) else: logging.error('Invalid road marking type.') rm_mask = None # remove glare near vp if config['rm'].getboolean('has_glare'): # cv2.imshow('before deglare', rm_mask) # cv2.waitKey(0) radius = config['rm'].getint('glare_radius') rm_mask = cv2.circle(rm_mask, vp, radius, 255, cv2.FILLED) # cv2.imshow('before deglare', rm_mask) # cv2.waitKey(0) cv2.floodFill(rm_mask, None, vp, 0) # cv2.imshow('before deglare', rm_mask) # cv2.waitKey(0) return rm_mask
def fill_color_demo(image): copyIma = image.copy() w, h = image.shape[:2] print(w, h) mask = np.zeros([w + 2, h + 2], np.uint8) cv.floodFill(copyIma, mask, (30, 30), (0, 255, 255), (50, 50, 50), (50, 50, 50), cv.FLOODFILL_FIXED_RANGE) # cv.floodFill(copyIma, mask, (30, 30), (0, 255, 255), (20, 20, 10), (20, 20, 20)) cv.imshow("fill_color", copyIma)
def fill_binary(): image = np.zeros([400, 400, 3], np.uint8) image[50:350, 50:350, :] = [0, 255, 0] image[100:300, 100:300, :] = 255 cv.imshow("fill_binary", image) mask = np.ones([402, 402, 1], np.uint8) mask[60:340, 60:340] = 0 # this range will be flood filled cv.floodFill(image, mask, (60, 60), (0, 0, 255), cv.FLOODFILL_MASK_ONLY) cv.imshow("filled binary", image)
def fill_binary(): #mask的指定的位置为零时才填充,不为零不填充 image = np.zeros([400, 400, 3], np.uint8) image[100:300, 100:300, :] = 255 cv.imshow("fill banary", image) mask = np.ones([402, 402, 1], np.uint8) mask[101:301, 101:301] = 0 cv.floodFill(image, mask, (200, 200), (100, 2, 255), cv.FLOODFILL_MASK_ONLY) cv.imshow("filled banary", image)
def get_corners(painting_roi, draw=False): gray = cv2.cvtColor(painting_roi, cv2.COLOR_BGR2GRAY) blur = cv2.bilateralFilter(gray, 9, 75, 75) erosion = cv2.erode(blur, np.ones((9, 9), np.uint8), iterations=2) dilation = cv2.dilate(erosion, np.ones((9, 9), np.uint8), iterations=2) _, thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # edges = auto_canny(thresh) h, w = thresh.shape[:2] mask = np.zeros((h + 2, w + 2), np.uint8) flood = thresh.copy() cv2.floodFill(flood, mask, (0, 0), 255) im_floodfill_inv = cv2.bitwise_not(flood) im_out = thresh | im_floodfill_inv contours, _ = cv2.findContours(im_out, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # find the biggest countour (c) by the area c = max(contours, key=cv2.contourArea) x, y, w, h = cv2.boundingRect(c) bbox = x, y, w, h corners = cv2.goodFeaturesToTrack(im_out[y - 10:y + h + 10, x:x + w + 10], 4, 0.01, painting_roi.shape[0] / 3, useHarrisDetector=True) corners = np.int0(corners) corners = np.squeeze(corners) corners_img = painting_roi.copy() # draw the biggest contour (c) in green cv2.rectangle(corners_img, (x, y), (x + w + 10, y + h + 10), (0, 255, 0), 2) if draw: for i, corner in enumerate(corners): x_corner, y_corner = corner.ravel() cv2.circle(corners_img, (x_corner, y_corner), 3, 255, -1) cv2.putText(corners_img, f'{i}', (x_corner + 3, y_corner + 3), cv2.FONT_HERSHEY_SIMPLEX, 0.75, color=(255, 0, 0)) cv2.imshow("corners", corners_img) # for corner in corners: # corner[0] += x # corner[1] += y return corners, bbox
def Fill_Holes(image): im_fill = image.copy() h, w = image.shape[:2] mask = np.zeros((h + 2, w + 2), np.uint8) cv2.floodFill(im_fill, mask, (0, 0), 255) im_fill_inv = cv2.bitwise_not(im_fill) filled_image = cv2.bitwise_or(im_fill_inv, image) return filled_image
def cut_background(img_src): """ @return x, y, w, h """ img = img_src.copy() h, w = img.shape[:2] # 背景填充 进行泛洪填充 mask = np.zeros((h + 2, w + 2), np.uint8) #掩码长和宽都比输入图像多两个像素点,满水填充不会超出掩码的非零边缘 cv2.floodFill(img, mask, (5, 5), (255, 255, 255), (3, 3, 3), (5, 5, 5), 8) # 去噪 img = cv2.fastNlMeansDenoisingColored(img, None, 20, 20, 7, 21) # 背景识别 mask = np.zeros((img.shape[:2]), np.uint8) bgdModel = np.zeros((1, 65), np.float64) fgdModel = np.zeros((1, 65), np.float64) rect = (5, 5, w - 5, h - 5) # 多次计算,保证计算准确度 cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 1, cv2.GC_INIT_WITH_RECT) #关于where函数第一个参数是条件,满足条件的话赋值为0,否则是1。如果只有第一个参数的话返回满足条件元素的坐标。 mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8') # 绘制轮廓 draw_img = img * mask2[:, :, np.newaxis] # 前景图使用白色填充,方便识别 draw_img[np.where((draw_img > [0, 0, 0]).all(axis=2))] = [255, 255, 255] # h, w = draw_img.shape[:2] draw_img = cv2.cvtColor(draw_img, cv2.COLOR_BGR2GRAY) #得到灰度图 _, binary = cv2.threshold(draw_img, 200, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) contours, _ = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) if len(contours) < 1: return img else: max_countor = sorted(contours, key=cv2.contourArea, reverse=True)[0] return cv2.boundingRect(max_countor)
def component_detection(binary, min_obj_area=C.THRESHOLD_OBJ_MIN_AREA, line_thickness=C.THRESHOLD_LINE_THICKNESS, min_rec_evenness=C.THRESHOLD_REC_MIN_EVENNESS, max_dent_ratio=C.THRESHOLD_REC_MAX_DENT_RATIO, step_h=5, step_v=2, rec_detect=False, show=False, test=False): """ :param binary: Binary image from pre-processing :param min_obj_area: If not pass then ignore the small object :param min_obj_perimeter: If not pass then ignore the small object :param line_thickness: If not pass then ignore the slim object :param min_rec_evenness: If not pass then this object cannot be rectangular :param max_dent_ratio: If not pass then this object cannot be rectangular :return: boundary: [top, bottom, left, right] -> up, bottom: list of (column_index, min/max row border) -> left, right: list of (row_index, min/max column border) detect range of each row """ mask = np.zeros((binary.shape[0] + 2, binary.shape[1] + 2), dtype=np.uint8) compos_all = [] compos_rec = [] compos_nonrec = [] row, column = binary.shape[0], binary.shape[1] for i in range(0, row, step_h): for j in range(i % 2, column, step_v): if binary[i, j] == 255 and mask[i, j] == 0: # get connected area # region = util.boundary_bfs_connected_area(binary, i, j, mask) mask_copy = mask.copy() cv2.floodFill(binary, mask, (j, i), None, 0, 0, cv2.FLOODFILL_MASK_ONLY) mask_copy = mask - mask_copy region = np.nonzero(mask_copy[1:-1, 1:-1]) region = list(zip(region[0], region[1])) # filter out some compos # ignore small area if len(region) < min_obj_area: continue component = Component(region, binary.shape) # calculate the boundary of the connected area # ignore small area if component.width <= 3 or component.height <= 3: continue # check if it is line by checking the length of edges if component.compo_is_line(line_thickness): continue if test: print('Area:%d' % (len(region))) draw.draw_boundary([component], binary.shape, show=True) compos_all.append(component) if rec_detect: # rectangle check if component.compo_is_rectangle(min_rec_evenness, max_dent_ratio): component.rect_ = True compos_rec.append(component) else: component.rect_ = False compos_nonrec.append(component) if show: print('Area:%d' % (len(region))) draw.draw_boundary(compos_all, binary.shape, show=True) # draw.draw_boundary(compos_all, binary.shape, show=True) if rec_detect: return compos_rec, compos_nonrec else: return compos_all
def floodFill(img): cv.floodFill(img)
def block_division(grey, org, show=False, write_path=None, step_h=10, step_v=10, grad_thresh=C.THRESHOLD_BLOCK_GRADIENT, line_thickness=C.THRESHOLD_LINE_THICKNESS, min_rec_evenness=C.THRESHOLD_REC_MIN_EVENNESS, max_dent_ratio=C.THRESHOLD_REC_MAX_DENT_RATIO, min_block_height_ratio=C.THRESHOLD_BLOCK_MIN_HEIGHT): ''' :param grey: grey-scale of original image :return: corners: list of [(top_left, bottom_right)] -> top_left: (column_min, row_min) -> bottom_right: (column_max, row_max) ''' blocks = [] mask = np.zeros((grey.shape[0] + 2, grey.shape[1] + 2), dtype=np.uint8) broad = np.zeros((grey.shape[0], grey.shape[1], 3), dtype=np.uint8) broad_all = broad.copy() row, column = grey.shape[0], grey.shape[1] for x in range(0, row, step_h): for y in range(0, column, step_v): if mask[x, y] == 0: # region = flood_fill_bfs(grey, x, y, mask) # flood fill algorithm to get background (layout block) mask_copy = mask.copy() cv2.floodFill(grey, mask, (y, x), None, grad_thresh, grad_thresh, cv2.FLOODFILL_MASK_ONLY) mask_copy = mask - mask_copy region = np.nonzero(mask_copy[1:-1, 1:-1]) region = list(zip(region[0], region[1])) # ignore small regions if len(region) < 500: continue block = Block(region, grey.shape) draw.draw_region(region, broad_all) # if block.height < 40 and block.width < 40: # continue if block.height < 30: continue # print(block.area / (row * column)) if block.area / (row * column) > 0.9: continue elif block.area / (row * column) > 0.7: block.redundant = True # get the boundary of this region # ignore lines if block.compo_is_line(line_thickness): continue # ignore non-rectangle as blocks must be rectangular if not block.compo_is_rectangle(min_rec_evenness, max_dent_ratio): continue # if block.height/row < min_block_height_ratio: # continue blocks.append(block) draw.draw_region(region, broad) # if show: # cv2.imshow('flood-fill all', broad_all) # cv2.imshow('block', broad) # cv2.waitKey() if write_path is not None: cv2.imwrite(write_path, broad) return blocks
def fill_border_contour(contour, img_shape): mask = np.zeros(img_shape, dtype=np.uint8) cv2.drawContours(mask, [contour], 0, 255, cv2.FILLED) # Extract the perimeter pixels, leaving out the last pixel # of each side as it is included in the next side (going clockwise). # This makes all the side arrays the same length. # We also flip the bottom and left side, as we want to "unwrap" the # perimeter pixels in a clockwise fashion. top = mask[0, :-1] right = mask[:-1, -1] bottom = np.flipud(mask[-1, 1:]) left = np.flipud(mask[1:, 0]) # combine the perimeter sides into one continuous array perimeter_pixels = np.concatenate([top, right, bottom, left]) region_boundary_locs = np.where(perimeter_pixels == 255)[0] # the perimeter here is not a geometric perimeter but the number of pixels around the image img_h = img_shape[0] img_w = img_shape[1] perimeter = (img_h - 1) * 2 + (img_w - 1) * 2 # account for the wrap around from the last contour pixel to the end, # i.e. back at the start at (0, 0) wrap_distance = region_boundary_locs.max() - perimeter # insert the wrap distance in front of the region boundary locations region_boundary_locs = np.concatenate([[wrap_distance], region_boundary_locs]) # calculate the gap size between boundary pixel locations gaps = np.diff(region_boundary_locs) # if there's only one gap, the contour is already filled if not np.sum(gaps > 1) > 1: return mask # add one to the results because of the diff offset max_gap_idx = np.where(gaps == gaps.max())[0] + 1 # there should only be one, else we have a tie and should probably ignore that case if max_gap_idx.size != 1: return None start_perim_loc_of_flood_entry = region_boundary_locs[max_gap_idx[0]] # see if subsequent perimeter locations were also part of the contour, # adding one to the last one we found subsequent_region_border_locs = region_boundary_locs[ region_boundary_locs > start_perim_loc_of_flood_entry] flood_fill_entry_point = start_perim_loc_of_flood_entry for loc in subsequent_region_border_locs: if loc == flood_fill_entry_point + 1: flood_fill_entry_point = loc # we should hit the first interior empty point of the contour # by moving forward one pixel around the perimeter flood_fill_entry_point += 1 # now to convert our perimeter location back to an image coordinate if flood_fill_entry_point < img_w: flood_fill_entry_coords = (flood_fill_entry_point, 0) elif flood_fill_entry_point < img_w + img_h: flood_fill_entry_coords = (img_w - 1, flood_fill_entry_point - img_w + 1) elif flood_fill_entry_point < img_w * 2 + img_h: flood_fill_entry_coords = (img_h + (2 * img_w) - 3 - flood_fill_entry_point, img_h - 1) else: flood_fill_entry_coords = (0, perimeter - flood_fill_entry_point) flood_fill_mask = np.zeros((mask.shape[0] + 2, mask.shape[1] + 2), dtype=np.uint8) cv2.floodFill(mask, flood_fill_mask, tuple(flood_fill_entry_coords), 255) return mask
blurred = cv2.GaussianBlur(gray, (9, 9), 0) #Adaptive gaussian thresholding produced the best results blu_thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 8) inv = cv2.bitwise_not(blu_thresh) kernel = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]], np.uint8) fin = cv2.dilate(inv, kernel) ##DETECTING THE GRID height, width, _ = img.shape maxi = -1 for x in range(0, height): for y in range(0, width): if fin[x, y] >= 128: area = cv2.floodFill(fin, None, (y, x), 80)[0] if area > maxi: maxpt = (y, x) maxi = area cv2.floodFill(fin, None, maxpt, 255) # cv2.imshow("a", fin) # cv2.waitKey(0) # cv2.destroyAllWindows() for x in range(height): for y in range(width): if fin[x, y] == 80 and x != maxpt[1] and y != maxpt[0]: cv2.floodFill(fin, None, (y, x), 0) # fin = cv2.resize(fin, (28, 28)) # cv2.imshow("a", fin) # cv2.waitKey(0)
def flood(image): image_flooded = image.copy() h, w = image.shape[:2] mask = np.zeros((h + 2, w + 2), np.uint8) cv2.floodFill(image_flooded, mask, (0, 0), (0, 0, 0)) return image_flooded