JS识别图片验证码

很久很久之前(大概在五年前),我就在想,能不能在前端用js识别图片验证码,直到现在,这个功能也未实现,因为做了一半发现实现不了,就放弃了,这里只是记录一下当时的思路和方向;

后来整理到 Github 上了,源代码DEMO 可点击查看;

当时的验证码比较简单,干扰因素比较少,字符也基本没有重叠,所以就想用Canvas对图片进行处理,与标准字符进行比较,找出最像的字符:

  • 将图片转成黑白;
  • 去除噪点;
  • 找到字符边界,拆分出单个字符;
  • 对字符进行分割;
  • 计算出每个分割出的区域中,有效像素的占比=有效的像素数/总的有效像素数;
  • 与26个英文字母大小写、数字的有效像素占比进行比较,得出最接近的值;

像 0、O、o,以及8,x 这种对称的字符应该很难识别;

后来发现,字体、字号大小、加粗与否、去除噪点的算法、旋转角度等,都会造成误差,影响精度;实际中,暂不考虑旋转角度和字体,如果字体固定、字符不旋转的情况下能识别出来,再加角度、换字体进行计算、比较就可以了,虽然计算量很大,但只计算一次就够了,把数据存储起来;

将图片转成黑白

将图片绘制到 Canvas 中,获取每个像素点的信息,将非白色的点统一转成黑色;

去除噪点

当时在网上找的实例图片,噪点都是一个个像素点,所以我的策略也比较简单,就是找孤立的像素点,然后删掉(改成白色);

找字符边界

去除噪点后,从左向右,找第一个出现黑色点的列(字符的左边界),然后再向后找,找到之后第一个纯白色点的列(字符的右边界),第一个字符就找到了;

然后循环上面的操作,找到图片中所有的字符;

*实际操作中,先按一张图片中只有一个字符来处理的;

分割

将找到的字符二维数组数据进行拆分,按照整除的原则(单数的话手动+1变成双数),比如 8行6列的数组,可以按照将行分成4组、列分成3组,这样就得到了12个分割区;比如下面是A的拆分:

分割的组数量并非越大越精确,因为验证码字符本身有效字符就比较少,如果再切分的太细,反而会放大误差;

计算

计算出每个分割区中有效像素的占比,有效像素的占比=有效的像素点数/总的有效点数;

比较

将26个英文字母大小写、数字绘制到 Canvas 中,也按照相同的分割规则,计算每个分割区的有效像素占比(这个占比可以只计算一次,然后存储起来,之后直接拿来用),然后与目标值进行比较,得出最接近的值;

如果这篇文章对你有用,可以点击下面的按钮告诉我

0

发表回复