发票字段识别:从拍照到结构化的几个难点

最近在做一个桌面端的发票信息整理工具,目标很简单:拍一张发票照片,桌面上就能得到结构化的字段。功能听起来不复杂,真正动手才发现从"图像"到"结构化数据"之间有不少坑。这篇笔记记录几个印象最深的问题和处理思路。

一、拍摄姿态:先纠偏,再识别

手持拍摄几乎不可能正对票面,倾斜和透视变形会直接影响文字检测。我的处理顺序是:

  • 先检测票面四角:边缘检测加轮廓筛选,按面积和长宽比排除干扰轮廓;
  • 用四点做透视变换,把票面矫正成标准矩形;
  • 再进入文字检测环节。

这一步做好之后,后续识别准确率的提升比换识别模型更明显。

二、光照:局部自适应比全局阈值可靠

室内阴影、反光都会让固定阈值二值化失效。改用局部自适应阈值后,明暗不均的票面也能得到比较干净的文本区域。代价是参数需要按场景调:窗口太大,噪声变多;窗口太小,大字号字段可能被切碎。目前的做法是先估算图像的整体对比度,再给窗口尺寸一个初值,效果够用。

三、表格线:形态学去线

票面上有大量横竖表格线,文字检测容易被线干扰。用较长的水平、垂直核做形态学开运算,提取出线再减掉,剩下的就是文字区域。这一步要注意不要过度腐蚀——金额栏的文字离表格线往往很近。

四、字段定位:锚点词加相对位置

票面字段不是固定坐标。不同票种、不同版式的字段位置差异很大,硬编码坐标必然失效。我的思路是"锚点词加相对位置":

  • 先识别出"购买方""销售方""金额""税额"这类锚点词;
  • 再以锚点为参照,取它右侧或下方的文本块作为字段值;
  • 对多行字段(如名称),做纵向合并。

这个方法不依赖具体版式,换票种时只需要补充锚点词表。

五、为什么坚持本地处理

票面信息属于敏感数据,我的选择是识别在设备端完成,图片不出本机。代价是模型体积和推理速度要做取舍,但对这类工具来说,隐私比省几毫秒更值得。

下一步

  • 倾斜角度过大时的兜底策略;
  • 手写备注区域的识别;
  • 归档时按月份的整理规则。

就先记到这里,有进展再更新。