驗證碼圖片均取自於國內某知名信息安全網站,通過圖像處理、模板對比識別等步驟,實現了該類簡單驗證碼圖片的識別功能。同時對程序實現了可視化界面,並集成了(驗證碼)圖片下載、(灰度值)門限手動調節等擴展功能。代碼存在github,傳送門請戳我。
一、程序內容及原理
本程序以Python實現,主要借助了PIL(Python Image Library,實現讀取圖片、讀取灰度值等圖像處理相關功能)及tkinter(實現界面設計相關功能)兩個庫。圖像處理及識別的主程序的總體流程如下:導入(讀取)驗證碼圖片,圖像處理,圖像識別,識別結果輸出。
圖一 程序總體流程
(一)、圖像處理
圖像處理的主要流程如下。
圖二 圖像處理流程
1.讀取圖片
利用PIL庫中的PIL.Image.open函數實現對驗證碼圖片的讀取,並以PIL.Image的格式返回(我們簡稱為im)。下文的圖像處理及圖像分割都是基於im格式完成的。
在主程序(imgRe.py)中,目標圖片的讀取需要手動輸入圖片名稱(可能還需輸入圖片所在路徑);在可視化程序(imgRe_GUI.py)中,只需通過點擊“選取圖片”即可方便快捷地選取目標圖片。
圖1.1 imgRe.py中的圖片讀取方式
圖1.2 可視化程序中的圖片讀取方式
2.圖片降噪(二值化)
圖片降噪的目的是把不同灰度值的背景、干擾線等多余的信息去掉,只留下單一的背景以及所需的驗證碼信息,以便進行接下來的圖片切割、識別等步驟。在本程序中,通過二值化處理使驗證碼圖片成為二進制點陣(及相應的位圖),以此實現降噪的功能,實現該功能的函數命名為“denoise”,處於類Div中。
本項目中,可以發現該類驗證碼有如下特點:灰度值分布規律較明顯,驗證碼信息灰度值為0或255,背景信息的灰度值處於2至253之間;驗證碼較“方正”,無需進行太多的圖像標准化處理。基於這些特點,本程序使用截取灰度值門限、灰度值映射的方法對圖片進行二值化處理,從而達到降噪的目的。例如,下圖2.1為某驗證碼圖片的示意圖,圖2.2為該圖的灰度直方圖示意圖,(已進行歸一化處理,橫坐標的灰度值從左至右為0至255)。
圖2.1 某驗證碼圖片示意圖
圖2.2 驗證碼圖片灰度直方圖示意圖
從圖2.2可見,其灰度值為255的像素點較多(對應原圖中的白色驗證碼信息“S2JW”),而灰度值為10左右的像素點占比最多(對應原圖的黑色環形圖像),其他灰度值像素點錯落分布(對應原圖中的灰色背景),因此將灰度值門限設置為253-255以截取右方的驗證碼信息,把截取到的門限內的灰度值映射為0(對應黑色),其他灰度值(0-253)全部映射為1(對應白色),以此實現圖片二值化及降噪處理,可以得到驗證碼信息與單一背景的位圖,其示意圖如下。
圖2.3 驗證碼圖片降噪后示意圖
3.圖片切割
圖像分割就是指把圖像分成各具特性的區域並提取出感興趣的目標的技術和過程。圖像分割是由圖像處理進到圖像分析識別的關鍵步驟,這是因為圖像的分割、目標的分離、特征的提取將原始圖像轉化為更抽象更緊湊的形式,使得更高層的分析和理解成為可能。本程序中,圖片切割的目的是將降噪后的驗證碼圖片根據其驗證碼信息切割為對應的圖片“碎片”,每個“碎片”對應唯一一個驗證碼信息,以便於模板進行比對、識別,實現該功能的函數命名為imDiv(及_div),處於類Div中。
在切割的算法中,程序首先選定某一縱列進行縱向掃描,若發現該列中有像素點像素值為零,即認為發現了驗證碼信息,將該列標記為“start”,隨后繼續掃描直至發現某一列中整列未出現驗證碼信息(即像素值為零的點),認為該驗證碼信息結束,將該列標記為“end”;以上完成一個驗證碼信息的橫向掃描,接着進行橫向掃描,道理同上,最后紀錄下該驗證碼信息的橫向和縱向的起始坐標點。
圖3.1 切割后的“碎片”示意圖
將“碎片”的二進制點陣進行直接打印輸出結果如下。
圖3.2 “碎片”二進制點陣示意圖
(二)、圖像識別
圖像識別采取的是模板對比的識別方法。將切割后的驗證碼“碎片”分別於各張模板一一比對,分別得出相似度的值,最后取相似度最高的模板圖名稱作為該“碎片”的識別結果。其“碎片”與某張模板進行比對時的流程如下。
圖一 比對流程
部分模板圖片如下。
圖二 部分模板圖片
1.獲取信息坐標
對於碎片圖或模板圖,首先需要獲得其驗證碼信息的像素點所在的坐標。如圖3.2中的符合的坐標點集合為(1,0),(2,0),(3,0)等等(以左上角作為原點)。實現該功能的函數命名為getPoints。
圖1.1 坐標點集合示意圖
2.計算相似度
計算兩圖的坐標點集合的相似度,使用的是歐幾里得距離的方法,並且我對該方法進行了改動:加入了均方差的檢測法和歸一化的處理方法,使得即使錯位的方法也可以進行識別。實現該功能的函數命名為fitting,處於類Recognize中。
通過比對“碎片”圖的坐標點集合與模板圖片的坐標點集合,在二維平面的情況下,我們可以利用公式:
求出兩圖中每一對對應點間的歐幾里得距離。
若兩圖相同,則每對對應點間的歐幾里得距離應該都為零,也就是相似度非常高。
當兩圖發生了一些錯位,比如下列的a和b兩個示意的坐標點集合,它們間對應點的歐幾里得距離都為根號二而不為零,說明他們的相對位置是相同的,可是由於錯位或原點不同等原因導致絕對位置不同。
圖2.1 坐標點集合
可計算出這兩個集合對應點的歐幾里得距離(為了方便計算和顯示這里取距離值的平方)均為2。接着對這個距離值的數列取均方差。計算數列的均方差並進行歸一化的函數命名為var,同屬於類Recognize中。
圖2.2 a、b數列的對應點歐幾里得距離
那么這個數列的均方差為零,表示a、b兩個坐標點集合對應點間的歐幾里得距離都相等,我們即可認為這兩個坐標點集合有着非常高的相似度(相似度的值最高為1,最低為0)。
圖2.3 驗證a、b兩個集合的相似度
二、程序執行結果
這里主要展示可視化(即imgRe_GUI.py)程序的執行結果,即軟件的運行情況。初始化時程序界面如下。
圖一 程序初始化界面
1.“選取圖片”之后的程序運行截圖
點擊“選取圖片”之后,程序自動展示如下三個示意圖:“原圖”、“降噪后的二值化圖”以及“灰度直方圖”。其運行結果如下。
圖二 程序讀圖后界面
2.“自動識別”按鈕之后的程序運行截圖
點擊“自動識別”之后,程序右下欄上部分顯示的是圖像切割處理后的“碎片”圖片,下方便驗證碼圖片的識別結果。該識別結果為文本形式,可直接復制粘貼。
圖三 程序識圖后界面
3.其他功能的程序運行截圖
其他功能主要包括“下載圖片”和“調節門限”。點擊“下載圖片”並拉動拖條選擇下載數量后,程序后台將自動下載對應數量的驗證碼圖片。圖片自動存於程序相同目錄下的“簡單驗證碼”文件夾中,若無該文件夾,程序將自動創建該文件夾。
“調節門限”功能一般較為少用,因為對於該類簡單驗證碼程序可自動判讀選擇灰度值門限。但是當選取的圖片較為復雜或用戶對識別結果不滿時,可自行選擇門限,程序將自動將選取的門限中的灰度值的像素映射為0,其他的為1。一旦確定最小值,程序會彈窗讓用戶選擇門限最大值,最大值的區間從已選定的最小值開始至255。
三、總結
這項技術源自於程序自動登錄、注冊時對於破解驗證碼這個“攔路虎”的欲望,同時該技術也可適用於車牌識別、身份證識別等場景,具有一定的研究價值。
遺憾的是,目前的算法還是很基礎很簡單,因此只能應對這種干擾較少、驗證碼“中規中矩”的驗證碼圖片。對於出現了干擾線、驗證碼文字扭曲的圖片暫時未能較好處理和識別。希望在未來有時間能繼續交流學習,不斷改進算法。另一個則是,進行可視化界面設計時是使用tkinter這個庫進行設計的,並不能實現太復雜的設計。以后有機會可爭取使用QT實現更完善的界面。
最后想說的是,整個項目的整體思路參考了網上的文章或相關介紹,所以我希望通過消化之后的這些很簡單但又基本的思路和代碼能繼續為他人、為正在做類似研發的有需要的人提供微薄幫助。希望高手多多指教。