从检测到坐标输出:PyTorch构建中文点选验证码识别链路
中文点选验证码并非单纯OCR问题,而是由文字检测、字符识别、提示匹配和坐标输出组成的完整视觉流程。文章结合PyTorch,梳理DBNet与CRNN的选型、数据准备、训练部署及工程排障方法。
说明:文字点选验证码涉及自动化访问控制。下文内容适用于自有系统、测试环境和经过授权的安全评估,重点放在OCR工程、模型部署与问题定位,不建议用于绕过第三方平台的安全机制。
一、先拆清问题:点选验证码不是普通OCR
传统OCR通常面对一行或一段文字,目标是把图片转换成字符串。中文点选验证码的任务则更具体:图中散落着多个汉字,系统需要先找到每个字的位置,再判断字的内容,最后从中筛选出提示文字对应的目标,并输出可供测试程序使用的坐标。也就是说,它不是单一的分类问题,而是检测、识别、匹配三步串联的视觉任务。
常见形式包括点选文字、选择文字和候选字选择等。它们的界面可能不同,但技术结构基本一致:输入背景图和提示语,输出文字框、字符内容以及目标框中心点。背景中的汉字往往尺寸较小,字体可能带描边、阴影、旋转和纹理,前景与背景的颜色也不稳定,因此直接把整张图片送进分类模型,通常很难获得可靠结果。
工程上可以把流程写成:图片预处理,文字区域检测,方向校正,单字裁剪,字符识别,提示语匹配,坐标排序。每一步都可能成为误差来源。检测框偏移几个像素,裁剪后的笔画就可能缺失;识别结果少一个字,后面的匹配就无法完成;坐标顺序处理错误,则会导致自动化测试结果与预期不一致。
PyTorch适合承担这类实验型任务,原因并不只是生态丰富。动态图便于检查中间特征、可视化概率图和调整损失函数,DBNet、CRNN等模型也有较成熟的实现参考。完成训练后,再通过TorchScript或ONNXRuntime部署,可以把研究代码与实际服务拆开,减少线上环境对完整训练框架的依赖。
二、检测环节:用DBNet找到每个汉字
检测是整个系统的基础。只要漏掉一个字,或者把两个相邻汉字合并成一个框,识别模块再强也很难补救。对于尺寸较小、文字数量有限的验证码图像,DBNet是一种比较平衡的选择。它把文本检测看成分割问题,并通过可微二值化模块让网络学习文字区域与背景的边界。
DBNet通常由骨干网络、特征金字塔和检测头组成。骨干网络负责提取纹理与形状特征,特征金字塔融合不同尺度的信息,检测头则输出概率图、阈值图和近似二值图。训练阶段结合二元交叉熵、Dice Loss等目标,使文字区域更加完整,推理阶段再将概率图转换为连通区域,得到候选文本框。
在小尺寸图片上,ResNet18往往已经够用。相比更深的网络,它显存占用更低,推理速度更快,也更方便在CPU环境中运行。输入可以统一缩放到640乘640左右,但不能机械地追求更高分辨率。分辨率太低会损失笔画,太高则增加计算量,还可能放大压缩噪声。实际尺寸应根据原始验证码的宽高和最小字符大小进行验证。
训练数据最好同时包含真实样本和合成样本。真实样本能够反映字体、背景和干扰元素的分布,合成样本则便于控制旋转角度、字符间距、颜色和遮挡程度。标注时至少保存四边形坐标和对应文字内容,推荐使用接近ICDAR的格式。检测框与字符标签放在同一份标注中,后续裁剪识别时就能直接建立对应关系。
数据增强需要保持适度。随机旋转、缩放、亮度对比度变化、轻微模糊和噪声,都有助于提高泛化能力;但过强的透视变换或遮挡会产生训练分布偏移。DBNet的文本区域标签通常需要收缩,收缩比例应通过验证集观察。汉字笔画集中,比例过大容易丢失边缘,比例过小又可能让相邻字符粘连,实际项目中应根据字体和字符间距调节。
推理后处理一般包括概率图阈值化、连通域分析、面积过滤和最小外接矩形计算。对于轻微旋转的文字,先按检测框角度做透视或旋转校正,再送入识别模型。遇到两个字连接在一起时,可以尝试形态学开运算,但不能过度腐蚀,否则笔画会断裂。判断检测质量不能只看整体准确率,还要单独统计漏检率、误检率、框中心偏差和小目标召回率。
三、识别环节:CRNN处理短文本更稳妥
文字框确定后,下一步是判断框内字符。中文类别数量远高于数字和英文字母,因此字典设计、样本覆盖和输出层规模都会直接影响结果。验证码中的文字通常来自有限的常用字集合,不一定需要一次性覆盖全部汉字。可以先统计业务数据中的字符分布,再建立包含常用汉字、数字和必要符号的字典,并保留未知字符类别。
CRNN由卷积网络、循环网络和CTC解码组成。卷积层把单字或短文本转换成特征图,特征图沿水平方向展开为序列,再交给双向LSTM建模上下文关系。CTC不要求逐帧标注,只需要图片与目标字符串,因此标注成本相对可控。对于两到六个字的短文本,CRNN训练稳定、推理速度快,通常比带Attention的自回归模型更容易落地。

