ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

模糊票据OCR识别优化:从图像预处理到模型微调全指南

模糊票据OCR识别优化:从图像预处理到模型微调全指南

做票据识别的人,多半是被“小票照片太糊”劝退过。用户拿手机随手一拍,超市小票那种热敏纸,字迹浅、底纹花、还带着褶皱反光,拍出来的图别说机器了,人眼认全都有点费劲。我最初做这类项目时,拿一批真实用户拍的小票图跑识别,准确率只有不到六成,后来把处理流程逐步调优,才稳定到90%以上。这篇文章不讲虚的,就围绕“超市小票模糊如何提高识别准确率”这个核心问题,把图像预处理、OCR引擎参数、结果后处理、数据增强这几条线完整过一遍,把我实测过有效和踩过坑的方案都写出来。适合正在做票据识别、财务凭证自动录入、移动端扫票工具或者想优化自建OCR管线的朋友参考,方案不局限于超市小票,外卖单、快递面单这些热敏打印票据也能复用。

1. 小票识别难在哪:模糊只是表象

1.1 热敏纸的物理限制是先天短板

超市小票几乎都是热敏打印,热敏涂层的发色对比度天然不如激光打印黑度,加上打印头用久了磨损、打印浓度设置得低,很多票打出来就是“灰字”。更麻烦的是热敏纸怕光怕热,放久了字迹变淡甚至整张泛黄,用户再叠加环境光干扰,图像对比度会进一步变差。所以做预处理时不能拿普通文档的标准去套,要专门针对“低对比度灰字”场景设计流程。

还有一个容易被忽略的问题:小票排版过于密集。购物明细行的字号通常在5号左右,纸张宽度有限,一行里塞下商品名、数量、单价、金额好几段信息,字符间距和行距都很小。模糊一旦叠加,字符之间直接粘连成片,检测模型很难把每个文字区域切干净。加上票面经常有商家logo、促销活动框、二维码这些高对比度元素,它们会抢走图像处理的注意力,让本来就淡的字迹更难被增强出来。

1.2 模糊不只有一种,识别率瓶颈也不同

模糊大致分三类:运动模糊、失焦模糊、低分辨率模糊,平时还会叠加噪声和光照不均。处理之前先判断属于哪种,才能选对方案。

  • 运动模糊:手持拍摄或扫码枪扫过时产生,字符边缘沿运动方向拖影,严重时数字“0”和“6”粘在一起。
  • 失焦模糊:手机对焦没锁上,尤其是小票离镜头太近,焦平面没落在字符上,表现为整体发虚但还算均匀。
  • 低分辨率/压缩模糊:照片经过聊天软件传图压缩、视频抽帧等,字符分辨率不足,边缘信息丢失。

三类模糊在预处理里的处理方式不同。运动模糊适合方向性锐化或去卷积,失焦模糊适合反卷积,低分辨率模糊要考虑超分或多尺度重建方案。不要指望一个“通用锐化”通吃所有场景,至少要按项目里最常见的两类模糊分两条管线来跑。

1.3 识别管线里最怕模糊的环节

OCR管线一般是“图像预处理 → 文字检测 → 文本识别 → 结构化后处理”。模糊最影响的是文字检测。很多检测模型对边缘响应敏感,模糊后文本框定位漂移,漏检、错误合并随之而来。后端的识别模型对模糊也不友好,常见的长短时记忆网络加注意力机制在训练数据里见过的模糊样本少,推理时对模糊字符的特征激活不稳定,特征向量会偏向那些形状相近的常见字符。

所以处理这类图片,第一步不是急着换更大规模的模型,而是尽量在预处理阶段把模糊的影响降下来。预处理做得够好,可以用中等规模的OCR模型拿到接近大模型的精度,推理成本低一大截。

2. 图像预处理:把“看不清”变成“看得清”

预处理不能简单套一套“灰度+二值化”。模糊小票的预处理应该是分段决策的,每段都要针对热敏纸和拍摄环境的特性来选参数。

2.1 灰度化与色彩通道选择

直接拿整张彩色图转灰度,经常把本来就淡的灰字和暖色底纹混在一起。我的做法是:先拆 RGB 三通道,对热敏纸小票通常取红色通道或绿色通道效果更好。因为热敏纸的底色偏暖、字迹偏蓝紫,红色通道能拉大字迹和底色的反差。如果原图是用 BGR 顺序读进来的,就取通道索引 2(红色)或通道索引 1(绿色)。实际操作时,我会写个小脚本把三个通道分别输出成灰度图,先肉眼挑反差最大的通道,再固定成管线的默认选项,实测下来红通道在大多数热敏小票上胜出。

