尝试了一下bilibili的验证码破解

最近几天没事就打算尝试破解bilibili的验证码试试,当然了没事也是只是心情问题,事情永远都是干不完了啊(笑)。

几行python的事情:

import os  
import urllib  

save_path = 'img/'  
url="http://www.bilibili.com/captcha"
ct=761;

if __name__ == "__main__":  
    while True:
        try:
            fn="__%04d.png"%ct  
            fp = urllib.urlretrieve(url, save_path+fn);  
            print ct
        except IOError:  
            print "download error!" + str(ct)
        ct+=1

然后爬个1k张验证码图片:
QQ拼音截图未命名

然后对验证码分析可以知道,B站的验证码由”1 2 3 4 5 6 8 9 E F G H J K L M N P Q R T U V W X Y”组成,排除了”0 O Z I S”等几个比较容易混淆的数字和字母,然后”ABCD”也被排除了的样子……

一直以来做OCR识别倒是其次,分割是最困难的,当然了google去年爆出的captcha系统以及一些分割和识别一起做的深度学习的算法不在讨论之内。毕竟咱们不是专门搞captcha的,用最基础的神经网络搞一遍就OK了,写出来的算法也只能针对bilibili的验证码,不具备普适性。

那么先来看分割吧,通过对B站验证码观察可以得到以下信息:
1、背景有黑白2中颜色,而字符的颜色各种各样
2、字符是5个,有时候字符可能相互连接起来
3、有噪音点、噪音线

经过分析之后,我大概有了分割出5个字符的思路,拿这张验证码举个例子吧:
captcha (8)

因为背景和字符前景颜色都可能变化,基于灰度值来提取前景显然是不现实的,既然区别是颜色就把RGB转化到HSV颜色空间,利用Hue来做分割。我们可以料到背景是一个颜色,前景字符是一个颜色,那么Hue的灰度直方图必然是2个波峰,最高的波峰肯定是背景,第二个波峰就是前景的5个字符了。为了验证思路是否正确,我开始码代码了。环境是VS2012,图像处理库是OpenCV2.4.9,按照上面的思路写下来结果证明是可行的:
1、把上面的”2499M”转化到HSV空间是这样的:
hsv

2、提取hue通道是一个不那么明显的灰度图像:
2

3、计算一个256通道的直方图,找到第二个波峰,然后根据第二个波峰去hue里面找前景字符,效果还行:
3

4、对前景进行连在一起的前5大块分割出来,拿去喂分类器……当然了还得把背景里面的那些噪声点去掉,而且由于拿去喂分类器的是一个矩形的图片,有时候虽然2个字符分开了,但是2个字符对应的矩形框仍然可能包含另一个字符,比如:
captcha (12)
所以把字符块分别复制到一块黑色的背景上,然后再用矩形框取字符比较好。

当然了这是理想状态,实际上字符与字符连接的情况挺多的,这就导致了分割失败的情况,这种情况我们暂时不考虑,继续往下走。

之后简单的用一个神经网络来对标记好的字符进行训练,这个已经没什么好说的了,当然了做一个样本正确率评价比较好。大家可能觉得前面分割出来的字符各种变形,而且可能有噪声线、噪声点,不处理一下就之间拿去喂分类器可能导致效果不好。其实经过我的训练评价,发现那么一点噪声完全不用例会,字符变形更是完全没问题(实际上也没法做什么处理)。

这1k多张图片怎么得到样本是个大问题,为了方便采样我用MFC写了个界面,界面里把上面的字符分割逻辑也写进去了,用鼠标去点前景,然后输入对应的字符(后来为了更方便的采样干脆把识别也加进来了,自动确定对应的字符,错了自己去修正,当然了采集的越多越准确),就能保存该训练样本,大概是这样的(我正在采集那个2字,然后右边上方是处理过后的前景,下面选择2字就ok了):
4

现在采集工具搞定了,采集字符样本很快的,基本几秒采一张,2k张样本1、2个小时就搞定了。搞定了之后,还是得对训练效果做个评价,于是写了一个评价正确率的来看看效果如何:
4

5

有几张拿来训练但是识别又失败的图片,总体效果还过得去。

现在拿来试试识别效果如何:

6

 
7

8

9

这些前3个验证码的识别是成功的,最后一个没法成功分割导致识别失败,但是经过测试发现只要5个字符没有连接情况都能成功分割出5个字符来的,也就是都能成功识别出来的。但是一旦有任意2个字符连接起来的情况(实际上挺多的,遇到这个就没办法了),所以说还是那句话搞captcha就在与分割。处理字符连接的方法我目前倒是能想到几个,但是没那个时间+精力去写了。嘛,今天就到这里了,算是把搞验证码的方法过了一遍了。

发表评论

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