1. 程式人生 > >常用驗證碼的識別方法

常用驗證碼的識別方法


此文已由作者楊傑授權網易雲社群釋出。

歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。



全自動區分計算機和人類的圖靈測試(Completely Automated Public Turing test to tell Computers and Humans Apart,簡稱CAPTCHA),俗稱驗證碼,是一種區分使用者是計算機和人的公共全自動程式。驗證碼的主要目的是強制人機互動來抵禦機器自動化攻擊,為了確保伺服器系統的穩定和使用者資訊的安全,越來越多的網站採用了驗證碼技術。圖片驗證碼是目前最常用的一種,本文也主要討論這種驗證碼的識別。
最近在一個爬蟲專案中遇到了驗證碼,需要機器自動識別繞過。這些驗證碼大都解析度都較低,本身資訊量不大。通常被加入一種或多種干擾因素:各種背景干擾,噪聲點畫素,字型形變和累疊,字元位置隨機及個數不定,反色等情況。在網上調研了資料和文獻後,分別採用OCR識別和模板庫匹配方法對不同型別驗證碼進行了識別。主要過程可以分解為三個步驟:1.圖片清理,2.字元切分,3.字元識別。以下結合工作經驗和調研內容講解一些常用的驗證碼識別方法和過程。

1.圖片清理
圖片清理是為接下來的機器學習或模板匹配階段做準備的,指通過灰度化、二值化、干擾點清理等過程,得到比較乾淨的圖片資料,具體樣例見下表。


     

1.1 彩色去噪
在計算機中使用最多的 RGB色彩空間,分別對應紅、綠、藍三種顏色,通過調配三個分量的比例來組成各種顏色。以最常見的32位顏色為例,一個分量是用8位來表示,最大值是255,灰度圖是指組成顏色的三個分量相等。原始彩色圖片包含的資訊量是最大的,如果驗證碼圖片中有一些利用顏色反差加的干擾點或者線條,最好能在該階段做初步清理。比較簡單的一種處理方法是採用3*3矩陣對影象進行平滑處理,即對每個畫素取他所在3*3矩陣所有點的RGB均值,分別作為新的RGB值。稍微做點優化,取3*3矩陣中RGB三維歐式距離最接近均值的點作為新值。
1.2 灰度化
在彩色電視機系統中,通常使用一種叫 YUV 的色彩空間,其中Y表示亮度訊號,對於人眼來說,亮度訊號(Y)是最敏感的,如果將彩色影象轉換為灰度影象,僅僅需要轉換並儲存亮度訊號就可以。從RGB到YUV空間的Y轉換有一個很著名的心理學公式:Y = 0.299R + 0.587G + 0.114B。
而實際應用時,將係數縮放1000倍來實現整數運算:Gray = (R*299 + G*587 + B*114 + 500) / 1000 。注意後面那個除法是整數除法,所以需要加上500來實現四捨五入。該公式的另一個簡化變種也很流行:Gray = (R*30 + G*59 + B*11 + 50) / 100。更快的演算法是採用移位代替除法,所以可以將係數縮放成 2的整數冪,再做右移操作。該整數取7從精度和速度上最合適:Gray = (R*0.299*2^7 + G*0.587*2^7 + B*0.114*2^7)>>7 = (R*38 + G*75 + B*15)>>7
1.3 二值化
為了簡化接下來的計算,需要把灰度圖片轉化成黑白二值圖。預設情況下值大於127的畫素點被設定為白色,其餘畫素點設定為黑色。當然,這個閾值也需要根據圖片的實際情況計算調整。一般採用直方圖統計確定動態閾值的方法比較靠譜,白底黑字的取直方圖靠左邊的波谷位置作為閾值,黑底白字則取直方圖右邊的波谷位置作為閾值,將背景和字元作很好的區分。

 

    以(圖A),和(圖B)為例,對應直方圖分別為直方圖A和直方圖B,圖A對應的動態閾值取127,而圖B的動態閾值則取241比較合適。

       

    
 

1.4 底色統一
    如果是黑底白字的圖片,需要轉換成白底黑字,如以上圖B。
   
 

 
 

1.5 干擾點清理
在黑白二值圖片去噪階段,常用的去噪方法為聯通性去噪,通常採用8向聯通來計算連通點個數,若某個點的連通點數目小於預設的閥值,則認為這些點都是噪聲點。這一簡單粗暴的清理方法,通常情況下是非常有效的。

2 字元切分
該階段對前期預處理後的圖片進行切割處理,定位和分離出整幅圖片中的每個孤立的字元主體部分。主要採用X軸和Y軸投影的方法,即統計對應座標上黑色畫素點的個數。對於圖片

得到的X軸和Y軸投影分別如下。利用X軸投影可以切割出單獨的字元,再分別利用Y軸投影,裁剪掉頂部和底部的空白部分。  

 


 

3. OCR軟體識別
我們使用的是開源的OCR識別引擎Tesseract,初期由HP實驗室研發,後來貢獻給了開源軟體業,後經由Google進行優化並重新發布。呼叫程式碼以及識別效果如下:

api = tesseract.TessBaseAPI()
api.Init(".","eng",tesseract.OEM_TESSERACT_ONLY) #初始化api.SetPageSegMode(tesseract.PSM_SINGLE_LINE) #設定為單行字串模式api.SetVariable("tessedit_char_whitelist", whitelist) #設定白名單stringOCR = tesseract.ProcessPagesBuffer(mBuffer, len(mBuffer), api)

 
 

該方法的優點是:開發量少;比較通用,適合於各種變形較少的驗證碼;對於扭曲不嚴重的字母和數字識別率高。缺點也很明顯:對於扭曲的字母和數字識別率大大降低;對於字元間有粘連的驗證碼幾乎難以正確識別;很難針對特定網站的驗證碼做定製開發。
 


4.模板庫匹配
4.1 建立字元模板庫
首先需要針對目標網站收集大量的驗證碼;然後根據上一章節的方法,進行圖片清理;最後按照固定的長寬值切分出字元模板圖,儲存檔名帶上對應字元的標記。

 
 

4.2 字元匹配
首先,把目標驗證碼圖片按字元個數切分,這裡的圖片切分方法必須與模板製作時的切分方法一致,得到與模板圖同樣大小的字元圖。接下來通常的做法是使用漢明距離或編輯距離定義相似度,並用KNN方法得到K個最相似的字元,最後從K個字元中選取出現次數最多的那個作為匹配結果。參考了文獻[1]中K取值和字元識別率的變化關係(如下圖)。
 

   
   

然後,我們把K取值為5。並且把相似度重新定義為:matchScore = dotMatch^2 / (dotCaptcha * dotTemplate),其中dotMatch為驗證碼字元圖與模板圖對應位置都是黑色點的個數,dotCaptcha為驗證碼字元圖中黑色點個數,而dotTemplate為模板圖中黑色點個數。取這個分母是為了防止某些黑色點較多的模板圖在匹配度計算中始終得到較大值。識別效果如下表:    

 


   

該方法的優點是:原理簡單直觀;可以針對不同網站定製優化;對於扭曲的字母和數字識別率較高。缺點是:開發量大,需要定製開發;需要收集大量的字元圖片庫;字元變化很多的情況,匹配次數增加速度下降;對於字元有粘連的圖片識別率低;

