一次簡單粗暴的驗證碼識別經歷

  最近爬取一個網站時,遇到了驗證碼的狀況。驗證碼形式是計算題,10之內的數字(可能有少許十以上),加減乘計算。html

  開始懶得搞,第一批須要的數據量並不大,想着直接平臺打碼。python

  緣由是之前登陸新浪微博的時候也是直接打碼的,比較熟練,也簡便。但打碼成本比較高,後續需求量大,因此最好本身能識別。ide

  看了幾篇識別驗證碼的文章,基本處理流程以下:字體

    1.去掉顏色;灰度處理,二值化等網站

    2.去掉干擾,降噪;噪點,線等的處理spa

    3.切割字符,單獨識別code

    4.訓練字體htm

    5.自動識別blog

  我須要識別的驗證碼形式以下:教程

  

  通過反覆試驗,定了如下幾個步驟:

    1.去除干擾,將圖片中的干擾點線等刪除

    2.識別圖片,使用pytesseract識別圖片

    3.計算結果,使用識別出來的字符數字計算結果

  以上是代碼的流程,實際操做中還須要訓練字體,這裏留在最後說明。

  使用這張圖片爲例,簡要介紹一下流程:

  以上幾個步驟的基本操做思想:

    1.去噪。一般的思想是根據像素點的相鄰關係等去除,我在識別的過程當中發現,這裏的圖片像素值比較單一,

                  噪點的顏色比數字的顏色要淺。簡單打印一下RGB值,能夠發現除了(255,255,255)表示的白色之外,大體顏色值有如下幾種:

      (140,140,140)

      (112,112,112)

         (117,117,117)

                   因而,我經過判斷像素點的RGB值,把以上幾種點用白色替換(即去掉該點),示例圖片轉換後獲得圖像以下

         

                   能夠看到這個結果,基本上就能夠拿去識別了。這也是爲何我稱此次驗證碼識別爲簡單粗暴。

    2.識別。識別使用的是tesseract直接識別,沒什麼好講的,貼幾個連接本身看。

             關於數據訓練,也是直接照着教程作的,連文件名都沒改,所幸過程當中並未出錯。

 

from pytesseract import image_to_string
im = Image.open("1_no_noise.png")
str_img = image_to_string(im, lang='eng', config='-psm 6')
print('識別爲:%s' % str_img)

 

 

                   使用原裝英文庫識別結果以下:

識別爲:7x3:?

              使用訓練過的庫識別:

from pytesseract import image_to_string
im = Image.open("1_no_noise.png")
str_img = image_to_string(im, lang='fontyp', config='-psm 70')
print('識別爲:%s' % str_img)

# 識別爲:7x3=?

                  ※在使用過程當中,嘗試修改config的配置,能夠幫助更準確地識別。

    3.計算結果。計算結果就是拿識別出來的字符串,簡單拆分,分析操做符,作出對應計算,由於識別的時候沒有切圖,因此直接切割字符串。

               在切割字符串以後的數字轉換作了簡單的矯正。

  總體代碼以下:

 

# encoding=utf-8
__author__ = 'Masako'

from PIL import Image
from io import BytesIO
from pytesseract import image_to_string

NOISE_RGB_LIST = [117, 140, 112]    # 噪點像素值列表
OPERATE_LIST = ['+', 'x', 'X',  '-', '']

# 去除噪點 def del_point(img): pix = img.load() width = img.size[0] height = img.size[1] for x in range(width): for y in range(height): r, g, b = pix[x, y] # print(r, g, b) if r in NOISE_RGB_LIST: pix[x, y] = 255, 255, 255 return img # 數字識別 def data_ident(data_str): num = None if data_str == 'q': num = 9 elif data_str == 'z' or data_str == 'Z': num = 2 elif data_str == 'G': num = 6 else: try: num = int(data_str) except Exception as e: print("can't identify:" + data_str) return num # 計算結果 def deal_img_str(img_str): # str_list = img_str.split(' ') # print(str_list) calculate_result = None try: data_str = img_str[:img_str.rindex('=')] except Exception as e: print(img_str) return # print(data_str) for operate in OPERATE_LIST: if operate in data_str: # 判斷操做符 data_list = data_str.split(operate) if len(data_list) == 2: # 正確分割時的處理 data_left = data_ident(data_list[0]) data_right = data_ident(data_list[1]) if data_left and data_right: if operate == '+': calculate_result = data_left + data_right elif operate == 'x' or operate == 'X': calculate_result = data_left * data_right else: calculate_result = data_left - data_right if calculate_result != None: break return calculate_result def img_to_captcha_code(img_content): image_data = BytesIO(img_content) im = Image.open(image_data) im = del_point(im) str_img = image_to_string(im, lang='fontyp', config='-psm 70') result = deal_img_str(str_img) return result if __name__ == "__main__": im = Image.open("a.jpg") im = del_point(im) im.save('a_no.jpg') str_img = image_to_string(im, lang='fontyp', config='-psm 70') print('識別爲:%s' % str_img)

  參考文章連接:

    https://www.cnblogs.com/qqandfqr/p/7866650.html

    http://www.cnblogs.com/cnlian/p/5765871.html

相關文章
相關標籤/搜索