以前寫過一個刷校內網的人氣的工具,Java的(以后再也不行Java程序了),里面用到了驗證碼識別,那段代碼不是我自己寫的:-) 校內的驗證是完全單色沒有任何干撓的驗證碼,識別起來比較容易,不過從那段代碼中可以看到基本的驗證碼識別方式。這幾天在寫一個程序的時候需要識別驗證碼,因為程序是Python寫的自然打算用Python進行驗證碼的識別。 以前沒用Python處理過圖像,不太了解PIL(Python Image Library)的用法,這幾天看了看PIL,發現它太強大了,簡直和ImageMagic,PS可以相比了。(這里有PIL不錯的文檔)
上面這些處理使用Python才幾行: im = Image.open(image_name) im = im.filter(ImageFilter.MedianFilter()) enhancer = ImageEnhance.Contrast(im) im = enhancer.enhance(2) im = im.convert('1') im.show() 接下來就是提取這些數字的字模,使用shell腳本下載100幅圖片,抽出三張圖片獲取字模: #!/usr/bin/env python #encoding=utf-8 import Image,ImageEnhance,ImageFilter import sys image_name = "./images/81.jpeg" im = Image.open(image_name) im = im.filter(ImageFilter.MedianFilter()) enhancer = ImageEnhance.Contrast(im) im = enhancer.enhance(2) im = im.convert('1') #im.show() #all by pixel s = 12 #start postion of first number w = 10 #width of each number h = 15 #end postion from top t = 2 #start postion of top im_new = [] #split four numbers in the picture for i in range(4): im1 = im.crop((s+w*i+i*2,t,s+w*(i+1)+i*2,h)) im_new.append(im1) f = file("data.txt","a") for k in range(4): l = [] #im_new[k].show() for i in range(13): for j in range(10): if (im_new[k].getpixel((j,i)) == 255): l.append(0) else: l.append(1) f.write("l=[") n = 0 for i in l: if (n%10==0): f.write("\n") f.write(str(i)+",") n+=1 f.write("]\n") 把字模保存為list,用于接下來的匹配; 提取完字模后剩下來的就是對需要處理的圖片進行與數據庫中的字模進行匹配了,基本的思路就是看相應點的重合率,但是由于噪點的影響在對(6,8)(8,3)(5,9)的匹配時容易出錯,俺自己針對已有的100幅圖片數據采集進行分析,采用了雙向匹配(圖片與字模分別作為基點),做了半天的測試終于可以實現100%的識別率。 #!/usr/bin/env python #encoding=utf-8 import Image,ImageEnhance,ImageFilter import Data DEBUG = False def d_print(*msg): global DEBUG if DEBUG: for i in msg: print i, print else: pass def Get_Num(l=[]): min1 = [] min2 = [] for n in Data.N: count1=count2=count3=count4=0 if (len(l) != len(n)): print "Wrong pic" exit() for i in range(len(l)): if (l[i] == 1): count1+=1 if (n[i] == 1): count2+=1 for i in range(len(l)): if (n[i] == 1): count3+=1 if (l[i] == 1): count4+=1 d_print(count1,count2,count3,count4) min1.append(count1-count2) min2.append(count3-count4) d_print(min1,"\n",min2) for i in range(10): if (min1[i] < = 2 or min2[i] <= 2): if ((abs(min1[i] - min2[i])) < 10): return i for i in range(10): if (min1[i] <= 4 or min2[i] <= 4): if (abs(min1[i] - min2[i]) <= 2): return i for i in range(10): flag = False if (min1[i] <= 3 or min2[i] <= 3): for j in range(10): if (j != i and (min1[j] < 5 or min2[j] <5)): flag = True else: pass if (not flag): return i for i in range(10): if (min1[i] <= 5 or min2[i] <= 5): if (abs(min1[i] - min2[i]) <= 10): return i for i in range(10): if (min1[i] <= 10 or min2[i] <= 10): if (abs(min1[i] - min2[i]) <= 3): return i #end of function Get_Num def Pic_Reg(image_name=None): im = Image.open(image_name) im = im.filter(ImageFilter.MedianFilter()) enhancer = ImageEnhance.Contrast(im) im = enhancer.enhance(2) im = im.convert('1') im.show() #all by pixel s = 12 #start postion of first number w = 10 #width of each number h = 15 #end postion from top t = 2 #start postion of top im_new = [] #split four numbers in the picture for i in range(4): im1 = im.crop((s+w*i+i*2,t,s+w*(i+1)+i*2,h)) im_new.append(im1) s = "" for k in range(4): l = [] #im_new[k].show() for i in range(13): for j in range(10): if (im_new[k].getpixel((j,i)) == 255): l.append(0) else: l.append(1) s+=str(Get_Num(l)) return s print Pic_Reg("./images/22.jpeg") 這里再提一下驗證碼識別的基本方法:截圖,二值化、中值濾波去噪、分割、緊縮重排(讓高矮統一)、字庫特征匹配識別。 |
|