1. 程式人生 > >(一)python爬蟲驗證碼識別(去除干擾線)

(一)python爬蟲驗證碼識別(去除干擾線)

(一)python爬蟲驗證碼識別(去除干擾線)

1.開發環境與工具

  • python27:sklearn、pytesser、opencv等
  • pycharm
  • windows7

2. 資料集

avatar這裡寫圖片描述這裡寫圖片描述這裡寫圖片描述這裡寫圖片描述這裡寫圖片描述這裡寫圖片描述這裡寫圖片描述
用request庫爬蟲抓取某一網站驗證碼1200張,並做好標註

3.驗證碼識別大概步驟

  • 轉化成灰度圖
  • 去背景噪聲
  • 圖片分割
(1)轉化成灰度圖
im = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
(2)去除背景噪聲

驗證碼去除干擾線的思想可參考連結:驗證碼去除干擾線
本文所使用的去除背景噪聲的方法:
     認真觀察我們的實驗資料,發現根據

線降噪方法來去除噪聲是不可行的,因為我們的圖片干擾線很粗,和數字差不多粗。那再認真觀察一下,1個數字的顏色都是一個‘“色”,那麼是否可以跟據顏色來分呢?
     博主認真想了下,先轉化成灰度圖,再通過影象分割把圖片分割一下,去除掉邊框和部分噪聲,這樣就分成了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:在執行過程中,程式還可能會幫你檢測出人工標錯的喲!
這裡寫圖片描述
這裡寫圖片描述

喜歡就點個贊吧~~~一起在程式猿路上行走!!!加油
——肆無忌憚走天下