前些时间,因为工做关系,须要作验证码识别相关的工做,因为以前没有接触过这方面,因此一切重头开始,通过一个月的查阅资料、作实验尝试,总算做出了一个能够用的东西。下面尝试总结一下这一个多月学习的东西,能够加深下本身的印象,也能够向你们分享一下心得。java
验证码的主要用途是用来区分对象是机器仍是人。由于若是对象是机器的话,就能够在短期内提交大量的表单,从而形成破坏,甚至能够形成一些没法估量的损失。若在提交以前有验证码的话,就能够在必定程度上防止这种事情发生。而了解验证码识别的原理,能够有效预防生成的验证码被识别,从而加大自身的安全性,故“未知攻,焉有防”。git
下面就开始对如何识别验证码做出介绍,同时本文中只会给出思路和部分代码,避免引发一些没必要要的麻烦。github
这里咱们指的验证码是字符和数字的组合,其余验证码并不在此作介绍。咱们引用的例子是这张验证码:
算法
目前验证码识别的原理通常是将验证码中的字符按照顺序分割开来,以后对图片中的每一个字符进行识别,以后将字符识别结果组合在一块儿,即为识别的结果。这个过程大体有如下的步骤:安全
1.去噪,二值化markdown
2.分割字符网络
3.标准化字符学习
4.识别对象
各个步骤的具体描述以下所示:blog
标题的意思是将去除验证码图片中干扰部分,以后只留下背景和内容,并将内容所有处理为一种颜色(缘由在4中讲解)。
二值化处理:
去噪处理:
此处的原理是验证码图片中内容和无用部分通常会有一个颜色上明显的区分,若是内容和其余区别不明显,会给人带来不好的用户体验。咱们能够经过取色器观察内容和其余的颜色值,从而找出一个阀值,在此阀值上的颜色都为内容,阀值下都是无用的部分。以后遍历图片,保留阀值上的颜色,将其置为一种颜色,将阀值下的颜色置为背景色。这样图片中就只有两种颜色,就完成了二值化的过程。
在很多时候,验证码中会有躁点之类的噪音存在,因此在此也须要将这些噪音去除。在此介绍去除噪点的方法:判断此像素的相邻像素,若是相邻超过N(这须要看具体状况)个像素与此像素颜色不同,就能够认为此像素为噪点,将其置为背景色便可。下面是检查相邻像素的代码,在检查以前已经将图片进行了二值化。
下面来进行第二步,字符分割
字符分割一直是验证码识别的重点和难点,只有将字符分割成功,才有可能进行到下面的步骤。可是目前没有通用的分割方法,通常是根据具体的状况来具体应用。本文介绍一种简单状况下的处理方法:扫描法。使用这种方法的前提是验证码中各个字符没有链接。效果以下:
分割后:
具体的方法是这样的:
已知图片的高为y,宽为x。咱们将图片的左下角视为坐标(0,0),左上角坐标视为(0,y),右下角坐标视为(x,0)。
以后沿着图片的x轴,在x轴上的某点,对0到y-1高度的像素进行遍历,来获取每一个字符的开始和结尾。若是某一列中像素都是背景色,同时下一列中有内容,则此列为字符的开始。获取字符结尾的原理与此类似。
在此步骤中通常作如下(不限于)几件事情:
验证码中的字符通常会有各个角度的倾斜,从而相同的字符在通过不一样角度的倾斜后,也会呈现出不一样的姿态。扶正倾斜的字符,能够减小字符倾斜对识别形成的影响。
扶正能够采用旋转卡壳算法。能够将图片旋转,由-30度开始,到30度结束,选宽度最小的一张做为扶正的图片。
扶正的效果:
有些验证码中的字符会粗细不均,将其细化后,能够减小采样,从而减小粗细不均对识别形成的影响。
有些验证码中的相同的字符会有大小不一样的形式,因此须要将其处理为一种形式,理由同上。
这里简单介绍下缩放图片的一个java开源库--Scalr.使用很是方便,缩放代码以下所示:
这里就到了最后的一步,目前比较有效的方法是采用采用神经网络进行识别,训练量大的话识别率会很客观。关于神经网络在此不作赘述,网上关于神经网络的资料员有不少,这里介绍一个java的神经网络库:Encog。这里是图片识别的示例,修改下就可使用了。目前来看,识别效果还能够。
以上就是验证码识别的一种方法,关于增强验证码安全的能够阅读参考资料中的文章,里面总结的很全面,我就不在这里献丑了。
水平有限,多多指教。
谢谢
欢迎关注个人微博,ID:小牛_yetuweiba。
参考资料:
http://drops.wooyun.org/tips/141。
文中的思路主要来自此篇文章,这是一篇几乎毫无水分的文章。在此感谢做者。
最后,博客园的markdown的语法真折磨人。