每个人都不喜好验证码(CAPTCHA) - 那些令人讨厌的图像中包含了你必须精确输入的文本,只有输入成功后才能访问网站。 验证码旨在通过验证你是一个真实的人来防止机器(蠕虫)自动填写表格。 但随着深度学习和打算机视觉的兴起,现在很随意马虎利用机器来自动识别验证码了。
我一贯在阅读Adrian Rosebrock的书《打算机视觉:基于Python的深度学习》。在这本书中,Adrian利用机器学习技能绕过了E-ZPass New York网站的验证码:
Adrian访问不了用来天生验证码图像的运用程序源代码。因此为了实现上述系统,他只能下载数百个样本图像,人工识别答案,然后作为演习数据来演习他的机器学习系统。

但是如果我们想要绕过的是一个开源的验证码系统,是不是有更好的办法?
我在WordPress.org插件重心搜索\"大众captcha\公众。 排在最前面的被称为\"大众Really Simple CAPTCHA\公众,有总计超过100万次的安装:
最主要的是,它自带源码!
由于我们有了用来天生验证码的源代码,以是这该当很随意马虎绕过去。 为了让事情更有寻衅性,让我们给自己一个韶光限定。 能在15分钟内绕过这个验证码系统吗? 让我们试试!
主要声明: 这绝不是对\"大众Really Simple CAPTCHA\"大众插件或其作者的批评。 插件作者自己说,不能连续担保这个别系所天生验证码的安全性,建议你利用别的替代品。 这只是一个有趣、快速的技能寻衅。 但是,如果你是上述100多万用户之一,大概你该当考虑切换到其他的产品:)
寻衅为了组织一个攻击操持,让我们看看Really Simple CAPTCHA天生的验证码图像。 在演示网站上,我们看到:
好,验证码图片看起来包含四个字母。 让我们在其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个可能的字母和数字须要进行识别。 没问题!
已用时:2分钟
工具集在连续之前,让我们来看一下办理这个问题要用到的工具:
Python 3:Python是一款有趣的编程措辞,有大量用于机器学习和打算机视觉的精良的库。
OpenCV:OpenCV是一个盛行的打算机视觉和图像处理框架。 我们将利用OpenCV来处理验证码图像。 它有一个Python的API,以是我们可以直接从在Python中利用它。
Keras:Keras是一个用Python开拓的深度学习框架。 Keras的存在简化了深度神经网络的定义、演习和利用,常日你只须要编写少量的代码即可得到一个网络。
TensorFlow:TensorFlow是Google的机器学习库。 我们利用Keras进行开拓,但Keras实际上本身并没有实现神经网络的逻辑。 相反,它利用后真个TensorFlow库来完成繁重的事情。
好,回到寻衅!
要开拓任何机器学习系统,都须要演习数据。 为了识别验证码,我们须要如下的演习数据:
由于我们有WordPress插件的源代码,因此可以对其进行修正,天生10,000张验证码图像以及对应的精确答案。
只须要几分钟的代码编写,添加一个大略的'for'循环,我就得到了一个文件夹与演习数据 - 10,000个PNG文件,文件名便是精确的答案:
这是我不会给你示例代码的唯一部分。 我们写这篇文章的目的是为了学习互换,我不肯望你真的跑去给那些WordPress网站发送垃圾邮件。 不过,我会给你末了天生的10,000张图片,以便你可以重现我的结果。
已用时:5分钟
简化问题现在有了演习数据,我们可以直策应用它来演习一个神经网络:
有了足够的演习数据,这种方法可能行的通 - 但我们可以让问题变得更随意马虎办理。 问题越大略,演习数据越少,我们须要的打算能力就越少。 毕竟我们只有15分钟!
幸运的是,验证码图像总是由四个字母组成。 如果我们能够以某种办法切分图像,使每个字母位于单独的图像,那么我们只须要演习神经网络一次识别一个字母:
我没有韶光浏览10,000个演习图像,并在Photoshop中手动将它们分割成单独的图像。 这可能须要几天的韶光,而我只剩下10分钟了。 而且我们不能将图像分成四个相同大小的块,由于验证码会将这些字母随机放置在不同的水平位置:
幸运的是,我们仍旧可以自动实行此操作。 在图像处理中,我们常常须要检测具有相同颜色的像素团(blob)。 这些像素团周围的边界被称为轮廓 (contour)。 OpenCV有一个内置的findContours()函数,可以用来检测这些连续的区域。
我们将从一个原始的验证码图像开始:
然后,将图像从灰度转换为黑白(阈值化:thresholding ),这样就很随意马虎找到连续的区域:
接下来,我们将利用OpenCV的findContours()函数来检测包含相同颜色像素团的单独部分:
然后,将每个区域保存为一个单独的图像文件就很大略了。 而且由于我们知道每个图像该当包含从左到右的四个字母,以是可以利用这些知识来标注字母。 只须要按顺序用适当的字母名称保存每个图像字母即可。
但是等等 - 我创造一个问题!
有时候验证码有这样的重叠字母:
这意味着我们终极提取到的是两个字母拼在一起的区域:
如果我们不处理这个问题,终极只能得到质量不高的演习数据。 我们须要办理这个问题,以免欠妥心让机器把这两个重叠的字母识别为一个。
这里有个大略的技巧,便是说,如果一个轮廓区域的宽度比高度大很多,就意味着很可能把两个字母挤在一起了。 在这种情形下,我们可以将连体字母拆分成两半,并将其视为两个单独的字母:
现在有了提取单个字母的方法,让我们在所有的验证码图像上运行这个代码。 目标是网络到每个字母的不同变革形态。 我们可以将每个字母保存在单独的文件夹中,以保持良好的数据样本组织。
下面是我提取所有字母后,W文件夹的样子:
已用时:10分钟
建立和培养神经网络由于只须要识别单个字母/数字的图像,因此我们不须要一个特殊繁芜的神经网络。 识别字母比识别阿猫阿狗这样的繁芜图像要随意马虎得多。
我们利用具有两个卷积层(convolutional layer)和两个全连接层(fully-connected layer)的大略卷积神经网络:
如果你想知道卷积神经网络的事情事理,以及为什么它特殊适用于图像识别任务,请查看Adrian的书或我以前的文章 。
在Keras中定义这个神经网络只须要几行代码:
# Build the neural network!model = Sequential()# First convolutional layer with max poolingmodel.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 poolingmodel.add(Conv2D(50, (5, 5), padding=\"大众same\"大众, activation=\公众relu\公众))model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))# Hidden layer with 500 nodesmodel.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 scenesmodel.compile(loss=\公众categorical_crossentropy\公众, optimizer=\"大众adam\"大众, metrics=[\"大众accuracy\"大众])
现在可以演习了!
# Train the neural networkmodel.fit(X_train, Y_train, validation_data=(X_test, Y_test), batch_size=32, epochs=10, verbose=1)
经由10轮演习后,我们达到了将近100%的准确度。现在,我们该当能够自动绕过这个验证码了!
我们做到了!
已用时:15分钟(喔!
)
现在我们有了一个演习好的神经网络,用它来识别验证码非常大略:
从利用此WordPress插件的网站抓取真实的验证码图像。
利用我们用来创建演习数据集的相同方法,将验证码图像分解为四个独立的字母图像。
让神经网络对每个字母图像做一个单独的预测。
利用四个预测字母作为验证码的答案。
狂欢吧!
下面的动图展示了我们的模型是如何识别验证码的:
或者,命令行输出:
试试看!
如果你想亲手考试测验一下,可以在这里获取源代码 。 它包括10,000个示例图像和本文中每个步骤的所有代码。 在运行之前,请先查看个中包含的README.md文件。
但是,如果想理解每一行代码,我强烈建议你找这本书《打算机视觉:基于Python的深度学习》来看看。 它深入很多的细节,并且有大量的详细示例。 这是迄今为止我所见过的唯一的一本书,即讲解了机器学习的运行事理,也讲解了如何利用机器学习技能来办理现实中的难题 。 试一试!
如果你喜好这篇文章,别忘了关注我!
原文:How to break a CAPTCHA system in 15 minutes with Machine Learning