1. 程式人生 > >Python3使用tesserocr識別字母數字驗證碼

Python3使用tesserocr識別字母數字驗證碼

一、背景

        最近有個需求是從一個後臺的留言網站爬取留言資料,後臺管理網站必然涉及到了登入,登入就有個驗證碼的問題必須得解決,由於驗證碼是從後端生成的,並且不瞭解其生成規則,那就只能通過影象識別技術來做驗證碼識別了!通過查閱資料發現Python中的的tesserocr這個庫好像使用的比較多,所以對這個庫進行了一番研究,並且實現了那個後臺網站驗證碼的識別。

二、準備工作

1. 安裝tesserocr

      由於我使用的Python版本是python3.5,所以一下所有操作都是基於python3的,如果有python2的同學,可以找找其他教程~~

      首先需要下載tesseract,它為tesserocr提供底層支援。具體下載官方路徑:https://github.com/UB-Mannheim/tesseract/wiki,選擇對應的系統版本,可以選擇一個相對不帶dev的穩定版本下載,如:tesseract-ocr-setup-3.05.02-20180621.exe。然後一路安裝,唯一記得勾選Additional language data(download),勾選可能會用到的語言tessdata,如簡體、繁體中文,數學模組等,不需要全選,下載tessdata的時間會比較長。

     然後安裝python3對應的tesserocr庫,通常我們安裝庫的方法是使用命令pip install tesserocr,但是這裡會報錯:“error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools", 

這個時候不宜直接去下載Microsoft Visual C++ Build Tools,而是使用原始的whl檔案方式安裝。tesserocr 的whl官方檔案下載路徑:https://github.com/simonflueckiger/tesserocr-windows_build/releases,下載本地環境對應的whl檔案,如我的是window64位系統,python版本是3.5。下載完後,使用cd跳轉到whl檔案所在目錄,然後 執行 ”pip install tesserocr-2.2.2-cp35-cp35m-win_amd64.whl“,即可輕鬆完成安裝。

 

   緊接著用例子驗證如何使用:我們找到一個驗證碼圖片:image.jpg,下載到本地磁碟,用程式碼進行驗證:

1 import tesserocr
2 from PIL import Image
3 image=Image.open('image.jpg')
4 print(tesserocr.image_to_text(image))

    不出意外,首次執行總是不順利,相信我遇到的坑大多數人都會遇到,大抵錯誤類似:

 Traceback (most recent call last):
  File "G:\pythonSources\my12306/obtain_message\test.py", line 4, in <module>
    print(tesserocr.image_to_text(image))
  File "tesserocr.pyx", line 2400, in tesserocr._tesserocr.image_to_text
RuntimeError: Failed to init API, possibly an invalid tessdata path:  “本地某個路徑”

    有個比較簡單粗暴的解決方法是把安裝好的Tesseract-OCR下的tessdata資料夾整個拷貝到提示的那個路徑中,親測有效。

2. 安裝opencv

    由於驗證碼需要做一些優化處理,方便更加容易被tesserocr識別,所以需要使用opencv來做一些特殊的處理,安裝opencv比較簡單,直接pip install opencv-python即可。

三、識別過程

1. 將圖片變成黑白圖片

    我需要爬取資料的這個後臺網站驗證碼是黃底白字的,這種色差較小的tesserocr識別起來比較困難,稍微試了一下,基本上沒怎麼識別對過。。。所以我們需要先將圖片變成色差最大的黑白圖片。初始圖片見下圖:

   首先,將圖片變成灰色,並將灰色圖片儲存起來方便後續做對比,變成灰色以後的圖片如下:

   變成灰色後,通過畫素點的顏色值將灰色部分的背景變成白色,白色的具體內容變成黑色,這樣白底黑字的黑白圖片就有了:

   處理成黑白圖片的實現程式碼如下:

1 img = Image.open(self.code_path)
2 # 將圖片變成灰色
3 img_gray = img.convert('L')
4 img_gray.save('../images/code_gray.png')
5 # 轉成黑白圖片
6 img_black_white = img_gray.point(lambda x: 0 if x > 200 else 255)
7 img_black_white.save('../images/code_black_white.png')

2. 去除圖片噪點

       圖片轉成黑白以後,一些雜點也隨著我們的主體內容變成了黑色的點,這樣對識別的效果也有較大的影響,所以需要想辦法將這些干擾點去掉。這裡就需要藉助opencv的功能了,在使用opencv去除噪點之前,需要先將圖片做灰值化以及二值化處理,具體程式碼如下所示:

1         # opencv處理
2         img_cv = cv2.imread('../images/code_black_white.png')
3         # 灰值化
4         im = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY)
5         # 二值化
6         cv2.adaptiveThreshold(im, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1)

       基本處理之後,就需要消除噪點了,消除噪點的原理也比較簡單,就是遍歷圖片的每一個畫素點,找到其上下左右四個畫素點位置的顏色,如果這四個點中白色點的數量大於2則說明這個點是噪點,需要將該點的顏色直接置為白色點,在邊框位置的畫素點也直接置為白色,因為主要內容一般都是在圖片中間的。以下為處理噪點的程式碼:

 1 # 噪點處理
 2 def interference_point(img):
 3     filename = '../images/code_result.png'
 4     h, w = img.shape[:2]
 5     # 遍歷畫素點進行處理
 6     for y in range(0, w):
 7         for x in range(0, h):
 8             # 去掉邊框上的點
 9             if y == 0 or y == w - 1 or x == 0 or x == h - 1:
10                 img[x, y] = 255
11                 continue
12             count = 0
13             if img[x, y - 1] == 255:
14                 count += 1
15             if img[x, y + 1] == 255:
16                 count += 1
17             if img[x - 1, y] == 255:
18                 count += 1
19             if img[x + 1, y] == 255:
20                 count += 1
21             if count > 2:
22                 img[x, y] = 255
23     cv2.imwrite(filename, img)
24     return img, filename

    噪點處理完畢之後,就是一張非常清晰的圖片了:

    這個時候就可以直接使用tesserocr來識別了,具體識別的方式如下:

1 tesserocr.image_to_text(img_result)

   識別測試結果如下:

       經過多次識別驗證測試,另外也由於這個驗證碼的字型相對比較規範,所以成功率是相當的高了,即使偶爾的一次失敗,我們也是可以進行重試就又成功了。哈哈, 差不多就是這個樣子啦,歡迎大家指正文中的問題~~不多說了,我要去使用新學的技術去做“壞事”了!