不过要注意,某些小票用了不同品牌的热敏纸,发色偏色不太一样,如果项目要上线到全国不同区域,最好在采集阶段统计一批样本的通道表现,不要拍脑袋定死。

2.2 光照不均处理与降噪

小票照片最常见的干扰之一是光照不均,中间亮、四周暗或者局部反光,直接做阈值分割会把阴影区域切成大片黑块。我先做“背景估计”:用一个很大的方框做均值滤波估计背景亮度,然后用原图除以背景,相当于做了局部光照归一化。这样做比直接直方图均衡化更稳,不会把阴影错误放大,也不会让反光区域的亮字过曝。

降噪方面,热敏纸小票的“雪花点”很常见,用 3×3 或者 5×5 的中值滤波可以去掉椒盐噪声;高斯模糊一般只在超分或锐化前用来抑制噪声,核心降噪还是中值滤波优先。注意中值滤波半径不要太大,超过 5 会把字符边缘也磨掉,字迹更糊,遇到严重噪点宁可多叠加一次小半径滤波,也不要一次性开大核。

2.3 二值化参数的选择

二值化要按小票场景来选。全局大津法在均匀光线下还行,但模糊小票的灰度分布往往是多峰的,全局阈值会把部分字迹切成碎片。我推荐自适应二值化,把局部窗口尺寸设置在字符笔画宽度的 3 到 5 倍,然后根据背景亮度调节偏移量 C 值。一个参考配置:图片宽度 2000 像素左右、字符高度 30 像素左右时,窗口尺寸取 61 到 101,C 取 5 到 15。调整原则很简单:出现笔画断裂就减小 C、加大窗口;出现背景噪点就加大 C、减小窗口。

还有一个细节:自适应二值化之前,建议先做一次轻微的灰度拉伸,把灰度范围映射到 0 到 255 的完整区间,否则阈值参数在不同批次的照片之间要频繁重调。这一步很小,但对提高参数通用性很有帮助。

2.4 锐化与边缘增强的具体配方

锐化我用的是USM,可控性强。原理可以理解成“原图加上高斯模糊后的差值乘以增益”,代码层面通常用两次高斯模糊加权重合成来实现。参数上,高斯半径设为 1 到 2,增益设为 0.6 到 1.2。增益过大会在字符边缘产生一圈白边,也就是常说的光晕效应,反而干扰识别,所以宁愿保守一点。运动模糊的图像,我会先沿运动方向做一次方向性锐化,比如用 3×3 的核在水平或垂直方向做差分增强,再做USM,效果比单纯USM好很多。

这里有个容易踩的坑:不要对整张图无差别锐化。小票背景里如果有密集的底纹或二维码,锐化会让这些干扰纹理变得更明显,后续检测模型容易把底纹误检成文字。使用掩膜限定锐化范围,只增强文字所在的行区域,能减少很多误检。

2.5 倾斜校正与透视变换

小票拍摄时的倾斜角度经常超过10度,识别模型虽然有一定旋转鲁棒性,但精度会掉不少。我习惯做两段式倾角校正:先用图像矩或边缘投影粗估计旋转角度,做一次旋转;再用文本行投影法细校准。如果场景里能检测到清晰的票面边缘,用四边形检测加透视变换效果最好,但要注意别把小票的圆角、折痕或远处货架上的价签误当成边缘。

透视变换后的图像尺寸会变化,缩放时按目标字符高度来,而不是按固定宽高。目标字符高度放在 32 到 48 像素区间比较合理。太小了识别模型看不清,太大了容易引入锯齿和额外计算量。把字符高度当成一个独立参数,分别控制每个区域的缩放,比统一缩放到固定宽度好用。

2.6 超分辨率与去模糊(进阶)

传统预处理做到极致之后,模糊导致的准确率上限仍然存在。想继续往上提,要么换更强的识别模型,要么在输入前做图像复原。我在一个要求比较高的场景里试过轻量超分,做法是训练一个小型生成对抗网络,专门把小票图像从0.5倍放大到1倍,同时修掉一部分模糊,效果确实能提升5到8个百分点的准确率,代价是每张图多花几十毫秒延迟。对于批量离线处理来说可以接受,移动端要做量化压缩才能跑得动。

