注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

ㄨiao愛

转载技术文档

 
 
 

日志

 
 

转:简单的验证码识别技术,学习笔记  

2012-06-05 14:23:09|  分类: php |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

作者:白菜 发布时间:June 15, 2011 分类:编程算法

Screenshot-C12-Aurora.pngScreenshot-C12-Aurora.png

原理

对于简单的验证码,使用的原理也相当的简单。
现在有两个长度一致的二进制的数字,1110111011101和1010111011100,比较他们的相似度可以使用XOR运算!

1110111011101 XOR 1010111011100 = 0100000000001

结果中,1的数目越小,相似度越高。现在比较两张单色的图片,也可以使用这样的方法。这两张图必须是规格相同的,
compare.png
把两张单色的图片进行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()

Screenshot-compare.bmp.png


上面两个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个验证码!
观测样本
Screenshot-J6NLD.png.png
为了看清楚点,去除噪点,转换成黑白单色图!
Screenshot-4.png

通过观察一大堆验证码,得出如下结论:
1. 验证码不复杂,只使用了一种字体类型
2. 验证码不复杂,只使用了一种字体大小
3. 验证码不复杂,只使用了一种字体颜色
4. 验证码不复杂,每张由5个字母或数字构成,5个字母或数字的位置都是固定的
5. 验证码不复杂,没有图片的歪曲变形,没有干扰线条或图案

因此,这堆验证码非常适合识别验证码技术的初学者小试牛刀!

提取字模

既然已经知道每个字母或数字在图片中的具体位置,就可以从这些样本之中,把它们提取出来!!!
每个字模的大小都是8x10,宽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个字模。
Screenshot-font.png
从这些字模之中,每个数字或字母,我们只需要一个看上去比较标准的就够了。飞之同学说,如果知道它是什么字体,就可以直接用脚本生成一堆标准的模板就行了,省去自己去匹配的麻烦呢。

识别程序

代码的流程比较简单,先加载标准的模板,然后读取一张验证码的图片,裁剪出这张图片的每个数字或字母的局部图,然后跟我们的标准模板进行比较,统计像素点不相同的个数。然后把每个字模的统计结果进行排序,不相同点个数最小的,相似度就应当是最高的了!!!

下面的代码把识别出来的验证码另存到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)
效果图片:
Screenshot-result-700x472.png

50个验证码中,有两三个出现了把E识别成B的现象,其他问题都不大,识别成功率超过90%。

小结

机器识别验证码,能够超过90%的正确率已经是相当不错的了。有的验证码肉眼识别也达不到90%,所以有的网站提供的验证码,我要更换好几次!!!
如果是用来刷票,超过50%的识别率都已足够啦!

这次试验只是用来进行入门,复杂一些的验证码就不能只是这么做了,还需要考虑很多问题,对图片预处理复杂很多吧,识别的时候也可以考虑加入学习功能(例如神经网络)来逐步提高识别的成功率。因此,仅仅是菜鸟入门,大牛可以无视之。

转自:http://xiaoxia.org/?p=4168

标签: none

  评论这张
 
阅读(321)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017