TeleOCR 到底能不能直接吃手机拍的发票 / 模糊和倾斜会影响多少?

文章导读
手机拍的发票交给 TeleOCR,多数情况下值得先直接解析一次,但“能不能直接吃”不取决于照片看起来清不清楚,而取决于解析过程里文字检测框和字段还原这两步各自有没有垮。模糊、倾斜、阴影落在不同步骤上:模糊更容易让文字识别出错字,倾斜先影响检测框的形状,侧向阴影常把两者一起拖下去。可行的做法是拿同一张发票拍出几组受控样本,先跑一遍看哪一步先变差,再决定加不加旋转矫正和去阴影预处理。
📋 目录
  1. A 先备好三组对照样本,把变量控制在同一张发票上
  2. B 用清晰正拍样本跑一遍,记录字段识别基线
  3. C 只改模糊度再跑一遍,看是字段漏识别还是整行丢失
  4. D 换成倾斜十几度的样本,检查框线是否跟着歪
  5. E 加入侧向阴影后复核,划出直接解析可用与必须先预处理的分界
A A

手机拍的发票交给 TeleOCR,多数情况下值得先直接解析一次,但“能不能直接吃”不取决于照片看起来清不清楚,而取决于解析过程里文字检测框和字段还原这两步各自有没有垮。模糊、倾斜、阴影落在不同步骤上:模糊更容易让文字识别出错字,倾斜先影响检测框的形状,侧向阴影常把两者一起拖下去。可行的做法是拿同一张发票拍出几组受控样本,先跑一遍看哪一步先变差,再决定加不加旋转矫正和去阴影预处理。

手机直拍发票可以先进 TeleOCR 直解一次,判断依据不是观感清晰度,而是解析日志里检测框是否成行、行序是否连续、关键数字是否逐位正确。模糊主要压文字识别,倾斜主要压检测框形状,阴影往往同时干扰两者。建议先用同一张发票做清晰、模糊、倾斜、带阴影四组对照,再决定是否补旋转矫正和去阴影;发票代码、发票号码、价税合计任一项漏识或错位,就该走预处理。

先备好三组对照样本,把变量控制在同一张发票上

三组对照的目的,是让每一次只改变一个拍摄因素。如果换成两张不同发票,字段数、版式、印章位置都变了,解析结果变差时你无法判断是拍摄问题还是票据本身的问题。所以底稿只用一张发票,所有样本都由它派生。

文件命名建议把发票编号、拍摄变体、光线条件写进文件名,后面对日志时不用翻相册回忆:

inv01_sharp_straight_even.jpg    # 清晰、正拍、光照均匀,基线
inv01_blur_straight_even.jpg     # 只把清晰度调低,其余不变
inv01_sharp_tilt15_even.jpg      # 只让票据倾斜十几度,其余不变
inv01_sharp_straight_shadow.jpg  # 只加侧向阴影,其余不变

“模糊”这一组不要靠手抖随机拍,抖动方向和幅度不可复现;可以用同一张已经拍好的清晰图,在本地做一次轻度降质导出,保留原图对照。“倾斜十几度”也建议在导出时旋转,而不是靠手举着估角度,这样倾斜角度是已知量。阴影组可以在手机手电或台灯下从侧上方贴着拍,让票据一半偏亮一半偏暗。

三类干扰的观察重点不一样,先列成一张对照表,跑完逐行填:

TeleOCR 到底能不能直接吃手机拍的发票 / 模糊和倾斜会影响多少?
对照组拍摄条件命名后缀要观察的环节
清晰与模糊正拍、光照均匀,仅改变清晰度_sharp / _blur文字识别是否出错字、是否整行丢失
正拍与倾斜清晰度一致,仅旋转十几度_straight / _tilt15检测框是否跟着歪、行序是否错乱
均匀与带阴影正拍、清晰度一致,仅加侧向阴影_even / _shadow字段是否命中、关键数字是否无误

用清晰正拍样本跑一遍,记录字段识别基线

基线样本 inv01_sharp_straight_even.jpg 的解析结果,是后面所有对照的比较对象,所以这一次的记录要尽量完整,不能只记“识别成功”。每次跑之前固定输入条件:长边像素(例如统一压到 1600 或 2000)、文件格式(统一导出为 JPG,避免同一批里混进 HEIC 和 PNG)、是否开启检测框坐标和行序返回。TeleOCR 不同版本或不同部署方式的接口名与参数名会有差异,下面是一个可替换的通用骨架,把 URL、字段名换成你环境实际支持的即可:

POST /ocr/invoice
Content-Type: multipart/form-data

file=@inv01_sharp_straight_even.jpg
return_boxes=true      # 要求返回检测框四点坐标
return_row_index=true  # 要求返回行序或行的归属

关键字段建议只圈定少数几个,字段太多会把注意力摊薄。通常把这几项作为关键字段:发票代码、发票号码、开票日期、金额、税额、价税合计。购买方和销售方名称可以一并记录,但出现个别字形差异时不必立刻判定失败,因为名称里的生僻字和括号全半角本身就不稳定。

记录模板可以用一行 CSV,跑完一组填一行,横向对比最省事:

case_id,long_edge_px,format,latency_ms,box_count,row_order_ok,fields_hit,fields_wrong
inv01_sharp_straight_even,2000,jpg,,,yes,,

