def block_detection(input_img_path, output_root, num=0, resize_by_height=800, show=False): start = time.clock() name = input_img_path.split('\\')[-1][:-4] # *** Step 1 *** pre-processing: read img -> get binary map org, grey = pre.read_img(input_img_path, resize_by_height) # *** Step 2 *** block processing: detect block -> calculate hierarchy -> detect components in block blocks = blk.block_division(grey) blocks = blk.block_add_bkg(blocks, org, grey.shape, show=show) blk.block_hierarchy(blocks) file.save_blocks(pjoin(output_root, name + '.json'), blocks) draw.draw_region(blocks, grey.shape, show=show, write_path=pjoin(output_root, name + '_blk.png')) cv2.imwrite(pjoin(output_root, name + '.png'), org) print("[Compo Detection Completed in %.3f s] %d %s" % (time.clock() - start, num, input_img_path))
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 block_division(grey, show=False, write_path=None, 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) ''' def flood_fill_bfs(img, x_start, y_start, mark): ''' Identify the connected region based on the background color :param img: grey-scale image :param x_start: row coordinate of start position :param y_start: column coordinate of start position :param mark: record passed points :return: region: list of connected points ''' def neighbor(x, y): for i in range(x - 1, x + 2): if i < 0 or i >= img.shape[0]: continue for j in range(y - 1, y + 2): if j < 0 or j >= img.shape[1]: continue if mark[i, j] == 0 and abs(img[i, j] - img[x, y]) < grad_thresh: stack.append([i, j]) mark[i, j] = 255 stack = [[x_start, y_start]] # points waiting for inspection region = [[x_start, y_start]] # points of this connected region mark[x_start, y_start] = 255 # drawing broad while len(stack) > 0: point = stack.pop() region.append(point) neighbor(point[0], point[1]) return region blocks_corner = [] mask = np.zeros((grey.shape[0], grey.shape[1]), dtype=np.uint8) broad = np.zeros((grey.shape[0], grey.shape[1], 3), dtype=np.uint8) row, column = grey.shape[0], grey.shape[1] for x in range(row): for y in range(column): if mask[x, y] == 0: region = flood_fill_bfs(grey, x, y, mask) # ignore small regions if len(region) < 500: continue # get the boundary of this region boundary = util.boundary_get_boundary(region) # ignore lines if util.boundary_is_line(boundary, line_thickness): continue # ignore non-rectangle as blocks must be rectangular if not util.boundary_is_rectangle(boundary, min_rec_evenness, max_dent_ratio, grey.shape): continue block_corner = det.get_corner([boundary])[0] width = block_corner[1][0] - block_corner[0][0] height = block_corner[1][1] - block_corner[0][1] if height / row < min_block_height_ratio: continue blocks_corner.append(block_corner) draw.draw_region(region, broad) if show: cv2.imshow('block', broad) cv2.waitKey() if write_path is not None: cv2.imwrite(write_path, broad) return blocks_corner