前言

因为校园网的 wifi 连接了一段时间会断开,博主就想自己弄一个 wifi 客户端出来,能自动断线重连。但是功能太少,UI 难设计,想了许久,觉得就弄个查询用户余额的,然后就有了下面的界面

获取用户的网费余额,要另外登陆 wifi 的自助平台,然后从里面的用户资料里面获取。

基本思路就是,用 HttpClient 来模拟登陆,然后用 jsoup 解析返回的 html 代码,从中获取用户余额。


可是 pst 的登陆表单里面有个难搞的东西,,就是验证码,总不能让用户每次登陆都输入一遍验证码吧,所以下面就针对这个网站的验证码做解释

正文

(跳过一系列的抓包、分析)

有些代码是以前参考了别人的,因为太久了,目前找不到出处


0. 下载

写个方法下载图片,看得见的东西比较好操作,方便后面要做的

下载一张


1. 去噪点

从上面的图能看到,这网站的验证码像素有点低,而且噪点也很多,去噪点这一步会很艰难

用 QQ 或微信的截图工具能看到图片每个像素的 RGB,不难发现字体部分的 RGB 要比附近的噪点要深,而且 R、G、B 都大约在 30 以下。

那么去噪点的方法就是把那些 R、G 或 B 大于 30 的像素都换成 RGB(255,255,255) 白色

上面的代码,原本应该是检查上下左右的像素是不是字体颜色的,如果不是,证明这个是噪点,然后换成白色。不过这里的像素有点低,两个字母之间也就一两个像素的距离,用那种方法的话,后面就很难切割了

把刚刚下载的图片去噪

顺便把不是纯白色的像素块替换成纯黑色的,后面用来判断


2. 切割

OCR 验证码识别最简单的就是把 4 个字体切成 4 块, 然后一块块和字典对比

最简单的切割就是那种固定位置的验证码,只需要算好大小,直接拿起来就切,例如正方教管理务系统的验证码(这个已破,要源码的留下评论)
  

但像现在这种形状大小角度都不变,唯独位置变化的验证码,如何切割好,成了提高识别率的关键

  

(其实就是不等宽字体的锅)

如果把它转化成瀑布图呢

现在就很明确了,只要把白色的全切开了,剩下 4 块黑色的就是我们想要的。但是,这里我们要的是这些黑色的区域,而不是要这瀑布图来识别,虽然可以,但是在这像素特别低的情况下识别率很低,i、l、1、t,w、m,h、n 这些非常难识别,所以还是转化成二值化再识别吧

下面先把他切了

看看效果


3. 二值化

说白了就是把每块像素根据颜色转换成 0 和 1

输出如下

这每一行都是这个字符的特征码,只要对比这个特征码,就能识别到这个字符了


4. 训练

其实就是人工识别上一步得出的特征码,并保存起来,组成” 字典”,用于下一步的机器识别。

有个小技巧

就是做一个 GUI,只显示一个输入框和一个图片,手动输入验证码,然后把输入的验证码用 HttpClient 构造一个表单 post 到网页去验证,返回验证结果,正确的话就处理好并将结果输出到 txt 文件,就可以像流水线一样生产了 [滑稽笑]


5. 对比

这没什么好说的了,直接上代码

最后,就算是完成了。识别率不是 100 都没问题,识别率不高,字典来补是吧。其实只要能识别,加个递归效果就好很多了

博主有个陋习,很少写注释,但是这些代码都挺简单的而且都很入门的,不难看懂

One Reply to “基于 Java 的 OCR 验证码识别 (验证码位置不定、大小形状不变)”

发表评论

电子邮件地址不会被公开。 必填项已用*标注