要在自家业务里判断 HyOCR-1.5 哪类图像能用,比较稳妥的做法不是先跑一份混合样本看总分,而是先把验收集按图像来源拆开:印刷体票据、手机翻拍、手写各建一套。先在印刷体这一类上把调用链路、输出字段和字段取值跑通,再拿手写和翻拍类单独看失败模式。混在一起算分,通常会出现“印刷体拉高平均分、手写素材其实完全不可用”的情况,验收结论也就没法落到具体场景。
判断方向:HyOCR-1.5 的可用性要按图像来源分开验证。印刷体票据、手机翻拍、手写三类各自建目录,先只跑印刷体确认基础链路和输出字段,再跑手写与翻拍并单独记录漏检、错字、错行。验收看每类的观察项和可接受边界,而不是一个平均分。边界在于:单类样本偏少、或没有人工复核口径时,这套结论只适合用来决定“先上哪类、哪类先不上”,不宜当成整体识别能力的定论。
按图像来源分成印刷体票据、手机翻拍、手写三类目录
目录先按来源分桶,再做二次标注。这样跑评测时可以用一个参数只跑某一类,也能在结果里按来源聚合,不会因为目录平铺而丢分类信息。
eval_sets/
printed_invoice/ # 扫描件、PDF 导出图、电子发票截图
images/
{yyyy}-{source}-{doctype}-{seq}.jpg
manifest.csv
out/
phone_photo/ # 手机翻拍、桌面平铺拍照
images/
manifest.csv
out/
handwriting/ # 手写单据、手写备注区
images/
manifest.csv
out/
_rejected/ # 跑不通、字段缺失、无法判读的样本
文件命名建议带上来源和单据类型,例如 2025-shopA-invoice-0001.jpg、2025-mobileA-receipt-0007.jpg,序号只用本地递增,不要用哈希值,方便人工在结果里定位原图。manifest.csv 至少包含 id、file、doctype、expected_fields 四列,expected_fields 写期望能取到的字段名,不写期望值——期望值先放人工标注表,避免标注和样本一起改坏。
入选标准按来源分别定:印刷体票据选清晰、无强反光、整页完整的图;手机翻拍选带倾斜、阴影、轻微畸变的真实拍摄图,而不是同角度补拍的“干净版”;手写类选有实际录入需求的那几栏(金额、日期、签字区),签字区如果业务上本来就不要求识别,就不要放进验收集充数。建议每类先攒到能覆盖常见单据类型为止,样本不够就先补,不要用一类样本去代表另一类。
先只跑印刷体这一类,确认基础链路与输出格式
印刷体票这一类的目的是排流程问题,不是评效果。先确认图片能传进去、结果能取回来、字段名和业务侧能对上,再去碰手写。
# run_eval.py `--set` printed_invoice `--limit` 5
import csv, json, pathlib
def call_ocr(image_path):
# 替换为 HyOCR-1.5 的实际调用方式:本地服务、命令行封装或 SDK
raise NotImplementedError
def run(set_dir, limit=None):
rows = list(csv.DictReader(open(set_dir / 'manifest.csv', encoding='utf-8')))
(set_dir / 'out').mkdir(exist_ok=True)
for row in (rows[:limit] if limit else rows):
img = set_dir / 'images' / row['file']
try:
out = call_ocr(str(img))
except Exception as e:
print('ERR', row['file'], repr(e))
continue
json.dump(out, open(set_dir / 'out' / (row['id'] + '.json'), 'w',
encoding='utf-8'), ensure_ascii=False, indent=2)
输出字段检查清单,跑完前 5 张就逐项对照,缺什么先补在适配层里,别留在评测脚本里补:
- 有没有整页纯文本字段,以及分块/分行结果是否带 bbox
- bbox 是像素坐标还是归一化坐标,是否与图片尺寸对应
- 有没有行级或字段级置信度,没有的话验收就只能靠人工比对
- 空结果用什么表示:空字符串、null 还是空列表,适配层要统一
- 多页单据是否分页返回,页序是否稳定
- 编码统一 UTF-8,金额里的逗号、小数点在返回里是否被改写
异常样本的收集方式:报错、超时、返回空、字段缺失这四种,直接把原图和返回内容一起复制到 _rejected/,文件名加后缀 _err 或 _empty,并在一行日志里记下时间、样本 id 和异常类型。这批样本不要删,后面判断回退条件时用得上。
再跑手写与翻拍类,单独记录失败模式
手写和翻拍的失败往往不是“认错字”,而是“根本没框到”。如果记录表只写“识别不准”,后面就没法判断该改预处理、改字段规则还是干脆不做。所以失败模式至少要分开:漏检(该出现的行或字段没有出现)、错字(框到了但内容错)、错行(内容对但串到相邻行或相邻字段)。
| id | 类别 | 模式 | 位置 | 意外输出 | 期望 | 是否阻断上线 |
|---|---|---|---|---|---|---|
| hw-0003 | 手写 | 漏检 | 金额栏 | 空 | 非空金额 | 是 |
| pp-0011 | 翻拍 | 错行 | 第 2 行 | 商品名带出单价 | 仅商品名 | 否 |
典型样本留存建议原图、返回 json、人工标注三方放同一个目录 cases/{set}/{id}/,并在记录表里写清楚这张图属于哪种失败。翻拍类还要额外记一条拍摄条件(倾斜、阴影、反光),否则复现时没法还原现场。手写类记录笔迹特征,例如连笔、数字 1 和 7 写法、是否有涂改。
给每类图像定验收观察项,而不是一个总分
三类图像的观察项不一样,硬凑一个总分意义不大。印刷体票据看关键字段能不能直接取用、表格行有没有错位、印章覆盖区是否影响金额;手机翻拍看整页可读性和边缘裁切,重点字段是否落在被裁掉的区域;手写类先看是否只要求关键几栏,连笔字段直接标成“需人工”,不要算进必须通过的观察项。
可接受边界建议写成规则而不是比例,例如:金额允许缺千分位和货币符号,不允许小数点错位;日期允许分隔符不同,不允许日月互换;单据号允许前缀缺失,不允许位数缺失。这样验收时是一条条对,不依赖某次抽样算出的数字。
需要人工复核的情形也提前写下来:置信度偏低、字段为空、同一字段出现多个候选、印章或涂改覆盖、跨页续行。这几类在灰度期一律转人工,不进自动入库,避免把边界情况当成识别正确。
把两类结论合并成上线范围说明
最后交付的不是“HyOCR-1.5 能用”这句话,而是一段范围说明,写清楚先上哪类、哪些先不上。模板可以这样写:本期仅对印刷体票据、且来源为扫描或清晰拍照的单据启用自动识别,字段限于金额、日期、单据号;手机翻拍与手写类暂不启用,仍走人工录入,待样本补齐并单独验收后再评估。灰度期按来源分开抽检,出现某类样本连续报错、空输出集中出现、或金额类字段人工改单明显集中,即回退到人工录入并保留原图和返回结果用于排查。
监控项按类看,不要合并:每类每日的空结果数、调用异常数、人工改单数、字段缺失数。这几项用日志和人工改单记录就能统计,不需要额外造指标。回退条件在灰度前写好并让业务方确认,避免出现问题时临时争论阈值。