You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现图像表格单元格边框绘制:解决膨胀后单元格融合问题

解决单元格间距过近时表格边框绘制问题

我完全懂你现在的困扰——单元格间距太近,一膨胀就把相邻单元格的文本区域连成了整块,轮廓识别根本分不出单个单元格,自然没法画出正确的边框。咱们换两个更适配这种场景的思路来解决:


思路1:直接提取表格网格线(推荐)

这个方法跳过文本区域的膨胀,直接定位表格的横竖网格线,从网格本身分割单元格,完美适配间距近的表格:

步骤拆解

  1. 预处理图像:灰度化后用阈值处理突出表格线,再用形态学操作单独提取横线和竖线
  2. 生成网格掩码:把提取到的横竖线合并,得到完整的表格网格
  3. 识别单元格轮廓:从网格掩码中找到每个单元格的轮廓,直接绘制边框

改进后的代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:32:09