(一)python爬蟲驗證碼識別(去除干擾線)
(一)python爬蟲驗證碼識別(去除干擾線)
1.開發環境與工具
- python27:sklearn、pytesser、opencv等
- pycharm
- windows7
2. 資料集
用request庫爬蟲抓取某一網站驗證碼1200張,並做好標註
3.驗證碼識別大概步驟
- 轉化成灰度圖
- 去背景噪聲
- 圖片分割
(1)轉化成灰度圖
im = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
(2)去除背景噪聲
驗證碼去除干擾線的思想可參考連結:驗證碼去除干擾線
本文所使用的去除背景噪聲的方法:
認真觀察我們的實驗資料,發現根據
博主認真想了下,先轉化成灰度圖,再通過影象分割把圖片分割一下,去除掉邊框和部分噪聲,這樣就分成了4張圖,然後統計每張圖的灰度直方圖(自己設定bins),找到第二大所對應的畫素範圍,即某一畫素範圍內畫素數第二多所對應的畫素範圍(畫素最多的應該是白色,空白處),取畫素範圍中位數mode,然後保留(mode+-biases)的畫素。這樣就可以將大部分噪聲去除掉啦。
(這段描述有點複雜,需要一定的影象基礎,不懂的,可以看程式碼del_noise()方法)
4. 實驗方法
(1)使用Google的pytesser識別圖片方法,準確率在50%左右
pytesser環境配置參考 https://www.cnblogs.com/lcosima/p/7138091.html
(2)使用機器學習方法KNN,準確率在99.6%
pip install sklearn
5.pytesser方法
- 這裡im_cut是指:分割好驗證碼後,傳入的子圖片
def del_noise(im_cut):
''' variable:bins:灰度直方圖bin的數目
num_gray:畫素間隔
method:1.找到灰度直方圖中畫素第二多所對應的畫素,即second_max,因為影象空白處比較多所以第一多的應該是空白,第二多的才是我們想要的內容。
2.計算mode
3.除了在mode+-一定範圍內的,全部變為空白。
'''
bins = 16
num_gray = math.ceil(256 / bins)
hist = cv2.calcHist([im_cut], [0], None, [bins], [0, 256])
lists = []
for i in range(len(hist)):
# print hist[i][0]
lists.append(hist[i][0])
second_max = sorted(lists)[-2]
bins_second_max = lists.index(second_max)
mode = (bins_second_max + 0.5) * num_gray
for i in range(len(im_cut)):
for j in range(len(im_cut[0])):
if im_cut[i][j] < mode - 15 or im_cut[i][j] > mode + 15:
# print im_cut[i][j]
im_cut[i][j] = 255
return im_cut
# 替換文字
def replace_text(text):
text = text.strip()
text = text.upper()
rep = {'O': '0',
'I': '1',
'L': '1',
'Z': '7',
'A': '4',
'&': '4',
'S': '8',
'Q': '0',
'T': '7',
'Y': '7',
'}': '7',
'J': '7',
'F': '7',
'E': '6',
']': '0',
'?': '7',
'B': '8',
'@': '6',
'G': '0',
'H': '3',
'$': '3',
'C': '0',
'(': '0',
'[': '5',
'X': '7',
'`': '',
'\\': '',
' ': '',
'\n': '',
'-': '',
'+': '',
'*': '',
'.': '',
';': ''
}
#判斷是否有數字,有數字直接返回第一個數字,不需要字元替換
print text
if len(text) >= 1:
pattern = re.compile(u'\d{1}')
result = pattern.findall(text)
if len(result) >= 1:
text = result[0]
else:
# 字元替換,替換之後抽取數字返回
for r in rep:
text = text.replace(r, rep[r])
pattern = re.compile(u'\d{1}')
result = pattern.findall(text)
if len(result) >= 1:
text = result[0]
return text
- 主方法
#im_cut = [im_cut_1, im_cut_2, im_cut_3, im_cut_4]
for i in range(4):
im_temp = del_noise(im_cut[i])
im_result = Image.fromarray(im_temp.astype('uint8'))
#使用pytesser識別
text = image_to_string(im_result)
#做文字替換處理
text_rep = replace_text(text)
#獲得預測結果
pre_text.append(text_rep)
pre_text = ''.join(pre_text)
- 結果
6.KNN分類(sklearn)
(1)先轉成灰度圖,去背景噪聲,分割1200張已標註好的圖片,得到4800張子圖片;
(2)用knn訓練分類器,訓練集:測試集=0.8,訓練結果精度達到99%以上;
(3)使用訓練好的模型,進行實際驗證碼預測,效果不錯。
# -*-coding:utf-8-*-
import numpy as np
from sklearn import neighbors
import os
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.externals import joblib
import cv2
if __name__ == '__main__':
# 讀入資料
data = []
labels = []
img_dir = './img_train_cut'
img_name = os.listdir(img_dir)
# number = ['0','1', '2','3','4','5','6','7','8','9']
for i in range(len(img_name)):
path = os.path.join(img_dir, img_name[i])
# cv2讀進來的圖片是RGB3維的,轉成灰度圖,將圖片轉化成1維
image = cv2.imread(path)
im = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
image = im.reshape(-1)
data.append(image)
y_temp = img_name[i][-5]
labels.append(y_temp)
# 標籤規範化
y = LabelBinarizer().fit_transform(labels)
x = np.array(data)
y = np.array(y)
# 拆分訓練資料與測試資料
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)
# 訓練KNN分類器
clf = neighbors.KNeighborsClassifier()
clf.fit(x_train, y_train)
# 儲存分類器模型
joblib.dump(clf, './knn.pkl')
# # 測試結果列印
pre_y_train = clf.predict(x_train)
pre_y_test = clf.predict(x_test)
class_name = ['class0', 'class1', 'class2', 'class3', 'class4', 'class5', 'class6', 'class7', 'class8', 'class9']
print classification_report(y_train, pre_y_train, target_names=class_name)
print classification_report(y_test, pre_y_test, target_names=class_name)
# clf = joblib.load('knn.pkl')
# pre_y_test = clf.predict(x)
# print pre_y_test
# print classification_report(y, pre_y_test, target_names=class_name)
結果截圖:
ps:在執行過程中,程式還可能會幫你檢測出人工標錯的喲!
喜歡就點個贊吧~~~一起在程式猿路上行走!!!加油
——肆無忌憚走天下