袁隆平院士逝世的消息弹出来时,我正在调试 PaddleOCR 对一张皱巴巴的送货单的识别准确率,窗外成都的雨声突然变得清晰起来。不是那种抒情的清晰,是物理上的,雨点砸在空调外机上的声音,和屏幕上不断跳出的识别错误日志,频率几乎一致。那一刻我脑子里闪过的念头是,这位让无数人吃饱饭的老人,大概不会想到,2021年还有我这样的人,在为了把纸上几个潦草的数字变成准确的 Excel 表格而绞尽脑汁,就为了省下几个雇人录入的工时。时间就是金钱,这话在疫情后我断尾求生、重新回归个人交付的档口,不再是口号,是生存的血压。
客户是本地一家连锁餐饮的供应商,每天经手几百张手写单据,入库、分拣、对账,全靠三个阿姨手工录入到电脑。一个月人工成本一万二,错误率还高。我接这个活的报价是八千,开发一套自动化系统。听起来很美,直到我拿到第一批扫描件——手机拍的,光线不均,有手指影子,纸张皱褶像地图上的等高线,字迹潦草得仿佛医生处方。Tesseract 这种老牌 OCR 上去就扑街了,识别率不到 30%。我不得不转向 PaddleOCR,看中的是它的中文场景优化和自定义训练能力。
真正的战斗从数据预处理开始。光是灰度化和二值化的阈值调整,就耗掉我两天。大津法(Otsu)在光照不均的图片上就是个废物,必须手动尝试不同的局部自适应阈值算法。然后是对比度增强,CLAHE 算法用上了,但参数(clipLimit 和 tileGridSize)稍微不对,就会把纸张纹理也强化成干扰噪点。这阶段的核心矛盾是:预处理得太“干净”,可能会损失笔画细节;保留太多原图信息,背景干扰又会让 OCR 引擎困惑。我写了个批处理脚本,用 OpenCV 遍历不同的参数组合,生成上百张中间结果图,再肉眼抽样判断,试图找到那个脆弱的平衡点。这活儿毫无技术浪漫可言,就是纯粹的体力型调试,一种数字时代的“精耕细作”。
调好了预处理,PaddleOCR 本身还有坑。默认的通用中文模型对印刷体友好,但对手写数字、连笔字、以及“土豆”“青椒”这种特定货品名,识别率感人。我没有足够的数据去从头训练模型,只能走微调(Fine-tuning)的路子。从现有的几百张单据里,手动标注了大概两千个文本区域,生成合成数据(比如加噪点、仿射变换模拟褶皱)扩充到一万条。训练环境又是一道坎,本地显卡是 GTX 1060,6G 显存,跑 PaddleOCR 的检测-识别联合训练,batch size 只能设到 4,一个 epoch 要跑三小时。训练过程中要盯着损失函数曲线,防止过拟合,还得用验证集实时测试准确率。那几天,电脑风扇的轰鸣声和窗外的雨声混在一起,我像个炼丹道士,守着炉子,期待着一炉能提升 5 个百分点的“仙丹”。
最后上线的系统,是一个用 FastAPI 搭的简易服务,部署在客户内网一台旧电脑上。前端就是个上传图片的网页,后端流程是:图片预处理 -> PaddleOCR 检测识别 -> 基于规则(正则表达式匹配金额、日期格式)和简单 NLP(匹配货品名称库)进行结构化 -> 输出 JSON 并自动填入提前设计好的 Excel 模板。识别率最终稳定在 94% 左右,剩下的 6% 错误,主要是极端模糊或字迹完全飞起的部分,系统会高亮标注出来,让阿姨们快速复查修正。整体效率提升了大概 70%。
雨还在下。我保存好最后的模型文件,关掉训练终端。新闻里在回顾袁老的一生,强调“一粒粮食能救一个国家”。我盯着屏幕上那套刚刚能稳定运行的 OCR 流程,想的是,我这一串代码,大概也能帮那个小供应商每个月省下几千块钱,少加几个班。一种非常具体、甚至有些卑微的“生产力提升”。在这个超级个体必须用技术武装到牙齿才能存活的时代,这种提升,就是我的“粮食”。它不宏大,但能让我,以及我的客户,在下一波不确定性到来时,多扛一会儿。技术人的价值,有时候就是这么直接而骨感。