这里的 latency_ms 记端到端耗时,从发起请求到拿到完整响应;“快”本身不是目标,它只是用来发现某次解析是否中途退化。检测框数量 box_count 和行序 row_order_ok 是后面两节要用到的关键列,基线这一行必须填上。

只改模糊度再跑一遍,看是字段漏识别还是整行丢失

把 inv01_blur_straight_even.jpg 用同样的参数再跑一次,然后逐字段对差异,不要只对“成功/失败”。对差异的位置比数量更重要:把两次结果的字段值和检测框按位置对齐,看变化集中在哪一块区域。

TeleOCR 到底能不能直接吃手机拍的发票 / 模糊和倾斜会影响多少?

两种失败的成因不同,处理方向也不同:

  • 整行丢失:基线里某一行的检测框在模糊样本里整体消失,box_count 明显减少,且减少的框集中在同一行的横条区域。这通常指向文字检测阶段,也就是模型没把这条文字当成候选文本,后面根本没有识别机会。方向是提高输入分辨率、降低压缩率,或者换更清晰的拍摄,而不是去调字段后处理。
  • 单字段出错:检测框数量和行位置基本没变,但个别字段的值变了,例如数字 0 和 8、1 和 7 互换,或税额少一位。这通常指向文字识别阶段,检测到了但认错了。方向是对关键数字做二次校验(位数、小数位、价税合计的加和关系),而不是加旋转矫正。

一般规律是:轻微模糊先表现为单字段出错,继续加重才出现整行丢失。所以看模糊样本时,重点是它停在哪一级。如果只到单字段出错,可以靠后处理校验兜住;如果已经整行丢失,说明这条路的输入质量不够,应该回到拍摄或预处理环节。

换成倾斜十几度的样本,检查框线是否跟着歪

跑 inv01_sharp_tilt15_even.jpg,这一次重点不是字段值,而是检测框输出本身。若接口返回了四点坐标,就看每一个框的四个点:正常正拍时上下边基本水平,四点的纵坐标接近;倾斜样本里如果四点整体跟着票据一起转,上下边仍然平行,框的形状和票据边缘一致,说明检测阶段把倾斜吃下来了,倾斜只影响后续的透视还原。

如果返回的是可视化图片,直接看框是否贴合文字行、是否有一行文字被斜切成两段、相邻两行的框是否互相吃掉。判断依据可以归成两条:

TeleOCR 到底能不能直接吃手机拍的发票 / 模糊和倾斜会影响多少?
  1. 框是否退化成一个包住整片区域的水平大框。若是,检测阶段没跟上倾斜,相邻列可能被并进同一行,行序会直接错。
  2. 框虽然是斜的,但每个框只覆盖一行、行与行的上下顺序仍然连续。这种情况下继续用原图解析通常可行,只需要在后续还原环节做透视校正。

旋转矫正该不该预先做,取决于上面两条落在哪一边。只有出现退化大框、行被切开或行序错乱时,才建议在送进 TeleOCR 之前做一次旋转矫正;如果框线都跟着歪但行序正常,预先旋转属于可省的动作,做了反而多一次重采样,可能轻微损失清晰度。

加入侧向阴影后复核,划出直接解析可用与必须先预处理的分界

跑 inv01_sharp_straight_shadow.jpg,它的特点是亮暗不均:亮侧的文字识别正常,暗侧可能出现漏检或错字。阴影样本不要只看整体是否成功,按下面三条判据逐条过,每条都有明确的观察点:

  • 字段是否命中:逐字段对照基线,观察暗侧区域的字段(常是右侧金额列和票面下半部分)是否缺失。命中数比基线少,且缺失集中在暗侧,说明阴影压低了局部对比度。
  • 行序是否正确:看返回的行顺序是否和票面从上到下一致,阴影边缘是否把一行拆成两行、或把两行并成一行。行序错会导致字段归属错位,比单字识别错误更难靠后处理补救。
  • 关键数字是否无误:金额、税额、价税合计逐位核对,并做一次加和自检(金额加税额是否等于价税合计)。数字逐位正确是硬要求,出现错位或漏位就不算通过。

这三条判据可以沉淀成一份可复用的决策清单,每次拿到新的一批手机发票照片都可以照着走:

  1. 先固定输入尺寸、格式和解析参数,用清晰正拍样本跑一次,确认关键字段都能命中,作为这批照片的参照基线。
  2. 直接解析实际待处理的手机照片,对照基线看三条判据。三条全部通过,直接解析可用,不必预处理。
  3. 只有字段漏检、且漏检集中在亮度不均的区域,先加去阴影或局部对比度增强,再解析一次对比。
  4. 只有检测框退化成大框、行被切开或行序错乱,先加旋转矫正,再解析一次对比。
  5. 三条判据里有两条以上不通过,说明单纯预处理收益有限,应先改善拍摄条件(正面、均匀光、避免手抖),再重跑基线。
  6. 每次调整只改一个变量,改完必须回到同一张底稿复跑,否则无法判断改善来自哪一步。

边界需要说清楚:这套判断依赖你实际环境的输入尺寸、压缩方式和接口返回内容,同样的照片在不同分辨率或不同参数下结论可能不同,所以清单里的阈值不能照搬,要先用自己的一批样本跑出基线再定。另外,预处理本身也会引入新的误差,去阴影过度会压低文字笔画,旋转重采样会让细笔画发虚,因此能靠拍摄解决的,优先回到拍摄,而不是层层叠加预处理。