5. 支援向量機  
支援向量機通俗來講是一種二類分類模型,其基本模型定義為特徵空間上的間隔最大的線性分類器,其學習策略便是間隔最大化,最終可轉化為一個凸二次規劃問題的求解。實際應用上,往往遇到的是非線性可分得情況,因此通過核函式把低維向量對映到更高維空間,使得樣本滿足線性可分。  
驗證碼識別問題實際上是其中單個字元識別問題,而在字元可窮舉的情況下,比如只有英文字元和數字,單個字元識別問題其實是一個分類問題。一個英文字母或數字表示一類,而驗證碼中切分後得到的單個字元需要被機器自動分到某一類。一般情況下,把單個字元的灰度圖片轉成整形陣列,陣列的每一個元素表示圖片的一個畫素,即一個特徵維度。我們切分得到的圖片大小為10x16=160畫素,即有160個特徵,當特徵數量多且特徵之間關係不明確時,採用支援向量機分類比較合適。  
 LIBSVM   是臺灣大學林智仁(Lin Chih-Jen)副教授等開發設計的一個簡單、易於使用和快速有效的SVM模式識別與迴歸的軟體包,他不但提供了編譯好的可在Windows系統的執行檔案,還提供了原始碼,方便改進、修改以及在其它作業系統上應用。該軟體還有一個特點,就是對SVM所涉及的引數調節相對比較少,提供了很多的預設引數,利用這些預設引數就可以解決很多問題;並且提供了互動檢驗(Cross Validation)的功能。主要引數使用:多類別(C-SVC=0),radial basis function(kernel_type=2),訓練和預測程式碼如下。對於      這樣輕微變形的驗證碼,有字母和數字共36個類別,收集訓練樣本共778個字元圖的情況下,單字元預測準確率接近100%:
 

labels = []
samples = []for ch in captchaTemplate.keys():    for table in captchaTemplate[ch]:
        labels.append(ord(ch))
        samples.append(map(lambda e:e/255., table))
problem = svm_problem(labels, samples)
model = svm_train(problem, '-t 2 -c 500')print len(samples)
data = map(lambda e:e/255., list(Image.open(TESTFILE).getdata(TESTFILE)))
y = ord('z')

prediction = svm_predict([y,], [data,], model)print prediction

該方法的優點是:無需設計快速的影象匹配演算法;只要圖片切分方法合適,對於扭曲傾斜的字母和數字識別率也較高;並且可以針對不同型別的驗證碼做定製優化。缺點是:支援向量機原理比較複雜,無法直觀解釋,需要了解支援向量機等機器學習方法。

6. 神經網路
  以上驗證碼識別都依賴於字元切分,切分的好壞幾乎直接決定識別的準確程度。而對於有字元粘連的圖片,往往識別率就會低很多。目前驗證碼識別最先進的是谷歌在識別“街景”影象中門牌號碼中使用的一套的演算法。該演算法將定位、分割和識別等幾個步驟統一起來,採用一種“深度卷積神經網路”(deep convolutional neural network)方法進行識別,準確率可以達到99%以上。谷歌拿自有的reCAPTCHA驗證碼做了測試,結果發現,對於難度最大的reCAPTCHA驗證碼,新演算法的準確率都達到 99.8%,這可能也好於大多數人為驗證。  
驗證碼作為一種輔助安全手段在Web安全中有著特殊的地位,瞭解驗證碼識別的方法和原理,不僅有利於繞過驗證碼抓取網站內容,而且有利於設計更安全合理的驗證碼。
 


 

網易雲安全(易盾)行為式驗證碼超10億次完美驗證,堅固守衛網站安全第一道防線。網易雲易盾提供新一代網站驗證碼,包括智慧驗證碼、滑動驗證碼等形式,驗證碼介面穩定性 99.9%,感知威脅可智慧切換驗證難度,告別繁瑣驗證,保護業務安全,點選可免費試用

 


                

參考資料:

[1] 《高效的驗證碼識別技術與驗證碼分類思想》

[2] 《驗證碼的識別與改進》

[3] Tesseract專案:http://code.google.com/p/tesseract-ocr

[4] 常見驗證碼的弱點與驗證碼識別:http://drops.wooyun.org/tips/141

[5] http://blog.csdn.net/v_july_v/article/details/7624837

[6] http://www.codeproject.com/Articles/106583/Handwriting-Recognition-Revisited-Kernel-Support-V

[7] http://www.csie.ntu.edu.tw/~cjlin/libsvm/index.html

 




相關文章:
【推薦】 flex佈局之flex-grow和flex-shrink如何計算
【推薦】 用雙十一的故事串起碎片的網路協議(中)
【推薦】 手把手帶你打造一個 Android 熱修復框架(上篇)