Python实现图像表格单元格边框绘制:解决膨胀后单元格融合问题
解决单元格间距过近时表格边框绘制问题
我完全懂你现在的困扰——单元格间距太近,一膨胀就把相邻单元格的文本区域连成了整块,轮廓识别根本分不出单个单元格,自然没法画出正确的边框。咱们换两个更适配这种场景的思路来解决:
思路1:直接提取表格网格线(推荐)
这个方法跳过文本区域的膨胀,直接定位表格的横竖网格线,从网格本身分割单元格,完美适配间距近的表格:
步骤拆解
- 预处理图像:灰度化后用阈值处理突出表格线,再用形态学操作单独提取横线和竖线
- 生成网格掩码:把提取到的横竖线合并,得到完整的表格网格
- 识别单元格轮廓:从网格掩码中找到每个单元格的轮廓,直接绘制边框
改进后的代码
import os import cv2 import numpy as np def extract_table_grid(img): # 灰度化 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 阈值处理:反转颜色,让表格线变成白色 thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] # 提取横线:用水平结构元素 horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40, 1)) horizontal_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2) # 提取竖线:用垂直结构元素 vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 40)) vertical_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2) # 合并横竖线得到网格 grid = cv2.addWeighted(horizontal_lines, 0.5, vertical_lines, 0.5, 0) # 膨胀网格让线条更清晰 grid = cv2.dilate(grid, None, iterations=2) return grid def draw_cell_borders(img, grid): # 找网格的轮廓(每个轮廓就是一个单元格) contours, _ = cv2.findContours(grid, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 过滤掉过小的轮廓(非单元格区域) min_area = 100 # 根据你的图像调整 vis = img.copy() for cnt in contours: area = cv2.contourArea(cnt) if area > min_area: x, y, w, h = cv2.boundingRect(cnt) cv2.rectangle(vis, (x, y), (x+w, y+h), (0, 0, 255), 1) return vis if __name__ == "__main__": in_file = os.path.join("data", "page1.jpg") out_file = os.path.join("data", "out_grid.png") img = cv2.imread(in_file) grid_mask = extract_table_grid(img) result = draw_cell_borders(img, grid_mask) cv2.imwrite(out_file, result)
关键调整说明
- 用水平/垂直结构元素分别提取横竖线,不会让相邻单元格连在一起
- 通过
addWeighted合并横竖线,得到完整的表格网格 - 过滤小轮廓避免误识别页面上的其他小线条
思路2:优化原代码的文本区域聚类
如果你想继续用原思路(从文本区域反推单元格),可以调整膨胀操作的结构元素,避免横向过度膨胀:
修改后的预处理函数
def pre_process_image(img, save_in_file, morph_size=(1, 5)): # 灰度化 pre = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Otsu阈值处理 pre = cv2.threshold(pre,250, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] # 用垂直结构元素膨胀:只让文本上下连成块,横向不膨胀 cpy = pre.copy() struct = cv2.getStructuringElement(cv2.MORPH_RECT, morph_size) cpy = cv2.dilate(~cpy, struct, anchor=(-1, -1), iterations=1) pre = ~cpy if save_in_file is not None: cv2.imwrite(save_in_file, pre) return pre
其他参数调整建议
morph_size改成(1,5)(垂直方向的结构元素),避免横向膨胀导致单元格连在一起cell_threshold调小(比如改成5),因为单元格间距近,需要更精细的聚类min_text_height_limit和max_text_height_limit根据你图像里的文本实际高度调整,避免过滤掉有效文本框
内容的提问来源于stack exchange,提问作者user3809411
相关产品推荐
相关产品推荐

