ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于 PaddleOCR-VL 与 PP-OCRv6 的指定颜色发票验证码识别服务实践记录

2026/8/30 15:48:04 拓冰建站 浏览量
基于 PaddleOCR-VL 与 PP-OCRv6 的指定颜色发票验证码识别服务实践记录 一、为什么要做这个服务在发票查验、票据流转、自动化录入等场景里验证码并不总是简单的“看图输入字符”。有一类验证码会要求用户只识别某一种颜色的文字例如提示识别红色、蓝色或黑色字符而图片里还会混有干扰字符、背景纹理、噪声和相近色块。直白的说发票发票还是发票这全都怪发票验真需要验证码镂空字体示例实心字体示例图片预处理结果如果只把整张图直接丢给通用 OCR效果往往不稳定。原因很直观模型看到的是完整图片而业务真正需要的是“指定颜色上的那一组字符”。当背景、干扰字、颜色相近或字体形态变化时通用 OCR 很容易把不该识别的内容也读进去或者漏掉真正需要的字符。这次实践的目标不是做一个炫技 Demo而是把验证码识别变成一个可维护、可复核、可持续迭代的服务。它需要满足几件事能根据业务提示识别指定颜色的验证码文字对常见颜色和字体变化保持稳定能输出识别结果和可信度便于上层业务判断是否采用能记录失败案例持续回流训练和评估服务部署尽量轻量便于在现有系统中集成。二、整体思路最初的想法很简单找一个 OCR 模型直接识别验证码图片。实际测试后发现单纯依赖通用模型并不能稳定解决“指定颜色”这个问题。后来方案逐步调整为“视觉理解 文本识别 工程化预处理 质量闭环”的组合方式。整体流程可以概括为图片输入 - 目标颜色处理 - OCR/多模态识别 - 结果判断 - 失败回流其中 PaddleOCR-VL 更适合在前期分析复杂图片结构、理解样本形态和辅助制定处理策略PP-OCRv6 更适合作为轻量、稳定的文本识别主干经过针对性微调后承接在线识别任务。这里有一个很重要的取舍线上服务追求的是稳定、响应速度和可解释的失败处理不是把所有逻辑都塞进一个大模型里。因此最终的服务形态更偏工程化模型负责识别外围流程负责把输入整理到模型更擅长处理的状态。三、第一阶段从通用 OCR 到定制识别刚开始测试时我分别尝试过通用 OCR、视觉语言模型和已有验证码识别方案。通用 OCR 在清晰图片上表现不错但一遇到颜色提示、干扰字符和背景混色结果就开始飘。典型问题包括识别出了非目标颜色的字符把背景纹理或干扰线当成文字字符大小写不稳定相似字符容易混淆单个字符置信度很低但整体平均分看起来还可以某些字体下会出现漏字或多字。这些问题说明仅仅看最终识别文本是不够的还要关注模型在每个字符上的稳定性、目标区域是否干净以及同一类失败是否反复出现。因此我把识别过程拆成几个相对独立的环节颜色提示解析图片规范化指定目标内容提取OCR 识别结果后处理失败样例分类。拆开之后每个环节都可以单独评估。比如一张图识别错了先判断是目标内容没有处理干净还是 OCR 模型本身误判或者是业务提示解析出现偏差。这样后续调试会清楚很多。四、第二阶段模型选择与训练策略模型部分主要围绕 PaddleOCR-VL 和 PP-OCR系列 展开。PaddleOCR-VL 的价值在于它对复杂文档和图像元素有更强的理解能力适合用于分析样本结构、观察不同验证码形态并帮助判断问题到底来自图像本身还是识别链路。它不是本文线上服务的唯一核心但在方案验证阶段提供了很多帮助。PP-OCR 则更适合落到实际识别服务里。它的文本识别能力、部署方式和推理效率都比较适合做在线服务。实践中我没有直接使用原始模型“一把梭”而是基于业务样本做了针对性训练和评估让模型更熟悉当前验证码里的字符形态、字体变化和干扰模式。由于基础模型都是开源的没有特殊点这里不展开训练集构造、字符表、增强方式、训练参数和模型转换过程只记录几个比较有价值的经验样本质量比样本数量更重要。低质量标签会把模型带偏尤其是相似字符和大小写问题。失败样例要单独管理。把所有样本混在一起训练很容易看不到真正影响线上效果的长尾问题。评估集要贴近线上分布。只看随机测试集准确率不能代表真实服务稳定性。颜色、字体、长度和干扰类型要分维度观察。总体准确率上升不代表每一类样本都变好了。模型版本要可追溯。每次训练、转换、评估和上线都要能对应到明确版本。训练完成后我把模型转换成更适合服务部署的形式减少线上环境对训练框架的依赖。这样服务启动更轻部署也更可控。五、第三阶段服务化改造模型可用之后真正麻烦的地方才开始如何让它稳定地跑在服务里。一个可用的验证码识别服务不能只提供“传图片、返回文本”这么简单。它还需要处理异常输入、颜色提示缺失、图片格式异常、模型加载失败、置信度过低、识别为空、耗时过长等情况。我把服务接口设计成比较克制的形式业务侧提交图片和必要的上下文信息服务侧返回识别文本、目标颜色、置信度、耗时和状态信息。上层业务可以根据状态决定是否继续、重试或进入人工处理。输出结果{ code: 200, skipped: False, input_path: val_data/标注后_检查后0528/宇羊UA_黑色on2an9w11a.png, processed_path: None, target_color: 黑色, rec_text: 宇羊UA, rec_score: 0.9386486262083054, message: 识别完成 } { code: 200, skipped: False, input_path: val_data/标注后_检查后0528/彤字沙RY_黑色nuwmyn6oho.png, processed_path: None, target_color: 黑色, rec_text: 彤字沙RY, rec_score: 0.9984363555908203, message: 识别完成 } { code: 200, skipped: False, input_path: val_data/val12/巨帙EQ_黑色73f7ddf9e3.png, processed_path: None, target_color: 黑色, rec_text: 巨帙EQ, rec_score: 0.9948489367961884, message: 识别完成 }当然也有错误案例{ code: 200, skipped: False, input_path: val_data/val12/3EUF3T_黑色84ec6a4288.png, processed_path: None, target_color: 黑色, rec_text: 3毛UF3T, rec_score: 0.9205710689226786, message: 识别完成 } { code: 200, skipped: False, input_path: val_data/val12/页Bp35E_黑色797c6e9cdf.png, processed_path: None, target_color: 黑色, rec_text: 页8P35E, rec_score: 0.8862185974915823, message: 识别完成 }线上流程大致如下服务化时重点做了几件事模型启动时加载避免每次请求重复初始化临时文件使用隔离目录识别完成后及时清理返回结构保持稳定方便业务侧接入异常信息分级记录避免把敏感图片和请求细节直接打进日志对低置信度结果做保守处理不强行返回看似可用的答案离线评估脚本和在线服务共用同一套核心识别逻辑减少“测试好、上线差”的情况。这一步的关键不是把接口写复杂而是让每一个失败都能被定位。验证码识别服务最怕“偶尔错一下但不知道为什么错”。只要失败能被归类、能复现、能回流模型就可以持续变好。六、第四阶段失败案例闭环这类任务的迭代过程很像做一个小型数据飞轮线上遇到失败离线还原问题人工确认标签再进入下一轮训练和评估。我把失败样例大致分成几类低置信度样例相似字符混淆目标字符缺失非目标内容误识别字体变化明显的样例背景或干扰特别重的样例提示信息异常或颜色无法判断的样例。分类之后训练就不再是盲目加数据而是针对问题补数据。比如某一类字符经常混淆就重点看这类字符的样本是否足够、标签是否统一、评估集中是否覆盖某一类颜色容易漏字就回到图像处理和样本分布上检查。为了你好不要只盯平均准确率。验证码识别的线上体验常常取决于最难的那一小撮样例。平均分很漂亮但如果某类关键场景反复失败服务依然不可靠。所以最终评估我更关注不同颜色下的识别稳定性不同长度验证码的结果分布单字符最低置信度错误样例是否集中在少数字符新版本相比旧版本是否引入新的退化服务耗时是否满足业务要求。这些指标比单个“准确率数字”更有指导意义。七、踩坑总结这次实践里印象最深的几个坑第一通用 OCR 不等于业务可用。模型在普通文字识别上表现好不代表它能理解“只识别某一种颜色”的业务意图。第二预处理不是越强越好。处理过度会让字符笔画断裂处理不足又会留下干扰信息。好的处理方式应该服务于模型而不是追求视觉上看起来很干净。第三标签一致性非常重要。大小写、相似字符、中文字符和异常样例如果没有统一规范训练效果会变得很不稳定。第四失败样例比成功样例更值钱。成功样例证明服务能跑失败样例告诉你下一步该往哪里优化。第五线上服务要保守。低置信度结果宁愿交给上层重试或人工处理也不要为了“看起来自动化”而强行通过。八、结果评估经过多轮训练、评估和失败样例回流后服务已经可以比较稳定地处理指定颜色验证码识别任务。当前版本主要覆盖常见颜色提示和常见字符组合能够返回识别文本、目标颜色、置信度和状态信息也能把异常情况纳入后续分析。在内部评测口径下不同模型路线和字体场景的表现如下。这里的“镂空字体”和“实心字体”使用两组对应验证集评估原图用于 PP-OCR 服务链路复测黑白处理图用于 PaddleOCR-VL/多模态路线评估。方案字体场景准确率说明PP-OCR 定制识别链路镂空字体约 96%在已有字体样式下整体表现稳定适合作为轻量服务链路PP-OCRv6 定制识别链路镂空字体约 86%新字体带来了明显的字体迁移问题需要继续补充样例和做针对性迭代PaddleOCR-VL实心字体95%基于黑白处理图评估两种字体场景均达到 95% 以上PaddleOCR-VL实心字体95%泛化稳定性更好但线上部署成本和响应耗时需要综合权衡从这个对比可以看出PP-OCR 定制链路在原有字体上准确率更高但遇到新字体时会出现一定退化多模态模型路线在两种字体下都能达到 95% 以上泛化稳定性更好。后续如果继续迭代可以把 PP-OCRv6 的轻量部署优势和多模态模型的泛化能力结合起来让线上服务在速度和准确率之间取得更好的平衡。本地单进程 QPS 测试口径如下测试样本来自未标注数据中随机抽取1000张和600张然后进行人工标注制作测试方式每个模型预热 10 张正式计时 1 轮测试范围原图进入识别脚本包含颜色目标处理、OCR 推理和结果解码并发方式单进程串行调用不代表多进程或服务网关并发上限。验证集脚本/方案统一大小写准确率字符级准确率QPS平均耗时P95 耗时结论镂空字体原图captcha_recognizer_v3_onnx.py95.36%98.26%24.0241.63 ms57.14 ms原有字体下稳定可作为旧版本基线镂空字体原图captcha_recognizer_v6_onnx.py94.29%97.95%39.5725.27 ms35.40 ms吞吐更高综合部署价值更好实心字体原图captcha_recognizer_v3_onnx.py1.31%13.60%23.7342.14 ms52.47 ms对新字体基本不适配不建议继续作为新字体主链路实心字体原图captcha_recognizer_v6_onnx.py86.07%94.21%24.4340.93 ms52.58 ms新字体场景可用但仍有继续提升空间当前环境captcha_recognizer_v3.py-----PaddleOCR/Paddle 推理初始化失败报libpaddle相关错误需要修复环境后重测当前环境val_merged.py95%----多模态路线在两种字体上准确率均达到 95% 以上当前 Python 环境缺少torchQPS 需在部署机补测从吞吐结果看ONNX 化后的 PP-OCRv6 识别链路更适合当前在线部署在原有字体和新字体验证集上它的速度和泛化表现更均衡。Paddle 原生版本和多模态验证脚本不是不能用而是当前机器环境没有满足完整压测条件因此不把它们写成确定 QPS避免误导。从工程角度看这个项目最大的收获不是某一次模型准确率提升而是建立了一套可持续迭代的流程有数据入口有模型训练有服务部署有在线记录有失败回流有版本评估。只要这个闭环存在后续遇到新的字体、新的颜色、新的干扰形态都可以按同一套流程继续迭代。九、结语整体来看不难就是标注数据非常麻烦网上相关资料比较少也没什么特别的都是真实数据撑起的准确率其他的也没有见到非常亮点的模型。。。另外也客气一下吧指定颜色验证码识别看起来是一个很小的 OCR 问题但真正落地时会牵涉到图像处理、模型训练、服务部署、日志脱敏、失败样例管理和业务兜底。单点能力并不难难的是把它做成一个稳定、可维护、可解释的服务。参考PaddleOCR 官方项目https://github.com/PaddlePaddle/PaddleOCR非常感谢前期数据标注项目ddddocr项目任务初期文章参考【2020.06】国税总局发票查验平台验证码最新获取方法_自动报税 手机验证码怎么获取-CSDN博客