須要識別的驗證碼圖像,其中包含 4 個字符(數字字母)python
驗證碼圖片來源:http://my.cnki.net/elibregist...網絡
前面兩步都是對圖像進行識別前處理,目的是提升計算機識別的準確度,畢竟計算機自己不能理解圖像,一個像素值的微小變化都有可能致使錯誤識別機器學習
import tesserocr from PIL import Image image = Image.open("87FW.jpg") # 灰度化 image = image.convert("L") # 二值化,傳入的是數字 1,默認閾值是 127。通常不推薦使用,由於不夠靈活 # image = image.convert("1") # 另外一種二值化。自定義灰度,將灰度值在 115 以上的設置 1(白色),其它設爲 0(黑色),至關於將閾值設置成了 115 table = [1] * 256 for i in range(256): table[i] = 0 if i > 115: break image = image.point(table, "1") print(tesserocr.image_to_text(image))
打印:工具
87FW
所謂的閾(yu)值是指將不一樣的像素值分開的那個臨界值學習
上面的代碼沒有保存圖片,爲了直觀得看到通過不一樣的處理後圖像的區別,下面展現的是兩張圖像分別是灰度處理和二值化(閾值 115)後的圖像測試
下面將每種不一樣閾值的圖像保存至本地,主要代碼以下:優化
... image = Image.open("87FW.jpg") image = image.convert("L") table = [1] * 256 for i in range(256): table[i] = 0 image.point(table, "1").save(f"87FW_{i}.jpg")
閾值爲 0 表明將全部像素處理成白色(沒有黑色);閾值爲 255 表明將全部像素處理成黑色。spa
能夠發現閾值設置得越低,白色越多,能看獲得的驗證碼(黑色)就少了,由於大部分灰度都處理成白色;反之,若閾值設置越大,黑色越多,更多的干擾像素處理成和驗證碼同樣的黑色。.net
如下是將上面不一樣閾值的圖片製做成的一個 gif 動態圖像,能夠看到若是閾值設定在 0 至 255 這個過程當中,驗證碼會呈現出不一樣效果code
閾值是一個很難把控的關鍵,閾值設置大或小都會影響識別的準確性,如下是遍歷全部閾值,測試閾值在哪一個區間能夠識別出正確的驗證碼。注:因爲沒有作優化,整個過程會比較慢
>>> for i in range(256): ... if tesserocr.image_to_text(Image.open(f"87FW_{i}.jpg")).strip()=="87FW": ... print(i, end=" ") ... 109 110 112 113 114 115 116 117 118 119 120 122 123 124 169 170 171 172 173
在 256 個閾值中只有 19 個(不足 7.42%)閾值能夠正確識別出驗證碼,仔細察覺能夠發現閾值區間被分紅了多個,分別是 109~1十、112~120、122~12四、169~173,說明閾值區間不必定具備連續性。更糟糕的是,不一樣的驗證碼圖片,能準確識別出其中驗證碼的閾值的數量、區間範圍、區間數等都極可能不一樣。固然還有不少問題,好比選擇一個「不恰當」的閾值致使圖像處理過分,只識別出其中 3 個字符,不要試圖隨機添加一個字母或數字,由於須要考慮具體是哪一個位置的字符沒識別出來,這樣瞎猜幾乎是很難一次就命中的,好點的作法是:當識別出來的字符不足時能夠嘗試換一個閾值處理圖像,因此能識別出驗證碼是機率事件。畢竟在正常的人機識別中,識別一個驗證碼一般只有一次機會,識別錯了就會出現新的驗證碼,沒有換閾值再從新試一次的機會,不過好在一般閾值的範圍都是能夠縮小的,好比能夠忽略小於 70 和大於 200 的這些圖像處理過分的閾值(正常人都很難識別是什麼數字、字母),這樣能命中的機率就會大大提升。
image.convert("1") 的默認閾值是 127,在上面 19 個能夠準確識別驗證碼的閾值中沒有 127,這也就是爲何直接使用 image.convert("1") 方法二值化的圖像沒法被準確識別出其中的驗證碼
上面的驗證碼還算容易處理的,若是干擾像素的灰度值與驗證碼灰度差異比較大,可用上面的方法;但若是遇到干擾線條的灰度與驗證碼差很少、驗證碼重疊等狀況,上面對圖像僅作簡單處理的方法就很難奏效了。這時就須要用到機器學習技術對識別器進行訓練,據說識別率幾乎 100%!