TensorFlow – 验证码识别(使用CNN)

效果预览

enter image description here

enter image description here

综合准确率在90%以上。

环境和数据准备

我们先保存几个教务处的验证码,通过观察这些验证码,我们发现了以下特点:

  1. 背景有一些彩色的椒盐噪声(可用滤波或点降噪去除)
  2. 验证码主体只有一种颜色 RGB:(0,0,153)(无法通过颜色的区别来分割字符)
  3. 进行了随机角度的旋转(可以想到切割后进行倾斜度矫正)
  4. 字符之间存在粘连,不易切割(主要是w、m等)

enter image description here

因此很容易可以想到以下两种识别方式:

  • 对验证码切割后使用SoftMax回归训练识别。(因为验证码存在粘连,准确率可能不是太高)
  • 直接对整张图片使用CNN(卷积神经网络)识别。(因为有4位字符,可能需要大量带标记样本才能达到不错的效果)

在本文中我们采用第二种方式,在不进行字符切割的情况下直接对验证码进行端到端的识别。

带标记数据获取

3000张带标签的验证码

数据预处理

格式转换

直接获取到的验证码是gif编码的,由于cv2不能处理gif,附一个转换成png格式的小脚本(当然也可以选择用其他的图形库替代cv2)。

去除边框、降噪、二值化

其实对于CNN这种级别的武器来说,不经过降噪直接识别也有不错的准确率,但是为了排除验证码带来的干扰,仍然进行降噪处理。

在输入的图像中虽然有较多的噪声点,但是经观察发现,验证码主体转成灰度图后只有3个灰度(17、62和68),因此在灰度图上先去除除了这三个灰度的所有点,再进行滤波。

读取灰度图

enter image description here enter image description here enter image description here enter image description here

只保留3个灰度(代码)

只保留3个灰度(效果)

enter image description here enter image description here enter image description here enter image description here

去除噪点(代码)

去除噪点(效果)

enter image description here enter image description here enter image description here enter image description here

输入和输出转化

由于在TensorFlow中,只支持向量的输入输出。所以我们将输入转成70*25维的向量,每个值代表一个像素(仅取0和1)。将输出转成36*4维的向量。其中4个字符,每个字符取值为数字0-9或小写字母a-z,分别对应0-35。例如:‘123p’对应的向量为:

训练

由于我们只有3000个样本,但是对于卷积神经网络来说,至少2-3k次的训练才开始有效果。我们取64个样本为一个batch,样本量远远满足不了训练的需求。因此我们采用滑动窗口的方式,第1次训练样本1-64,第2次训练样本2-65。。以此类推,当所有的样本都被训练完后,再回到第一个样本开始重复训练。

本文的CNN模型参考自此文
http://blog.topspeedsnail.com/archives/10858
斗大的熊猫–《WTF Daily Blog》

可视化模型图

graph

(Powered by Tensorboard)

点击此处查看大图

测试

训练完成后,使用保存的模型(迭代20000次)对100个测试集样本进行测试,正确率为93%,即在100个验证码的400个字符中,有7个字符识别错误。

训练效果分析

识别错误的验证码

enter image description here enter image description here

原因分析

字符重合度较大时,难以识别出重合的两个字符。另一方面,由于训练样本较少,某些字符旋转到特定的角度时可能没有被训练到(如:向右倾斜的6)

loss和准确率曲线

enter image description here enter image description here

loss和准确率曲线在3000,6000,9000处存在跳变,这是因为总共3000个训练样本,训练完一遍重新从头开始训练的缘故(改进训练样本的获取方式可以让曲线更平滑)。

可以看出,CNN在训练次数很小(小于2000)时几乎起不到任何作用,训练数到达某处时(2000)突然就开始有了突飞猛进的进步(量变引起质变?),最后逐渐趋向于稳定。当然这个loss开始下降的阈值并不是固定的,它取决于学习任务的难度、每次feed的样本量、学习率等多方面因素。

项目代码

https://github.com/misads/capcha_recog