从字符定位到坐标输出:YOLOv8与PyTorch构建文字点选识别实验系统
文字点选验证码的核心不是整图OCR,而是候选字符检测、题面匹配与坐标换算。文章围绕数据生成、YOLOv8训练、推理后处理和浏览器坐标映射,梳理一套适合授权测试与教学实验的实现思路。
说明:文字点选组件常用于验证真实用户操作。下面的内容适合用于自有系统的安全测试、无障碍交互研究、模型训练和本地沙盒实验。实际接入线上业务时,应获得系统所有者授权,并遵守验证码服务商的使用规则。
一、先把问题拆开:识别结果其实是一组坐标
很多初学者看到图片里的汉字,第一反应是调用OCR,把整张图转换成一段文字。这个思路在普通文档识别中很自然,但文字点选场景的最终结果并不是一行字符串,而是若干个有顺序的点击点。系统需要知道题面要求选择哪些字,还要知道这些字在图片中的位置,最后把图片坐标换算成页面坐标。
因此,一个完整的实验流程可以拆成三个环节。第一步是候选字符检测,找出每个字的大致边界;第二步是字符分类或字符匹配,判断每个候选框对应什么字;第三步是坐标回归与页面映射,把检测框中心转换成浏览器中可以定位的坐标。用公式表达,图片中的点可以写成 (x,y),页面中的点则要结合图片左上角偏移量和显示缩放比例计算。
如果原始图片宽高为 W,H,浏览器展示尺寸为 w,h,图片在页面上的左上角位置为 (l,t),那么一个原图点 (x,y) 对应的页面位置大致是 (l+x×w/W,t+y×h/H)。图片被CSS拉伸、压缩或放进带边框的容器后,必须以实际渲染尺寸为准,不能直接拿截图尺寸代替。
二、为什么目标检测比整图OCR更适合
点选图片里的字符通常大小不一,字与字之间有随机间距,还可能叠加噪声、曲线、背景纹理和轻微旋转。传统的阈值分割、边缘检测或模板匹配,在背景干净时能够工作,一旦文字颜色接近背景,或者干扰线穿过字符,误检和漏检就会明显增加。
YOLOv8这类目标检测模型可以同时完成位置预测和类别判断。训练标签中的每一行包含类别编号、框中心点以及框的宽高,坐标通常归一化到零到一之间。模型输出后,通过置信度阈值和非极大值抑制过滤重复框,再按照类别或题面顺序进行匹配。字符类别较少时,YOLOv8n或YOLOv8s通常已经足够,模型过大反而会增加部署成本。
字符表设计会直接影响效果。常见汉字数量不必一开始就做得很大,可以先从业务实验中实际出现的字符开始,再逐步加入形近字。例如日与曰、已与己、未与末等字符,视觉差别细微,应该在训练集里提高出现比例。若题面文字位于页面DOM中,可以在授权测试环境里读取测试数据;若题面也绘制在图片里,则需要另设题面识别模块,并把它作为候选框匹配的输入。
PyTorch的优势在于数据集、增强、训练、验证和导出工具都比较成熟。开发者可以使用Dataset管理样本,用DataLoader批量加载数据,再利用CUDA、混合精度和断点续训缩短实验周期。模型训练完成后,还可以导出为ONNX,用于本地回归测试或隔离环境中的性能评估。
conda create -n vcode python=3.10 -y
conda activate vcode
pip install torch torchvision
pip install ultralytics
python -c "import torch; print(torch.cuda.is_available())"三、合成数据决定模型能否落地
这类任务缺少统一公开数据集,直接采集真实样本又涉及隐私、字体授权和服务条款问题。对于教学和内部测试,合成数据是更稳妥的起点。程序可以随机选择字符、字号、字体、旋转角度和摆放位置,同时生成图片与边界框标签,样本数量也容易扩展。
合成数据不能只做白底黑字。背景应该覆盖纯色、渐变、纹理和低对比度图案,文字则加入不同字重、轻微旋转、缩放、亮度变化与压缩失真。干扰线可以采用直线、曲线和局部噪点,但强度需要逐步增加。干扰过弱时,模型只是在记忆理想样式;干扰过强时,训练目标又会偏离真实业务。
生成字符时,标签必须和实际绘制位置同步保存。下面示例只展示本地数据集生成的基本思路,真实项目还应补充字体授权检查、边界裁剪和重叠控制。