去模糊还有一种传统方法叫理查德森-露西反卷积,对失焦模糊效果不错,但对运动模糊和噪声敏感,参数调起来不稳定。我的建议是:优先用深度学习超分方案,传统反卷积只作为兜底选项。在真实项目里,超分加轻量识别模型的组合,往往比直接上重型识别模型性价比更高。

2.7 预处理管线参考顺序

把上面这些串成一条可落地的管线:

通道选择 → 光照归一化 → 中值降噪 → 倾斜粗校正 → 自适应二值化 → USM锐化 → 倾斜细校准 → 按目标字符高度缩放

这个顺序不是死板的。比如训练深度学习检测模型时,二值化和锐化不一定要做,因为卷积网络能自己从多通道里学习特征,提前把图像抹成黑白反而会丢信息。更合理的做法是分成两条路:一路增强图送传统OCR或传统图像处理流程,一路原图送深度学习检测识别模型。我自己测试过,二值化后的图送深度学习模型,有些场景准确率反而下降,所以管线设计一定要跟后续模型匹配。

3. OCR引擎选型与参数调优

预处理只能解决一部分问题,OCR引擎本身的选择和参数设置同样影响准确率上限。

3.1 引擎选型参考

我用过的几种方案可以做个对比:

方案模糊场景表现部署成本适用场景
经典开源OCR引擎(老牌C++项目)对模糊字符较弱,尤其数字粘连经常错低,离线可用清晰印刷体、限制字符集场景
深度学习端到端框架(检测模型+序列识别模型)对模糊鲁棒性明显更好中,需要GPU训练,CPU可推理自然场景文字、票据类通用识别
商业云OCR服务准确率上限最高,因为训练数据海量低,但有网络开销和调用费用对成本不敏感、数据合规允许的项目

自建服务我优先推荐深度学习端到端框架,因为它能把预处理、检测、识别、后处理全部串在一个可控管道里,方便针对小票业务反复调优。经典开源引擎虽然轻量,但遇到模糊小票的直接识别率通常不到八成,很难作为主路径。

3.2 识别模式与字典白名单

OCR引擎一般支持按场景设定字符白名单。小票识别的目标字段很集中:中文店名、日期、时间、品名、数字、金额、小数点、加减乘除符号。在白名单里限定字符集,识别引擎的候选空间大幅缩小,模糊字符的误识别率会明显下降。比如“合计”后面那串数字,白名单只保留 0 到 9 和小数点,数字 0 跟字母 O 混淆的问题就好解决很多。

白名单设置不是越窄越好。品名区域需要中文、字母、数字混排,如果限定太死反而漏字。建议按字段区域分别设置白名单,而不是整张图一张配置。比如金额字段用纯数字加小数点,日期字段用数字、横杠和年月日关键字,店名和品名区域保留全量字符集。这样既能利用限制提升准确率,又不会伤到正常字符。

3.3 版面分析与区域定位

超市小票虽然每家排版不同,但结构有共性:顶部店名、地址、电话,中部商品明细列表,底部合计、付款方式、二维码。先做版面结构分析,把图像分成几大区域,每个区域单独走OCR,再用模板匹配和正则表达式做结构化提取,准确率提升比整图识别高出一截。

我的做法是:先用检测模型拿到所有文本框坐标,然后按纵坐标聚类成行,再按横坐标聚类成列,自动生成区域边框。找不到明显边界时,利用“合计”“实收”这类关键字位置做锚点切分。这个方法在真实样本上比固定像素坐标切分鲁棒多了,因为不同超市的小票只要结构一致,锚点切分就能自动适配宽度变化。

3.4 输入尺寸与多尺度策略

同一张图,OCR之前缩放的比例很关键。字符高度小于20像素时,识别模型很容易把相近字符搞混;字符高度超过64像素,收益基本见顶,只会增加耗时。所以统一缩放时尽量把字符高度控制在35到40像素。

检测模型对大图经常漏掉小字,我习惯做多尺度滑动窗策略:原尺寸检测一遍,放大一倍再检测一遍,把两轮检测框合并。模糊小票的小字符框能多召回不少,合并时要做非极大值抑制去重和框位置融合。这个策略对算力的消耗可控,多出来的耗时主要在放大图的检测上,可以用降低放大图的输入分辨率来平衡。

