最近看到一篇关于PHP验证码的原理分析,很精彩!昨天试着写了一写,感觉样本足够的话准确率确实很不错。

他的原理大致是:图像二值化,去噪,分隔字符,比对字典。

作者大人有些地方写得很含糊,我来总结概括一下:

 

我们先用干扰少一些的进行举例。

第一:图像二值化

根据每个像素的RGB来判断是背景还是字符。此做法可行的原因是制作验证码的时候,背景是不能过于干扰认证字符的。

在例子中的验证码的RGB三个的大致范围是:红大于100,绿大于150,蓝大于220。我们将处于这个范围的RGB的像素点设为1,其余为0。运行部分代码我们可以得到如下的结果:

我们大致可以看出验证码的样子。

第二步:去噪

在图像二值化的过程中,或许有一些背景的干扰素也会存在于我们所列举的RGB的范围内。我们为了在分割的时候准确率更高,我们需要去噪。我们去噪的方法也很简单,判断噪点位置的上、下、右、左、上右、上左、下右、下左八个方向是否含有有1值。若八个方向都不存在1值那么说明此处为噪点,我们将他设为0。(貌似这个图例的干扰素比较单纯,所以基本上不用早点处理都可以得到比较好的二值化图像)

第三步:分割

先左右分割,确定每个字符的边界(如果是上线分割就不好确定边界了)。然后上下分割,确定字体长度。

第四步:分隔字符

这里涉及一个问题,如果验证码在制作的时候有少量粘连情况怎么处理?

我们采用了一个很简单的算法,就是用字符的开始边界减去结束边界,如果超过了字符的宽度阀值,那么我们就取边界只差的/2当作第一个字符的结束边界。

第五步:对比字典

字典需要大量的样本作为前提,特别是对于有旋转或是干扰素比较复杂的。如果对于无旋转且干扰素比较单一(如样本),那么只需要包括所有数字和大小写字母即可。

下面是程序运行图,可以看到,判断的准确率很高。

 貌似在网上能找到作者写的代码,但是太复杂了。我把他进行了重写了一下。

我的代码请戳:http://www.rayfile.com/files/984ee291-4430-11e2-94e6-0015c55db73d/

另外,代码中使用的是数组方式存储字典数据,其实更好的方式是上载数据库中。

另外为了方便,需要破解的对象我采用的是某一个样本文件。但是方法本身没问题,就是对字典中所有字符二值的逐一匹配。

建议:

对于验证码的制作,通过上面的分析,我们应该多增加粘连字符或者进行随机的缩放。例如像QQ或是淘宝,虽然验证码看起来比较简单,但是由于粘连数比较大,就增大了字符的分割难度。

 

 

虽然都是单一色调,RGB范围也比较稳定,但是4个字符互相直接粘连,让破解准确率降低。(请忽视51CTO的水印)

而对于下列的验证码形式,用以上的办法可以达到90%的破解率!所以请各位看官多多注意。