15分钟实现数字验证码自动识别,基于OpenCV+Keras
Posted 习悦智能
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了15分钟实现数字验证码自动识别,基于OpenCV+Keras相关的知识,希望对你有一定的参考价值。
0
简介
验证码是我们登录网站、提交订单时常常会遇到的,最近大家登陆12306抢票肯定也遇到过很多的验证码,在关键时刻还要从一堆低像素的图片中寻找灯塔和蜡烛,实在让人愤懑。本文从最简单也最为常见的数字验证码出发,利用机器学习实现验证码的自动识别。
验证码,可以看做网站的入口,只有当正确的输入验证码时才允许开始访问网站。验证码的英文为CAPTCHA,全称是全自动区分计算机和人类的公开图灵测试(Completely Automated Public Turing test to tell Computers and Humans Apart)」,作为图灵测试的一种,旨在确认访问者是真正的人类还是机器,从而防止恶意程序的入侵。然而,随着深度学习和计算机视觉技术的发展,自动识别验证码成为了可能。
Part
1
任务:搜集验证码
用时:2分钟
我们知道,机器学习需要大量的学习样本来进行权值参数训练。而在短时间内收集大量的验证码并非易事,本文作者找到了一个很容易破解的网站,其所用的验证码插件可轻松获得验证码的生成程序。有了这个生成程序就好办啦,相当于我们不用去找样本,找到了样本它妈,帮我们生一批样本出来。
作者找到的这个网站叫Really Simple CAPTCHA,先来看一下它生成的验证码长什么样子。
从上图我们可以看出,网站插件所生成的验证码是4位的,包含数字和字母。从插件的php代码再来确认一下,代码如下:
public function __construct() {
/* Characters available in images */
$this->chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
/* Length of a word in an image */
$this->char_length = 4;
/* Array of fonts. Randomly picked up per character */
$this->fonts = array(
dirname( __FILE__ ) . '/gentium/GenBkBasR.ttf',
dirname( __FILE__ ) . '/gentium/GenBkBasI.ttf',
dirname( __FILE__ ) . '/gentium/GenBkBasBI.ttf',
dirname( __FILE__ ) . '/gentium/GenBkBasB.ttf',
);
从代码里可以看到,验证码的位数为4位,每个字符的字体各不相同,由数字和字母构成,但是为了避免混淆不包含O和I。所以,我们总共有32个字符(8个数字+24个字母)需要识别。
Part
2
任务:工具准备
所需时间:0分钟
所谓工欲善其事,必先利其器。本文作者所使用的工具如下:
Python 3
Python 是目前人工智能领域中最为流行的编程语言,包含多种机器学习和计算机视觉库。
OpenCV
OpenCV 是计算机视觉和图像处理任务上的流行框架。在这里,我们需要使用 OpenCV 来处理 CAPTCHA 生成的图像,OpenCV 拥有 Python API,所以我们可以直接使用 Python 调用它。
Keras
Keras 是一个使用 Python 编写的深度学习框架。他可以让我们更加轻松地定义、训练和使用深度神经网络——仅需编写很少的代码。
TensorFlow
TensorFlow 是谷歌推出与维护的机器学习库,也是目前人工智能领域里最为流行的框架。我们会在 Keras 之上写代码,但 Keras 实际上并没有实现神经网络运算的方法——它需要使用 TensorFlow 作为后端来完成具体的工作。
假设环境你已经安装好了,不然的话光Tensorflow小编就能安一个星期啊。。T-T
Part
3
任务:建立验证码数据集
用时:3分钟
以往的数据集和标注都要耗费数月完成,有了上文提到的网站插件我们可以很轻松的获得想要的数据集。修改插件,加一个简单的for循环,使得其自动输出1万个验证码图片以及对应的字符。图片为PNG格式,图片的名字即为图片中所包含的字符,也就是true label真实标签。
生成的样本数据集如下图所示。
为了避免“鼓励”大家去破解上面的网站,作者开放了源码和对应的1万张样本。链接在文末,需要的小伙伴们自行下载哦~
Part
4
任务:字符分割
用时:5分钟
有了样本数据集,马上我们就可以建立网络模型来训练了。然而在训练开始之前,还要解决一个问题。现有的样本是由4个字符组成的,如果放在一起直接识别精度会有一定的限制,所以首先将字符分隔开,进行逐字符识别是比较优化的方案。
那么,要怎么分割字符呢?
不要告诉我你想用YOLO啊,虽然YOLO肯定可以实现,但是也太大费周折了吧,俗话说叫大炮打苍蝇了~
那么,是不是简单的平均分割就ok呢?当然也不行啊,字符在水平方向和垂直方向的分布都是不均匀的,平均分割会带来字符残缺的问题。如下图。
答案是用OpenCV。OpenCV是常用的图像处理库,在图像分析时,我们经常需要检测颜色相同的像素块。同理,在验证码中,字符是黑色的,背景是白色的,利用OpenCV内置的findContours()函数可以很容易检测像素块的边缘区域,实现分割。
原始的验证码图像像素如下图:
我们将灰色图像转为黑色,也就是将验证码转换为纯黑和纯白两种颜色,从而更容易寻找边缘轮廓,转换后的黑白图像如下图。
使用OpenCV的findContours()函数检测结果如下:
接下来我们按照顺序把单个字符区域与单个字符标签对应起来就好了。
到这里就可以进行下一步了吗?当然不是,每一步做完都要充分检查,确保无误后再开展后续的工作,这样不会带来误差积累,也是很好的工作习惯。
在检查分割的字符时,我们发现了下述问题,有些字符是连在一起的,很难通过边缘轮廓将其分隔开。如下图:
如果直接分割结果将会是一坨:
这种情况肯定要纠正的,不然后果不堪设想,那要怎么纠正呢?
这里的方法就简单粗暴了,如果一个图片中经过OpenCV之后分割出来3个字符,那么肯定存在着字符粘连的问题。宽度过大的字符分割我们认为其存在着粘连,并且简单直接的把它平均分为两部分。
最后整理一下字符,我们把相同的单个字符放在同一个路径下,每个路径包含多个该字符的样本,如下图,图中展示了字符W的样本,1万张样本里共有1147个W字符。
Part
5
任务:训练模型
用时:5分钟
经过上述处理过程后,我们的问题简化成了单个字符的识别问题,与著名的MNIST识别类似,只是多了些许字母而已。由于我们的任务比较简单,所以所需的网络模型也可以简单点,文中作者所用的模型包含2个conv卷积层和2个fc全连接层。
使用Keras构建网络的代码如下,有效代码才十几行,好简洁有木有。
# Build the neural network!
model = Sequential()
# First convolutional layer with max pooling
model.add(Conv2D(20, (5, 5), padding="same", input_shape=(20, 20, 1), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
# Second convolutional layer with max pooling
model.add(Conv2D(50, (5, 5), padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
# Hidden layer with 500 nodes
model.add(Flatten())
model.add(Dense(500, activation="relu"))
# Output layer with 32 nodes (one for each possible letter/number we predict)
model.add(Dense(32, activation="softmax"))
# Ask Keras to build the TensorFlow model behind the scenes
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
模型构建完毕后我们就可以开始训练了,训练代码如下。
对于这种简单的任务,迭代次数也不需要很多就可以收敛。最终作者用了10个Epoch,训练精度达到了100%。
# Train the neural network
model.fit(X_train, Y_train, validation_data=(X_test, Y_test), batch_size=32, epochs=10, verbose=1)
Part
6
终极目标:破解验证码
好了,万事俱备,我们可以正式开始破解验证码了!激不激动,兴不兴奋!
首先,基于前文所使用的网络查件,获取真正的验证码图片。
接着,将验证码图片用OpenCV和粘连矫正分割为4个单独的字符
然后,将4张单个字符的图片输入到训练好的网络模型中
最后,网络输出预测结果,如下图所示。
我们也可以直接在命令行看结果,如图。
怎么样,你学会了吗?感兴趣的小伙伴也可以试一下更高级别的图片验证码 ,轻松破解12306登录限制。
最后祝愿所有的小伙伴们都能如愿买到回家的车票~
文章代码和数据集链接:
https://s3-us-west-2.amazonaws.com/mlif-example-code/solving_captchas_code_examples.zip
英文原文链接:https://medium.com/@ageitgey/how-to-break-a-captcha-system-in-15-minutes-with-machine-learning-dbebb035a710
以上就是全部内容啦~关注“习悦智能”,获取更多行业新鲜资讯~
投稿渠道:mjl@zhthinkjoy.com
加入习悦:contact@zhthinkjoy.com
商务合作:business@zhthinkjoy.com
以上是关于15分钟实现数字验证码自动识别,基于OpenCV+Keras的主要内容,如果未能解决你的问题,请参考以下文章