字符圖像識別——數字字母混合

須要識別的驗證碼圖像,其中包含 4 個字符(數字字母)python

驗證碼

驗證碼圖片來源:http://my.cnki.net/elibregist...網絡

思路

  1. 灰度化:將圖像轉爲灰度圖像,即一個像素只有一種色階(有 256 種不一樣灰度),值爲 0 表示像素最黑,值爲 255 表示像素最白。
  2. 二值化:將圖像轉爲黑白圖像,即一個像素只有黑白兩種狀態,不是黑就是白,沒有灰色,值爲 0 表示像素最黑,值爲 1 表示像素最白.
  3. 圖像轉字符串:利用工具將圖像中的字符串識別出來

前面兩步都是對圖像進行識別前處理,目的是提升計算機識別的準確度,畢竟計算機自己不能理解圖像,一個像素值的微小變化都有可能致使錯誤識別機器學習

代碼

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)後的圖像測試

灰度處理

二值化(閾值 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%!

參考資料:

  • 《Python3網絡爬蟲開發實戰》——8.1 圖形驗證碼的識別
相關文章
相關標籤/搜索