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


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

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

  原因是以前登錄新浪微博的時候也是直接打碼的,比較熟練,也簡便。但打碼成本比較高,后續需求量大,所以最好自己能識別。

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

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

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

    3.切割字符,單獨識別

    4.訓練字體

    5.自動識別

  我需要識別的驗證碼形式如下:

  

  經過反復試驗,定了以下幾個步驟:

    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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM