基於Python簡單影象處理,識別驗證碼!
基本識別原理概述:
1、每一幅影象在構成上,都是由一個個畫素組成的矩陣,每一個畫素為單元格。
2、 彩色影象的畫素的由三原色(紅,綠,藍)構成元組,灰度影象的畫素是一個單值,每個畫素的值範圍為(0,255)。
問題來源
某系統門戶登陸介面如下:
現在我們要實現自動的驗證碼識別。
影象特徵
首先,我們仔細觀察下這個驗證碼影象,可以發現一些固定特徵:
1、驗證碼中的字元數始終為6,並且是灰度影象。
2、字元間的間隔看起來每次都一樣。
3、 每個字元都是完全定義的。
4、影象有許多雜散的黑暗畫素,以及穿過影象的線條作為干擾因素。
影象分析
所以我最終下載了一個這樣的影象,並使用一個工具(binary-image)以二進位制形式視覺化影象(0表示黑色,1表示白色畫素)。
我的觀察沒錯,影象尺寸為45x180,每個字元分配30個畫素的空間來適配,從而使它們間隔比較均勻。
因此,取得了驗證碼識別路上的第一步,結果:
把影象裁剪成6個不同的部分,每個部分的寬度為30畫素。
python影象裁剪
我們璇兒Python作為原型語言,因為它的庫最容易使用和部署。
經過簡單搜尋,我找到了PIL庫。還用到了Image模組,用來操作影象進行字元裁剪並將影象作為載入為數字矩陣。
字元部分裁剪
影象裁剪的語法是:
from PIL import Image
image = Image.open("filename.png")
cropped_image = image.crop((left, upper, right, lower))
比如要裁剪第一個字元:
from PIL import Image
image = Image.open("captcha.png").convert("L")
cropped_image = image.crop((0, 0, 30, 45))
cropped_image.save("cropped_image.png")
得到的影象為:
我將他打包到一個迴圈中,編寫了一個簡單的指令碼,從該站點獲取500個驗證碼影象,並將所有裁剪後的字元儲存到一個資料夾中。回顧我們上一部分觀察到的特徵第三點,每個字元都有明確定義。
影象去雜,清理干擾因子
為了"清理"影象中的裁剪掉干擾因素(刪除不必要的線和點),我們使用一個很簡單的演算法:
字元中的所有畫素都是純黑色(0)。如果它不是完全黑色的,將它當成白色的。因此,對於值大於0的每個畫素,將給其重新賦值為255。使用load()函式將影象轉換為45x180數字矩陣,然後對其進行處理。
pixel_matrix = cropped_image.load()
for col in range(0, cropped_image.height):
for row in range(0, cropped_image.width):
if pixel_matrix[row, col] != 0:
pixel_matrix[row, col] = 255
image.save("thresholded_image.png")
為了清晰起見,我將程式碼應用於原始影象。
原版的:
做過演算法矯正的圖
你可以看得到,並非完全黑暗的所有畫素都被刪除了。比如通過影象的線。上述方法在影象處理中的專業術語叫做閾值處理,當然還有很多處理方法,閾值處理事最簡單實用的方法。
去除影象中的黑點
回顧觀察到特徵的第四點,影象中有許多散雜黑點畫素的干擾因子。
迴圈遍歷影象矩陣,並且如果相鄰畫素是白色的,並且與相鄰畫素相對的畫素也是白色的,並且中心畫素是黑色的,則設定中心畫素為白色。
for column in range(1, image.height - 1):
for row in range(1, image.width - 1):
if pixel_matrix[row, column] == 0 and pixel_matrix[row, column - 1] == 255 and pixel_matrix[row, column + 1] == 255 :
pixel_matrix[row, column] = 255
if pixel_matrix[row, column] == 0 and pixel_matrix[row - 1, column] == 255 and pixel_matrix[row + 1, column] == 255:
pixel_matrix[row, column] = 255
結果為:
你可以看到,經過以上步驟的處理,影象已經只剩下字元框架了。雖然有些字元已經丟失了一些基礎畫素,但是每個字元的影象骨架基本上都完備。當然這個是必須的,我們做這麼多處理的主要原因是為每個可能的字元都擷取生成合適字元圖。
構建字元相簿
我將上述演算法裁剪得到的所有字元影象都儲存於資料夾下。下一個任務是為屬於"A-Z0-9"的每個字元找到至少一個樣本影象。這一步就像"訓練"步驟,我手動為每個字元選擇了一個字元影象並對其更名。
完成這一步後,每個字元都有一幅骨架影象!
選擇最優的字元圖
我還運行了其他幾個指令碼,確保每一個字元的影象中都有最佳的影象,例如,如果有20個'A'的字元影象,暗色(1)數量最少的影象顯然是噪聲最少的影象,因此最適合作為骨架影象。選擇的原則:
一個按照字元排序的相似影象(約束條件:黑畫素數量大小,並且相似度> = 90~95%)。
一個從每個分組字元獲得最佳影象。
因此,到目前為止,我們生成了一個畫素影象庫。我們將它們轉換為畫素矩陣,並將"點陣圖,把字元圖轉為數字點陣SON檔案
識別演算法
最後,這就是獲取任何新的驗證碼影象的演算法:
使用相同的演算法儘量減少新影象中不必要的干擾因子
對於新驗證碼圖片中的每字元,強制通過生成的JSON檔案舉證來匹配,基於相應的黑畫素匹配來計算相似度。
如果一個畫素是黑的並且在影象中的位置恰好是破解驗證碼,並且畫素在我們的字元庫中的骨架影象/點陣圖中的相同位置處也是的,則計數會遞增1。
與骨架影象中黑暗畫素的數量做對比,計算匹配百分比,選擇具有最高匹配百分比的字元就是識別結果的字元。
結果演示
最終結果如下:
得到的字元為Z5M3MQ, 驗證碼被成功識別出來了。
寫在最後:
如果大家在學習Python的路上,或者打算學習Python需要學習資料,可以加群571799375,群裡學習資料免費贈送給大家!
本文來自網路,如有侵權,請聯絡小編刪除!