OvisOCR2 把扫描件里的表格和公式一起抽出来,先确认哪些版面它接不住

文章导读
OvisOCR2 在扫描件里把表格和公式一起抽出来,能不能直接用,主要不取决于它识不认字,而取决于版面结构能否按块保留位置。比较稳妥的路径是先挑几页最接近真实业务的样张,把原图、输出块、坐标三者叠在一起看一遍;对不上的块集中在哪一类版面,就把那类版面划到人工重录或换流程的一侧,剩下的再谈批量和入库。
📋 目录
  1. Ⅰ 挑三类典型扫描页做样张
  2. Ⅱ 把输出按块对照回原图位置
  3. Ⅲ 确认表格与公式的还原边界
  4. Ⅳ 写清什么情况转人工或换流程
A A

OvisOCR2 在扫描件里把表格和公式一起抽出来,能不能直接用,主要不取决于它识不认字,而取决于版面结构能否按块保留位置。比较稳妥的路径是先挑几页最接近真实业务的样张,把原图、输出块、坐标三者叠在一起看一遍;对不上的块集中在哪一类版面,就把那类版面划到人工重录或换流程的一侧,剩下的再谈批量和入库。

判断 OvisOCR2 能否用于扫描件数字化的关键在于版面类型和位置信息,而不在于识别率。建议按纯文字页、含表格页、含公式页各取一到两页做样张基线,逐块核对文本块、单元格、公式区能否定位回原图坐标,并记录合并单元格、跨页表格、行内公式的实际输出形态。坐标对不上或结构被压平的页面不直接入库,只有样张上稳定定位、结构可复原的版面才进入批量与抽检流程。

挑三类典型扫描页做样张

样张的价值在于可比对:同一批参数下跑出来的输出,要能和原图逐页对应。选页时避开特例,优先选业务里出现频率最高的版式;每页记下页数、来源、扫描分辨率和扫描方式(灰度、彩色、是否倾斜),后续换参数时才有对照基准。分辨率建议保持与实际入库文件一致,不要用重新导出的高清版做样张,否则线上效果不可比。

样张编号版面类型页数来源扫描分辨率备注
S1纯文字页1合同正文300dpi 灰度无表格线
S2含表格页2报价单300dpi 彩色含合并单元格表头
S3含公式页1技术说明300dpi 灰度行内公式与正文混排

样张登记建议用一份简单清单保存下来,和输出文件同目录,方便回查。字段名按你实际的评测脚本改,这里只是可替换的骨架:

{
  'sample_id': 'S2',
  'source': '报价单归档',
  'pages': 2,
  'dpi': 300,
  'scan_mode': 'color',
  'layout': 'table',
  'layout_note': '含跨页表头,表格内无公式'
}

把输出按块对照回原图位置

结构化结果能不能用,很大程度上看每个块是否带位置信息,以及位置是否准。OvisOCR2 的输出字段名在不同部署形态下可能是 bbox、poly 或 points,先原样 dump 一次原始 JSON 看清结构,再决定校验脚本怎么取坐标。核对时分三类块分别看:文本块是否覆盖整段、有没有被切成碎行;表格单元格的行列顺序是否和原图一致;公式区标注的范围是否把上下文字也框了进去。

OvisOCR2 把扫描件里的表格和公式一起抽出来,先确认哪些版面它接不住

下面这段只是把块坐标画回原图的通用骨架,图像库和字段路径按你的环境替换,跑完对着原图肉眼比对即可:

from PIL import Image, ImageDraw
import json

img = Image.open('S2_p1.png').convert('RGB')
draw = ImageDraw.Draw(img)
blocks = json.load(open('S2_p1.json'))['blocks']  # 字段路径按实际输出替换

for b in blocks:
    x0, y0, x1, y1 = b['bbox']
    draw.rectangle([x0, y0, x1, y1], outline=(255, 0, 0), width=2)

img.save('S2_p1_overlay.png')

对照结果按块记录,不要只写“表格识别有问题”这种结论,要指到具体单元格或行:

OvisOCR2 把扫描件里的表格和公式一起抽出来,先确认哪些版面它接不住
块编号块类型原图位置输出形态是否对齐问题描述
B07文本块第1页上部整段是—
T02表格单元格第2页表头独立单元格否合并表头被拆成两列
F01公式区第1页中部独立块部分框入左侧引导文字

确认表格与公式的还原边界

同一个模型对简单版面和复杂版面的还原能力差别明显,判断边界要落到具体结构上。建议在样张输出里专门找三类情况,看它们最后变成了什么:

  • 合并单元格:常见输出是拆成独立的行列,rowspan、colspan 之类的合并信息丢失,或者合并区文本被复制到多个单元格。核对时看表头是否出现重复文字、行列数是否比原图多。
  • 跨页表格:常见输出是被切成两张独立的表,第二段没有表头,也缺少“续表”标记。核对时看两张表是否有共同的表格 ID 或页码字段;没有就得在入库前自己拼。
  • 行内公式:常见输出是被拉成独立的公式块,句子在公式处断成两截,或者公式整体退化成普通字符流。核对时看公式块是否带 inline、display 之类的类型标记,正文句子是否还连续。

这三类结构如果有任何一类在你的样张上出现压平或丢失,就把该类版面标成“需要后处理”,不要默认下游能靠字段名自动还原。表格线缺失、扫描倾斜、印章覆盖单元格的情况会放大这些问题,选样张时建议至少覆盖其中一种。

写清什么情况转人工或换流程

分流规则要能在页级执行,给出可判断的触发条件,而不是让人临场决定。可以按下面的方式定三档,字段名按你的管线替换:

OvisOCR2 把扫描件里的表格和公式一起抽出来,先确认哪些版面它接不住
分流档位适用版面触发条件下游动作
直接入库纯文字页、结构简单的规整表格样张上块坐标对得上,无合并单元格,无跨页,无公式按块写入,保留原图与坐标便于回查
抽检含少数字段合并的表格、公式与正文分离的页面存在合并单元格但行列顺序可对应,或公式以独立块输出且不影响正文按比例抽页人工核对后再入库
人工重录跨页表格、行内公式密集页、印章或水印压字的页面表格被切成多段且缺表头,或公式与正文混在一段字符流里,或关键单元格坐标对不上退回人工录入,OCR 结果只作参考底稿

规则写成配置更容易长期维护,示例如下,条件项对应你在对照表里记录的实际字段:

route_rules:
  - match: {layout: text, coord_check: pass}
    action: direct_load
  - match: {layout: table, merged_cell: true, cross_page: false}
    action: spot_check
  - match: {layout: table, cross_page: true}
    action: manual_retype
  - match: {layout: formula, inline: true}
    action: manual_retype
  - default:
    action: spot_check

落地时先把样张跑通这套路由,再逐步放开新来源的扫描件。每次新增一类版面,重新做一次原图与输出块的对照并更新对照表;人工重录的页面要留存原图与输出,用来判断是参数问题还是版面本身超出能力范围。换模型版本或调整预处理参数后,同一批样张需要重跑一遍,之前“能直接入库”的结论不能直接沿用。