驗證碼識別是一個適合入門機器學習的項目,之前用knn 做過一個很簡單的,這次用svm來實現。svm直接用了開源的庫libsvm。驗證碼選的比較簡單,代碼也寫得略亂,大家看看就好。
1. 爬取驗證碼圖片
1 import urllib 2 from urllib import request 3 4 5 def download_pics(pic_name): 6 url = 'http://smart.gzeis.edu.cn:8081/Content/AuthCode.aspx' 7 res = request.urlopen(url) 8 get_img = res.read() 9 10 with open( 'D:\python\驗證碼\%s.jpg'%(pic_name),'wb') as f: 11 f.write(get_img) 12 13 if __name__ == '__main__': 14 for i in range(100): 15 pic_name = i 16 download_pics(pic_name)
2. 二值化
接下來要做的工作就是二值化驗證碼,所謂二值化,就是將每一個像素點用0或1來表示,圖像的每個像素點都有rgb三個值,我們首先轉化成灰度圖,這樣每個像素點就只有一個灰度值了。接下來根據自己設定的閾值來確定每個像素點是該為0還是為1。
我的思路是首先將圖像轉化為array處理,當然完全可以直接圖像處理。
1 def binarization(im): #二值化 2 imgry = im.convert('L') 3 imgry = np.array(imgry) #將圖像轉化為數組 4 height, width = imgry.shape 5 #f = open('s.txt','w') 6 for i in range(height): 7 for j in range(width): 8 gray = imgry[i,j] 9 if gray <= 220: #閾值設為220 10 imgry[i, j] = 0 11 else: 12 imgry[i, j] = 1 13 #f.write(str(imgry[i,j])) #輸出到txt查看 14 #f.write('\n') 15 ''' 16 plt.figure('') 17 plt.imshow(imgry, cmap='gray') 18 plt.axis('off') 19 plt.show() 20 ''' 21 return imgry
在二值化處理之后,處理結果如下所示:
在txt的結果如下所示,可以很明顯的看到0413:
3. 去除噪點
在二值化之后,還存在一個問題就是圖像之中還有許多黑點,這成為噪點,是干擾項,去除噪點有很多不同的方法,由於我只是一個小菜鳥,所以我就用了最簡單的8-鄰域去除噪點法。依次檢查每個像素點周圍8個點的情況,如果黑點少於閾值時,那么就可以認為該點是噪點。其實這樣的處理效果是比較差的,只是適用於去除小點,但是對於干擾線條這種可能就沒什么作用了。
1 def noiseReduction(imgry): #去除噪點 2 global dx, dy 3 height, width = imgry.shape 4 for i in range(height): 5 for j in range(width): 6 cnt = 0 7 if imgry[i, j] == 1: #白點不用管 8 continue 9 else: 10 for k in range(8): 11 x = dx[k] + i 12 y = dy[k] + j 13 if x < 0 or x >= height or y < 0 or y >= width: 14 continue 15 if imgry[x, y] == 0: 16 cnt += 1 17 if cnt < 4: #周圍少於4點就算噪點 18 imgry[i, j] = 1 19 return imgry
處理之后可以明顯的看到黑點基本上都被處理掉了。
4. 圖片分割
接下來要做的就是將這四個數字分割開來形成訓練集,這個操作並不難。因為這些驗證碼的位置都是差不多的,如果驗證碼字符位置比較亂的話就會比較麻煩。。
1 def cutImg(img): #圖像切割 2 s = 12 3 w = 40 4 h = 81 5 t = 0 6 cut_img = [] 7 for i in range(4): 8 pic = img.crop((s + w * i, t, s + w * (i + 1), h)) 9 cut_img.append(pic) 10 return cut_img
5. 圖片分類
這個步驟的目的就是人為的給訓練集打上標簽。 將相同的數字放在同一個文件夾下面。
6. 訓練模型
訓練模型很簡單,因為直接就是使用libsvm庫,我們只需要按照數據格式生成一些特征值即可。在切割完圖片並保存之后,我發現我圖片的像素值有略微的改變,可能是重新保存了的原因,所有我這里又進行了一次二值化。。。
這里說明依稀libsvm數據格式的要求:
[label] [index:value] [index:value] [index:value].....
每一個數據都是這樣的格式,label是標簽,[index:value]是數據的特征值,index就是從0開始的編號,value是特征值。
在這里對於每一張圖片,我就把特征值設為每行每列的黑點個數了。如第一個特征值就是第一行黑點個數。。。
1 import os 2 from PIL import * 3 from PIL import Image 4 import numpy as np 5 from libsvm.python.svmutil import * 6 from libsvm.python.svm import * 7 8 9 address = 'D:\python\驗證碼-sort\\' 10 f = open('train.txt', 'w') 11 12 def get_feature(dir, file): 13 f.write(dir) 14 im = Image.open(address + dir +'\\' + file) 15 imarr = np.array(im) 16 height, width = imarr.shape 17 for i in range(height): 18 for j in range(width): 19 gray = imarr[i,j] 20 if gray <= 150: 21 imarr[i, j] = 0 22 else: 23 imarr[i, j] = 255 24 im = Image.fromarray(imarr) 25 count = 0 26 width, height = im.size 27 for i in range(height): 28 c = 0 29 for j in range(width): 30 if im.getpixel((j, i)) == 0: c += 1 31 f.write(' %d:%d'%(count, c)) 32 count += 1 33 for i in range(width): 34 c = 0 35 for j in range(height): 36 if im.getpixel((i, j)) == 0: c += 1 37 f.write(' %d:%d'%(count, c)) 38 count += 1 39 f.write('\n') 40 41 def train_svm_model(): 42 y, x = svm_read_problem('train.txt') 43 model = svm_train(y, x) 44 svm_save_model('model_file', model) 45 46 if __name__ == '__main__': 47 dirs = os.listdir(address) 48 for dir in dirs: 49 files = os.listdir(address + dir) 50 for file in files: 51 get_feature(dir, file) 52 train_svm_model()
7. 測試模型
用測試數據對模型進行測試。
1 from libsvm.python.svmutil import * 2 from libsvm.python.svm import * 3 import image_slove 4 5 if __name__ == '__main__': 6 model = svm_load_model('model_file') 7 yt, xt = svm_read_problem('test.txt') 8 p_label, p_acc, p_val = svm_predict(yt, xt, model)
還是不錯的,畢竟驗證碼很簡單。。。
8. 預測驗證碼
終於走到最后一步了,得到一張驗證碼后先按照之前的操作根據該圖片生成特征值,這里標簽還是需要的,可以隨便填一個,反正這個不重要。或許有別的方法,反正我暫時還不知道。
1 from libsvm.python.svmutil import * 2 from libsvm.python.svm import * 3 from PIL import Image 4 import image_slove 5 6 if __name__ == '__main__': 7 ''' 8 在這里處理圖片生成特征值 9 ''' 10 model = svm_load_model('model_file') 11 yt, xt = svm_read_problem('predict.txt') 12 p_label, p_acc, p_val = svm_predict(yt, xt, model) 13 print('該驗證碼為:', end='') 14 for label in p_label: 15 print(int(label), end='')
最后成功的驗證出來了。
9. 總結
通過這個實驗對於驗證碼識別流程有了一定的了解,這次也是直接使用了支持向量機,后續需要稍微學習一下。