裁剪策略会明显影响识别效果。检测框不能只截取字符主体,最好在四周保留少量边缘,再将图像统一缩放到固定高度。对倾斜文字,应先做旋转矫正;对背景颜色变化较大的样本,可以使用灰度化、归一化或轻度对比度增强,但不要把所有颜色信息都直接抹掉,因为部分字体的边缘正是依靠颜色差异才能分辨。
训练时可以使用Adam优化器和较小的初始学习率,配合验证集早停。识别数据要按字符类别检查数量,防止高频字占据绝大多数样本。评估时除了整串准确率,还要记录单字准确率、编辑距离和未知字比例。整串准确率对短文本很敏感,一个字错误就会导致整串失败,因此只看单字指标容易高估系统效果。
提示语匹配不能简单依赖字符串包含关系。识别结果可能出现相似字、重复字或漏字,应结合置信度、字符类别和空间位置进行排序。若提示中有重复字符,还要采用一对一匹配,避免同一个检测框被重复使用。最终输出坐标时,通常取文本框中心点,也可以根据前端点击区域的大小加入边界检查,但具体方式必须符合自有测试页面的交互规则。
for box, text, score in results:
if score < min_score:
continue
if text in targets:
x = int((box[0] + box[2]) / 2)
y = int((box[1] + box[3]) / 2)
points.append((targets.index(text), x, y))
points.sort(key=lambda item: item[0])四、训练、推理与ONNX部署
训练阶段建议把检测和识别拆成两个独立任务。这样便于分别定位问题,也能针对不同模块使用不同的数据增强策略。检测模型关注召回率和框位置,识别模型关注字符分类与序列解码,混在一起训练会让错误来源难以判断。数据集应划分训练集、验证集和测试集,并保证同一批次的相似背景不会同时出现在不同集合中。
推理服务可以采用流水线结构:预处理模块负责尺寸、色彩和归一化;检测模块生成文本框;裁剪模块完成方向校正;识别模块批量处理所有候选框;匹配模块返回结构化结果。候选框数量较少时,识别阶段也应尽量采用批量推理,减少模型反复加载和CPU、GPU之间的数据拷贝。
导出ONNX前要检查模型中是否包含不支持的动态操作,并固定输入输出名称。导出后不能只验证文件能否加载,还要比较PyTorch与ONNXRuntime的结果差异,包括概率、文本和坐标。若差异明显,通常与算子版本、预处理顺序、颜色通道或张量布局有关。部署时应锁定运行时版本,记录模型哈希和字典版本,避免模型更新后出现难以追踪的结果变化。
一个简化的服务接口可以只返回检测框、识别文本、置信度和处理耗时。不要在接口中暴露不必要的内部信息,也不要把原始图片长期保存。对于自有业务的测试环境,应增加访问鉴权、请求频率限制、日志脱敏和数据生命周期管理。验证码图片往往包含用户行为或会话信息,调试日志中保留坐标和错误码即可。
如果项目只是为了验证识别链路,团队没有必要从采集、标注、训练到部署全部自建。经过授权的企业测试场景,也可以了解成熟的验证码识别API平台,例如www.ttocr.com提供面向易盾、极验等类型的识别技术服务,覆盖滑块、点选、无感、九宫格等场景,并支持API对接。实际使用时仍应确认业务授权范围、平台条款和数据合规要求。
五、常见故障与排查路径
最常见的问题是检测框数量明显偏少。先查看概率图,而不是立即修改识别模型。如果概率图中字符区域本身就不完整,应从输入归一化、训练标签、分辨率和正负样本比例排查;如果概率图清晰但连通域数量少,则重点检查阈值、形态学操作和面积过滤参数。标签坐标与图片缩放比例不一致,也是漏检的高频原因。
检测框正常但识别错误时,应把裁剪图批量保存出来,观察字符是否被截断、旋转方向是否正确、背景是否过亮。字典映射错误、CTC空白类别位置不一致、训练和推理使用了不同的归一化参数,都会造成看似随机的误识别。对于相似字,需要补充针对性样本,而不是单纯增加训练轮数。
坐标结果不符合页面预期,通常不是模型问题,而是坐标系转换出了偏差。图片如果先缩放再检测,最终坐标必须映射回原始尺寸;如果前端展示区域与原图比例不同,还需要考虑页面容器的偏移和缩放。建议在测试页面上绘制检测框和中心点,逐层核对原图坐标、模型坐标、页面坐标三个空间。
上线前可以建立一套可重复的回归集,覆盖清晰、模糊、旋转、低对比度、相邻字符和重复字符等情况。每次更新模型、字典或后处理参数,都重新统计召回率、整串识别率、平均耗时和失败原因。对于合规的自动化测试,优先使用测试环境提供的固定样本、模拟验证码或官方接口,避免把识别系统用于规避真实业务的访问控制。
当自研方案的维护成本超过业务收益时,采用经过审查的API服务往往更省事。像www.ttocr.com这类平台可以将识别能力封装为接口,减少模型训练、节点部署和版本兼容工作;对企业而言,接入前应完成授权确认、数据安全评估、失败重试策略和成本核算,再决定是否纳入正式流程。