基于KNN的驗證碼識別算法

寫在前面

最近幾天忙完考試看了一個關于機器學習的基礎算法——k近鄰算法,簡稱為KNN。KNN是數據挖掘領域的十大經典算法之一,優點是簡單,精度高,對異常值不敏感,無數據輸入假定;缺點是計算的復雜度高,空間復雜度高。筆者由于剛剛機器學習入門,因此先從簡單的算法開始,手動實現了一下KNN算法,并且基于KNN做了一個網頁驗證碼圖片識別的demo出來。當然現實中做驗證碼識別大多都不用KNN來做,開銷太大而且太慢,但是目前水平有限嘛,就先用KNN來做著。

數據集獲取

由于對母校西南交通大學的教務系統懷有深深執念,因此數據集就采自西南交大的教務登錄系統,寫一個小爬蟲從教務系統的登錄界面采集1000張驗證碼圖片。


圖1

KNN核心算法編寫

KNN是一種有監督學習方法,其核心思想非常簡單,算法沒有訓練過程,當用戶傳入一個需要被分類的數據時,算法就會將該數據與數據集中的帶標簽數據進行對比,計算“距離”,并且根據與待分類數據距離的從小到大對數據集中的數據進行排序,最后根據用戶傳入的k值,選取前k個最接近待分類數據的數據的標簽,則待分類數據的標簽等于k個數據中出現次數最多的標簽值。代碼如下:

圖2

在這里,距離的衡量使用的是歐氏距離,用戶也可以使用其他的距離來作為數據之間距離的衡量指標。

數據預處理

算法在對圖片進行分類之前首先要對數據進行預處理。由于原始的圖片是RGB圖片,轉化成矩陣有三個維度不太好處理,因此首先要將圖片轉化成灰度圖,這樣其矩陣就是二維的。同時為了增加對比度,和最大限度地去除驗證碼圖片中隨機線條對分類器的干擾,筆者設定一個閾值,將大于這個閾值的矩陣數值置為255,小于這個閾值的的數值置為0。這個閾值的選定需要針對不同的驗證碼做多次實驗,來找到一個最優的值。

其次我們觀察驗證碼圖片可以發現,每張驗證碼圖片的頂部和左端都有條黑色的實線,這是數據集中的噪音,需要去掉,算法將把圖片在頂端和左端都切掉一個像素的寬度。

接下來我們需要對驗證碼圖片進行切分,將驗證碼中的字母從原始圖片中“切”出來,筆者認為這才是整個算法中比較有難度的一節。觀察從網絡上獲取到的驗證碼圖片,我們可以發現字母在圖片中的位置分布并不是固定的,因此不能采用定長分割這種方案。必須要針對不同的圖片動態分割,并且對分割后的圖片進行規整化操作,以使每張圖片都達到一樣的大小便于后期向量化處理。在圖片分割這個問題上,筆者以圖片的每一列為考察單位,因為畢竟是要縱向分割圖片。筆者基于這樣的一個假設,若一列上不包含驗證碼字母,則該列上大部分應該是白色(一則因為圖片上有一寫隨機干擾線無法完全去除,二則因為上一步將圖片二值化后圖片本底就變為白色),若一列上包含字母則該列上有相當一部分像素點的值應該不是白色,問題的關鍵依然在于選定一個閾值,若某一列白色閾值的比例大于這個值則判定該列上沒有字母可以作為備選分割線,若小于這個閾值則該列上包含有字母,不能作為分割的備選線,筆者通過實驗得出該閾值取0.9較為合適。那么,該算法第一步就能夠得到一系列備選的圖片分割線,第二步就是從這些備選分割線中選出真正的分割線,筆者在這里的設定是讓分割線之間的距離最小,即兩個字母之間若存在分割線則選擇最中間的那條。分類效果如下圖所示:

圖3

如上圖所示,算法的切分效果還是不錯的。

算法實現

到目前為止,筆者已經完成了圖片的預處理和規整化。接下來只用將圖片向量化并打上標簽輸入分類器就可以了。由于圖片本身是一個二維矩陣,我們只用將二維轉化成一維就行了,非常簡單。接著,我們需要手動為每一個字母打上標簽,效果如下圖所示:

圖4

如上圖所示,切分后的字母圖片的名稱第一個字母即為該圖片的標簽。

算法測試

筆者選取一百張驗證碼圖片對分類器進行測試,測試代碼如下:

圖5

最終測試結果表明該算法的錯誤率大約在0.2左右。

算法應用

筆者在該算法基礎上由寫了一個教務系統的登錄程序,看能不能對學校的教務系統進行登錄,代碼如下:

圖6

運行結果如下:

圖7

如圖所示,登錄成功。

開源

https://github.com/yhswjtuILMARE/KNN-Identification-codes

2018年1月19日

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容