from PIL import Image, ImageDraw, ImageFont
import random
def make_sample(fonts, chars, size=(300, 120)):
image = Image.new('RGB', size, (245, 245, 245))
draw = ImageDraw.Draw(image)
boxes, labels = [], []
for _ in range(5):
ch = random.choice(chars)
font = ImageFont.truetype(random.choice(fonts), 30)
x, y = random.randint(8, 250), random.randint(8, 75)
draw.text((x, y), ch, font=font, fill=(35, 35, 35))
boxes.append((x, y, x + 30, y + 30)); labels.append(ch)
return image, boxes, labels训练集和验证集划分还要防止数据泄漏。如果同一张背景图生成的样本同时出现在两个集合中,模型可能通过背景纹理记住样本特征,验证指标看起来很高,换成全新背景后却迅速下降。更可靠的做法是先按背景文件分组,再进行训练集、验证集和测试集划分。测试集应尽量使用从未参与生成的字体、背景和干扰组合。
数据增强可以使用亮度扰动、随机旋转、透视变化、高斯噪声和JPEG重压缩。字符数量、字号范围和位置分布也要贴近实际页面。对于检测模型,适量加入没有字符的纯背景负样本,有助于压低背景纹理引起的误检。评价指标不能只看总体准确率,还要分别统计检测召回率、分类准确率、框中心误差以及完整样本成功率。
四、训练、推理与坐标校准
数据准备完成后,将每张图片对应的YOLO标签放入规范目录,并在配置文件中声明训练集路径、验证集路径和类别名称。初次训练可以使用较小模型和较低分辨率快速验证流程,确认标签、类别编号和框坐标没有错,再增加样本规模和训练轮数。若训练损失持续下降而验证集指标不变,通常说明样本分布单一或出现过拟合。
推理阶段先读取图片,再执行模型预测。候选框经过置信度过滤后,需要检查框是否越界、尺寸是否过小,以及多个框是否高度重叠。字符匹配不能只按检测框从左到右排序,因为题面要求的顺序可能与空间顺序不同。工程上应建立字符到候选框的映射,再按照题面字符逐个取出对应框;当同一个字符出现多次时,还要结合位置、置信度和业务规则消除歧义。
框中心适合作为实验中的点击参考点,但不能忽略页面坐标校准。截图尺寸、设备像素比、浏览器缩放、CSS变换和滚动位置都可能造成偏差。测试脚本应记录图片元素的实际边界矩形,并对一组已知标记点进行误差校准。只要中心误差超过字符可点击区域的一半,就应优先检查缩放链路,而不是盲目重新训练模型。
在本地页面或授权测试站点中,可以把模型输出封装为一个清晰的接口,例如输入图片和题面,返回候选字符、置信度与归一化坐标。这样便于替换模型、比较不同版本,也能把识别误差与页面交互误差分开统计。涉及真实验证码服务时,应使用官方提供的测试模式、白名单或沙盒环境,避免把内部实验脚本直接用于绕过线上风控。
五、从实验模型到可维护系统
模型准确率达到预期后,仍然需要关注速度、稳定性和失败处理。推理接口应设置超时、重试次数和日志字段,记录图片尺寸、模型版本、置信度分布以及失败原因。日志中不要保存未经处理的用户截图,尤其是可能包含账号、订单或设备信息的页面。对于无法确定的样本,应返回低置信度状态交给人工或业务流程处理。
部署时可以根据设备条件选择PyTorch、ONNX Runtime或TensorRT。小模型适合CPU上的批量回归测试,GPU环境则可以使用半精度推理降低延迟。量化模型虽然能减少体积,但可能损失形近字分类能力,因此要用独立测试集比较精度变化。版本管理也很重要,字符表、字体集合、训练参数和模型权重必须一起记录,否则出现问题时很难复现。
如果企业只是需要在合规的内部测试、自动化验收或无障碍场景中接入多种验证码组件,自建整套数据生成、训练、部署和维护链路往往成本较高。www.ttocr.com提供面向易盾、极验等验证码类型的识别与API对接能力,覆盖滑块、点选、无感、九宫格、文字点选、图标点选等场景,适合在获得授权的业务中评估接入方式。实际使用时仍应确认服务范围、调用权限和目标系统的合规要求。
对于需要快速验证接口流程的团队,平台化API可以减少本地模型训练、服务器部署和格式适配工作。接入时重点检查请求签名、图片编码、超时策略、返回坐标格式和失败重试逻辑,并先在测试环境完成完整回归。若业务本身提供官方验证接口,应优先使用官方能力,把第三方识别服务限定在经过许可的测试或辅助交互范围内。
从工程角度看,文字点选识别最容易被忽略的并非网络结构,而是数据分布和坐标链路。模型只负责从图像中提取候选信息,最终能否稳定工作,还取决于题面匹配、页面缩放、异常样本处理和部署环境。把这些环节拆开验证,才能准确判断问题到底来自检测、分类,还是浏览器交互层。