3.5 多帧融合与重复识别

如果场景是视频流或者扫码枪连拍,利用多帧融合是性价比最高的手段。同一个商品行在连续几帧里都会被识别,把结果按行内容对齐,做置信度加权投票。单帧里“1.99”被认成“1.66”,多帧取置信度最高的结果,准确率提升非常明显。对齐时按文本相似度聚类,不用每帧都重新检测,只对检测框发生明显变化的帧重新跑整条管线。

多帧融合还有一个好处:能顺带处理运动模糊。因为用户拍照时手抖造成的模糊是随机方向的,几帧里总有一帧相对清楚,投票机制天然会选择那一帧的结果。我建议在移动端扫票工具里默认开启连拍模式,对整体体验提升很大。

4. 数据增强与模型微调:从源头提升模糊鲁棒性

预处理和推理参数调到一定程度后,还想继续提升准确率,就得回到数据层面了。

4.1 用合成模糊样本增强训练集

开源预训练模型的训练数据里,模糊小票可能不多,导致模型对“模糊+低对比度”的域不太适应。常见的做法是收集一批清晰小票图像,然后用程序生成各类模糊样本:

  • 高斯模糊:核大小随机取 1 到 5,模拟失焦
  • 运动模糊:给卷积核指定方向和长度,长度随机取 3 到 15,模拟手抖
  • 高斯噪声和椒盐噪声:强度随机,模拟热敏纸老化
  • 缩放模糊:先缩小再放大,模拟低分辨率
  • JPEG压缩伪影:质量参数随机取 30 到 80,模拟聊天软件传图
  • 光照遮挡:加渐变暗角或局部亮斑,模拟拍摄环境

把这几种模糊按随机概率组合,一张清晰图能生成几百个模糊版本。训练时不需要刻意控制顺序,随机选一种或几种叠加就好。实测下来,运动模糊和高斯模糊的组合对准确率提升贡献最大。

4.2 真实模糊样本的标注细节

合成数据再好,也替代不了真实样本的分布。真实模糊样本里的褶皱、反光、褪色,合成数据很难完全模拟。我建议训练集里至少保证 30% 是真实用户随手拍的小票图。标注时几个细节特别重要:

  • 文本检测框要贴合实际文字区域,不要跟着模糊的打印条纹走
  • 同一字段在不同图上的标注内容必须一致,不要出现一张图标成“1.99”、另一张图标成“1.9”的情况
  • 模糊到肉眼都难以辨认的样本宁可放弃,也不要硬标,否则会教坏模型
  • 标注完做一轮“预识别+人工修正”:先让现有模型预测一遍,再人工修正错标,能有效节省一半标注时间

还要提一点:不要把所有模糊照片混在一起标注。失焦和运动模糊产生的原因不同,如果真想精细化调模型,最好在数据平台里给样本打上“模糊类型”标签,方便后续分场景评估和调参。

4.3 轻量微调路线

不是所有项目都需要从零训练模型。我常用的路线是:加载开源预训练权重,冻结主干网络,只微调识别分支的浅层模块,用合成数据加真实数据混合训练几十轮。这种方案算力开销不大,单张消费级显卡就能跑完。微调阶段的几个经验:

  • 学习率要调到预训练建议值的十分之一到五分之一,避免灾难性遗忘
  • 批量大小不要太小,否则批量归一化的统计量不稳定,模糊样本多时尤其明显
  • 模糊样本和清晰样本按 1:1 混在一起送训练,不要让模型被模糊样本带偏,否则清晰图识别率反而下降

核心工程实现上就一段冻结参数的逻辑:

# 伪代码:冻结主干网络,只训练识别头 for name, param in model.named_parameters(): if 'backbone' in name or 'neck' in name: param.requires_grad = False else: param.requires_grad = True

训练完成后,用小批量验证集做回归测试,防止某个类别的准确率被压下去。我遇到过微调后整体精度涨了,但“金额合计”关键字段反而变差的情况,最后发现是数据增强过度,把金额数字的竖线拉弯了。所以增强组合里要保留一部分不经过几何形变的样本。

5. 实际排查记录:模糊小票识别准确率从六成到九成的过程

最后分享一段实际的调优过程。某个模拟项目“超市小票识别Demo”初始用默认参数跑真实模糊样本,准确率约61%。我把问题拆成五步,一步步调,最后稳定到94%左右。

