登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

OCR 识别表格时如何保留行列关系

来源:17golang原创

时间:2026-09-10 16:57:04 147浏览 收藏

OCR 识别表格时,真正容易丢失的不是文字,而是文字所在的格子。只拿到按阅读顺序排列的字符串,后面再怎么拼接也很难恢复列关系。可靠做法是让每个识别片段同时携带文本、坐标框和置信度,再根据几何位置重建行列。

官方文档:https://huggingface.co/docs/transformers/en/model_doc/table-transformer

要点速览
  • OCR 输出至少保留 textboxscore 三类信息。
  • 先按文本框垂直中心聚成行,再按左边界排序,不能依赖模型返回顺序。
  • 合并单元格、无边框表格和低置信度片段必须单独标记,交给规则或人工复核。

先把 OCR 结果从文字升级为带坐标的单元格候选

一个表格片段可以抽象成 (text, x1, y1, x2, y2, score)。坐标最好统一为原图像素坐标,避免裁剪、缩放后混用不同参考系。若使用 Table Transformer 一类模型,还应在后处理阶段把归一化框还原到原图尺寸;官方处理器提供了取得未归一化 bounding box 的方法。

不要先把识别结果拼成长字符串。先过滤明显无效的空文本,保留低置信度项并加上标记,因为它可能正好是表头、合计或跨列说明。

from dataclasses import dataclass

@dataclass
class Cell:
    # box 使用原图像素坐标:左、上、右、下
    text: str
    box: tuple[int, int, int, int]
    score: float

def center(box: tuple[int, int, int, int]) -> tuple[float, float]:
    # 用中心点参与聚类,降低字框高度不同带来的偏差
    x1, y1, x2, y2 = box
    return (x1 + x2) / 2, (y1 + y2) / 2

用坐标聚类恢复行列,而不是按识别顺序拼接

恢复结构可以分两层:先按 y 方向判断哪些框属于同一行,再在每一行内按 x1 升序排列。行判断不宜写死一个像素阈值,更稳妥的做法是用当前文字高度估计容差,例如两个框的垂直中心差小于较小框高度的 0.5~0.7 倍时归为同一行。

行聚好后,再从左到右排序。若同一行里有两个框水平重叠,先合并文本或保留为候选冲突,不要悄悄覆盖。这样可以看出“2024”“年报”被拆开,还是两个本来就属于不同列的值。

OCR 表格识别中由文本框、行聚类和列排序组成的静态结构关系图
图1:文本片段先进入坐标候选层,再按垂直中心聚成行,最后由列排序恢复二维阅读顺序。
def same_row(a: Cell, b: Cell) -> bool:
    # 使用框高估算容差,适应扫描件中字号略有变化的情况
    _, ay = center(a.box)
    _, by = center(b.box)
    ah = a.box[3] - a.box[1]
    bh = b.box[3] - b.box[1]
    tolerance = min(ah, bh) * 0.6
    return abs(ay - by)  list[Cell]:
    # x1 是列顺序的主要依据,y 只用于稳定排序
    return sorted(row, key=lambda item: (item.box[0], item.box[1]))

合并单元格和错位文本要单独处理

普通行列排序只能解决“看起来像网格”的表格。遇到合并单元格时,应先估计列边界,再判断文本框覆盖了几列。如果一个框横向覆盖两个以上列中心,输出中不要复制到每一列,而是保存 colspan,或将它放入带跨度的单元格对象。

无边框表格还要留意两种误判:一是相邻列文字距离很小,被误合并;二是换行文本的第二行被误认为新行。可以用同列重叠、行高连续性和相邻空白共同决策。低置信度文本不要直接删除,给它附上 needs_review 标记,比生成一个看似完整但列错位的 CSV 更安全。

OCR 表格识别中列边界、跨列单元格和二维输出之间关系的静态技术框图
图2:列边界负责判断文本覆盖范围,跨列候选进入单元格重建层,最后输出带跨度和复核标记的二维结构。

输出结构化表格前做三项检查

第一,检查每一行的列数是否突然变化;如果变化只发生在表头或合计行,可能是合并单元格,不能简单补空值。第二,检查同一列的 x 范围是否稳定,漂移过大通常意味着扫描倾斜、裁剪不一致或行聚类阈值过宽。第三,抽样查看低置信度和跨度最大的片段,并把原始坐标一并保存,方便回溯。

最终输出可以是二维数组,也可以是更适合审计的 JSON:

{
  "rows": [
    [{"text": "项目", "colspan": 1}, {"text": "金额", "colspan": 1}],
    [{"text": "服务费", "colspan": 2, "needs_review": false}]
  ]
}

这里的关键不是把每张图片都强行变成规则矩阵,而是保留“文字来自哪个位置、覆盖哪些列、是否需要复核”这三类证据。字符识别正确但位置错误,业务上仍然等于识别失败。

常见问题

为什么 OCR 文本都对,导出的 Excel 仍然错列?

因为文本准确率没有衡量坐标关系。导出前必须保留 bounding box,并重新做行聚类与列排序。

行聚类阈值应该固定多少?

不建议固定像素值。用文本框高度或页面缩放比例计算相对阈值,再用少量样本复核。

合并单元格要不要复制到每一列?

不要默认复制。优先保存 colspan 或覆盖列范围,后续由业务规则决定展示方式。

总结来说,保留表格行列关系的核心是“识别文字”和“重建布局”分离:OCR 负责提供文本与位置,几何规则负责恢复行列,异常项负责进入复核。只要坐标证据没有丢,后续换模型、换导出格式或增加合并单元格策略都还有调整空间。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>