陕西移动网上营业厅验证码识别方案

// 转载请注明出处  鲲鹏数据 http://www.site-digger.com

 

陕西移动网厅:http://www.sn.10086.cn/

验证码生成链接:https://sn.ac.10086.cn/SSO/servlet/CreateImage

验证码示例:

该验证码较为简单:内容为四位纯数字(0-9),单个字符宽度固定,字符垂直位置固定,背景有很少的杂色。

 

识别方案:

1)提取特征库。

下载足够多的验证码图片(至少包含0-9所有数字)。截取每个数字(8×20像素矩阵)单独存储作为特征库。

实现方法如下(用到了Python的PIL库):

view plaincopy to clipboardprint?

  1. import Image  

  2.   

  3. def make_lib():  

  4.     img = Image.open('code.jpg')  

  5.     gray_img = img.convert('1')   

  6.     gray_img.save('gray.jpg')  

  7.       

  8.     width, height = gray_img.size  

  9.       

  10.     # find each number  

  11.     w = 0  

  12.     while w < width:  

  13.         column = []  

  14.         for h in range(height):  

  15.             column.append(gray_img.getpixel((w, h)))  

  16.   

  17.         # begining of a number  

  18.         if sum(column)/height < 245:  

  19.             box = (w, 0, w+820)  

  20.             region = gray_img.crop(box)  

  21.             region.save('%s.jpg' % w)  

  22.             w = w + 10  

  23.         else:  

  24.             w = w + 1  

注:img.convert('1')作用是将彩色图二值化(只有0和255两种像素值)。

 

原理?

按列扫描,依次找到每个数字的起始位置,截取宽度为8像素,高度为20像素的区域保存。

 

如何识别字符的开始位置?

测试发现,列像素之合小于245的是有数字的部分。

 

最终建立如下特征库:

 

2) 匹配方案。

 

按列扫描,依次找到每个数字的起始位置,获取宽度为8像素,高度为20像素的矩阵A。

拿矩阵A一次跟特征库矩阵进行对比,以差值数(详见下面Captcha类中的_cmpmatrix方法)最小的特征字符为匹配字符。

 

下面给出我们实现的Captcha类。

view plaincopy to clipboardprint?

  1. # coding: utf-8  

  2. # captcha.py  

  3. # http://www.site-digger.com  

  4. # hello@site-digger.com  

  5. # Identify captcha on http://www.sn.10086.cn/  

  6.   

  7. import Image  

  8.   

  9. class Captcha:  

  10.     def __init__(self):  

  11.         self.imglib = {}  

  12.         self._loadlib()  

  13.       

  14.     def _loadlib(self):  

  15.         """Load characteristic image lib"""  

  16.           

  17.         import os  

  18.         if not os.path.exists('imglib'):  

  19.             print 'Can not find imglib dir.'  

  20.             return  

  21.           

  22.         for i in range(10):  

  23.             self.imglib[i] = []  

  24.             img = Image.open('imglib/%d.jpg' % i).convert('1')  

  25.             width, height = img.size  

  26.             for w in range(width):  

  27.                 # store all pixels in a column  

  28.                 column = []  

  29.                 for h in range(height):  

  30.                     column.append(img.getpixel((w, h)))  

  31.                 self.imglib[i].append(column)  

  32.           

  33.     def _cmpmatrix(self, listA, listB):  

  34.         """Return the count of difference between two list"""  

  35.           

  36.         if len(listA) != len(listB): return  

  37.           

  38.         num = 0  

  39.         for i, column in enumerate(listA):  

  40.             if len(column) != len(listB[i]): return  

  41.             for j, pixel in enumerate(column):  

  42.                 if pixel != listB[i][j]:  

  43.                     num += 1  

  44.         return num  

  45.       

  46.     def _whichnum(self, piexls_matrix):  

  47.         """Identify single number"""  

  48.   

  49.         minnum = None  

  50.         index = 0  

  51.         for i in range(10):  

  52.             ret = self._cmpmatrix(self.imglib.get(i, []), piexls_matrix)  

  53.             if ret!= None:  

  54.                 if minnum == None or minnum > ret:  

  55.                     minnum = ret  

  56.                     index = i  

  57.     

  58.         if minnum != None:  

  59.             return str(index)  

  60.         else:  

  61.             return '?'  

  62.       

  63.     def identify(self, filepath=None, fileobj=None):  

  64.         """Identify captcha"""  

  65.   

  66.         if filepath:  

  67.             img = Image.open(filepath)  

  68.         elif fileobj:  

  69.             img = Image.open(fileobj)  

  70.         else:  

  71.             print 'Invalid input.'  

  72.             return  

  73.           

  74.         img = img.convert('1')  

  75.           

  76.         width, height = img.size  

  77.           

  78.         w = 0  

  79.         number = ''  

  80.         while w < width:  

  81.             column = []  

  82.             for h in range(height):  

  83.                 column.append(img.getpixel((w, h)))  

  84.   

  85.             # begining of a number  

  86.             if sum(column)/height < 245:  

  87.                 piexls_matrix = []  

  88.                 for i in range(8):  

  89.                     piexls_column = []  

  90.                     for j in range(20):  

  91.                         piexls_column.append(img.getpixel((w + i, j)))  

  92.                     piexls_matrix.append(piexls_column)  

  93.                       

  94.                 number += self._whichnum(piexls_matrix)  

  95.                 w = w + 10  

  96.             else:  

  97.                 w = w + 1  

  98.   

  99.         return number  

  100.          

  101. if __name__ == '__main__':  

  102.     """Test performance of Captcha Class"""  

  103.     captcha = Captcha()  

  104.   

  105.     try:  

  106.         import urllib2  

  107.         response = urllib2.urlopen('https://sn.ac.10086.cn/SSO/servlet/CreateImage')  

  108.         open('code.jpg''wb').write(response.read())  

  109.         Image.open('code.jpg').show()  

  110.         print captcha.identify('code.jpg')  

  111.     except Exception, e:  

  112.         print 'Download captcha fail.', e  

 

 

测试用例说明: 动态下载陕西移动网厅的验证码,首先显示,然后调用Captcha类对其进行识别、打印。效果如下图所示。

 

 

 

 

 

 

特别说明:该文章为鲲鹏数据原创文章 ,你除了可以发表评论外,还可以转载到你的网站或博客,但是请保留源地址,谢谢!!(尊重他人劳动,你我共同努力)

转载于:https://my.oschina.net/xakzp/blog/472086

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值