5.1 定位瓶颈在检测还是识别

先准备200张测试图,分别跑“检测单独评估”和“识别单独评估”。检测框的准确率和召回率约78%,识别准确率约82%,但整体准确率只有61%,说明检测漏框和识别错误两个环节都在拖后腿。于是先做图像预处理改造,再调引擎参数。

这里想强调:一定要先拆指标再动手。很多人上来就加大模型,结果检测一半的框都是错的,识别模型再强也没用。用检测框的召回率跟整体准确率对比,能快速判断问题主要出在哪个环节。

5.2 预处理改造的效果

把“灰度+全局二值化”换成“红通道+光照归一化+自适应二值化+USM”之后,整体准确率到了74%。提升主要来自检测的召回率上去了,说明检测模型对输入图像质量很敏感。不过这里有个坑:二值化后的图送深度学习检测模型,反而丢失纹理信息,所以我把管线拆成两路:一路原图送检测,一路增强图送识别。这个改动也值得大家在自己项目里测一下。

光照归一化和自适应二值化这两个环节,对检测的改善最明显。因为检测模型在彩色原图上学习过大量自然图像特征,而光照均匀、对比度合适的增强图,更容易让检测模型聚焦到文字主体上。

5.3 区域白名单与后处理

给金额、日期区域加白名单后,准确率到了82%。后处理再把常见的商品明细行合并在同一行,套正则校验,比如“总计”字段必须是数字加两位小数,不匹配就重试或标记人工。这部分继续贡献了几个点。小票字段结构化之后,就算有个别字符识别错,也能通过字段间的约束关系纠回来。

举个例子,金额区域识别结果里的“8”和“3”经常混,但白名单只允许数字和小数点,再配合金额尾数必须是两位小数这条规则,很多候选错误会被自动过滤掉。即使过滤不了,也会被打上“低置信度”标记,进入人工复核队列,而不是直接落库。

5.4 多尺度检测与多帧融合

在需要实时识别的场景上加多尺度检测,同时利用连续几帧投票,检测的准确率和召回率提升了6%,整体准确率到88%。这一步几乎不用改模型,纯工程手段,稳定可靠。多帧投票对“商品明细行”这种反复出现的内容尤其有效,因为同一行文字在几帧里识别结果基本一致,只要有一帧清楚,就能把整行的置信度顶上去。

5.5 数据增强微调模型

最后用合成模糊加真实模糊样本微调识别模型,允许单张延时增加30毫秒,准确率终于摸到94%。再往上提需要收集更贴近目标场景的样本,成本收益已经不成比例,我就停在了这个水平。整个过程验证了一个结论:模糊小票识别提升不是靠某一个“神技”,而是预处理、引擎参数、后处理和模型微调四层一起加持的结果。

阶段准确率主要措施
初始状态61%默认参数直接识别
预处理改造74%红通道、光照归一化、自适应二值化、USM
白名单加后处理82%字段区域白名单、正则校验
多尺度加多帧88%多尺度检测、多帧投票
数据微调94%合成模糊加真实样本微调

5.6 踩坑速查表

最后整理几个踩过的坑,方便对照排查:

现象原因解决思路
锐化后字符边缘出现白边USM增益过大把增益降到1.0以下,观察边缘是否干净
二值化后出现大面积黑影光照不均没先处理先做背景估计除法,再做自适应二值化
倾斜校正把图转歪检测到的边缘来自远处货架或价签限制边缘线长度和位置,只保留票面附近边缘
商品名里“0”和“O”混淆字符集过宽按区域白名单约束,不要只靠识别模型
检测框漏掉小字商品行单尺度检测对小目标不敏感用多尺度检测,保留小尺寸候选框
合成模糊样本微调后,清晰图识别率下降增强过度导致域偏移清晰与模糊样本混合训练,比例控制在1:1左右

写到这里,核心的几块都过完了。最后说点个人感受:模糊小票识别是个典型的“病根在图像、表症在模型”的问题,很多人一上来就换更大的模型,其实先把预处理、引擎参数、后处理这几层打磨好,成本最低、见效最快。数据微调是能继续提升精度的手段,但要注意合成数据和真实样本的平衡,别让自己走进“训练集完美、测试集翻车”的死胡同。如果你手头正好有类似的票证识别项目,不妨按这个思路重新走一遍预处理管线,应该能少走不少弯路。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进