准备工作
首先,我们需要收集并下载验证码图片,并保存到本地。为了便于后续处理,我们会对这些图片计算 MD5 值并进行保存。这个步骤不仅有助于后期验证数据的完整性,也确保了每次处理的数据是一致的。
由于验证码图片的复杂性相对较低,目标检测不需要大量的图片数据,大约200到400张图像即可满足训练需求。
神经网络架构选择更多内容访问ttocr.com或联系1436423940
在验证码识别中,主流的两种方法是:
YOLO目标检测 + Siamese 网络进行相似度判断
YOLO目标检测 + CRNN进行文字识别
对于本项目,我们建议使用YOLO + Siamese网络,特别是在图标和文字的识别方面,这种方法效果较好。相比之下,CRNN虽然效果好,但需要大量的数据支持和长时间的训练,因此我们选择第一种方法。
注意事项
某些验证码的参考图片包含透明背景,这可能会影响相似度模型的训练效果。为避免这种情况,可以将这些图像的透明背景转换为白色,这样可以确保模型的训练和预测结果更为准确。
数据集构建
图片标注
图片标注的目标是识别图像中的文字部分。其他信息如图标标注、背景等不必考虑。标注时,我们只需要关注文字区域的标定,并确保数据的准确性。
具体标注方法可以参考我之前的文章。
注意事项
在某些情况下,参考文字与目标文字可能会位于同一张图片内,这时需要分别标注它们为不同类型。如果图片中包含图标,它们的位置是固定的,可以直接裁剪出来。极少会出现包含多种图标的情况。
YOLOv5目标检测
训练模型
YOLO训练的具体步骤已经在我之前的文章中介绍过,如果感兴趣可以查看链接。
构建相似度模型
我们将使用VGG16作为骨干网络,结合Siamese神经网络结构,构建一个相似度模型。该模型的目标是接收两张经过处理的图片,并输出它们的相似度值。该相似度值将会在0到1之间,代表两张图片的相似程度。
数据集
将所有经过目标检测并裁剪的图片按类别存储。需要注意的是,由于相似度模型无法直接处理文字,因此文字部分需要转换为图片形式。
以下是将文字转为图片的代码示例:
python
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
def text_to_image(text, text_color='black', bg_color='white'):
"""将文字转换为图片"""
img = Image.new('RGB', (100, 100), color=bg_color)
img_draw = ImageDraw.Draw(img)
width, height = img.size
font = ImageFont.truetype('msyh.ttc', size=75)
w = font.getlength(text)
img_draw.text(((width - w) / 2, 0), text, fill=text_color, font=font)
buf = BytesIO()
img.save(buf, format="JPEG")
return buf.getvalue()
我还使用了一个简单的PyQt5界面来进行人工分类。
最终,整理好的数据集可以按照如下目录结构进行存储:
kotlin
train
丁
丁_672.png
丁_673.png
.....
七
七_7408.png
七_7409.png
.....
val
丁
丁_672.png
丁_673.png
.....
七
七_7408.png
训练集和验证集的比例可以根据实际需求进行调整,常见的设置是90%的数据用于训练,10%用于验证。
训练模型
相关的存储库代码可以从以下链接获得:
Siamese-pytorch
dianxuan
Siamese-pytorch存储库是比较常用的,但它可能需要对代码进行一些修改以适应我们的数据集。为了避免出错,我们可以使用第二个存储库,它虽然代码不如前者简洁,但能满足我们的需求。
在开始训练之前,模型会下载一个预训练的VGG16模型文件。由于下载速度较慢,我们可以手动从以下链接下载模型文件:
下载VGG16模型
下载后,将模型文件放入%USERPROFILE%.cache\torch\hub\checkpoints目录中。
训练命令
python train.py
等待训练完成后,可以查看模型的损失(loss)和准确率(accuracy)。
导出ONNX模型
将训练好的模型导出为ONNX格式,以便在其他平台上使用。创建export.py文件,内容如下:
import torch
from text import Siamese
out_onnx = 'model.onnx'
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
dummy = (torch.randn(1, 3, 105, 105).to(device), torch.randn(1, 3, 105, 105).to(device))
model = torch.load('你的模型路径')
model.eval()
model = model.to(device)
torch_out = torch.onnx.export(model, dummy, out_onnx, input_names=["x1", "x2"])
print("finish!")
模型评估
创建predict.py用于评估模型:
python
import cv2
import onnx
import onnxruntime
import numpy as np
加载ONNX模型
onnx_model_path = 'model.onnx'
onnx_model = onnx.load(onnx_model_path)
创建ONNX推理会话
ort_session = onnxruntime.InferenceSession(onnx_model_path)
image1 = cv2.imread(r'1.jpg')
image2 = cv2.imread(r'2.jpg')
image1 = cv2.cvtColor(image1, cv2.COLOR_BGR2RGB)
image2 = cv2.cvtColor(image2, cv2.COLOR_BGR2RGB)
将图片转换为numpy数组
input1 = cv2.resize(image1, (105, 105)).astype(np.float32) / 255
input2 = cv2.resize(image2, (105, 105)).astype(np.float32) / 255
转换形状为 (C, H, W)
input1 = np.transpose(input1, (2, 0, 1))
input2 = np.transpose(input2, (2, 0, 1))
添加batch维度
input1 = np.expand_dims(input1, axis=0)
input2 = np.expand_dims(input2, axis=0)
outputs = ort_session.run(None, {'x1': input1, 'x2': input2})
输出相似度
print(outputs[0][0][0])
输出的数值即为图片之间的相似度。
图片识别与验证
结合目标检测和相似度模型,可以通过裁剪图片、转换文字为图像、然后计算每对图片之间的相似度,生成一个相似度矩阵。处理后,我们可以根据相似度最大值的索引来优化结果,直到矩阵中的所有值都为0。****