前些時間,因爲工做關係,須要作驗證碼識別相關的工做,因爲以前沒有接觸過這方面,因此一切重頭開始,通過一個月的查閱資料、作實驗嘗試,總算做出了一個能夠用的東西。下面嘗試總結一下這一個多月學習的東西,能夠加深下本身的印象,也能夠向你們分享一下心得。java
驗證碼的主要用途是用來區分對象是機器仍是人。由於若是對象是機器的話,就能夠在短期內提交大量的表單,從而形成破壞,甚至能夠形成一些沒法估量的損失。若在提交以前有驗證碼的話,就能夠在必定程度上防止這種事情發生。而瞭解驗證碼識別的原理,能夠有效預防生成的驗證碼被識別,從而加大自身的安全性,故「未知攻,焉有防」。git
下面就開始對如何識別驗證碼做出介紹,同時本文中只會給出思路和部分代碼,避免引發一些沒必要要的麻煩。github
這裏咱們指的驗證碼是字符和數字的組合,其餘驗證碼並不在此作介紹。咱們引用的例子是這張驗證碼:
算法
目前驗證碼識別的原理通常是將驗證碼中的字符按照順序分割開來,以後對圖片中的每一個字符進行識別,以後將字符識別結果組合在一塊兒,即爲識別的結果。這個過程大體有如下的步驟:安全
1.去噪,二值化markdown
2.分割字符網絡
3.標準化字符學習
4.識別對象
各個步驟的具體描述以下所示:blog
標題的意思是將去除驗證碼圖片中干擾部分,以後只留下背景和內容,並將內容所有處理爲一種顏色(緣由在4中講解)。
二值化處理:
去噪處理:
此處的原理是驗證碼圖片中內容和無用部分通常會有一個顏色上明顯的區分,若是內容和其餘區別不明顯,會給人帶來不好的用戶體驗。咱們能夠經過取色器觀察內容和其餘的顏色值,從而找出一個閥值,在此閥值上的顏色都爲內容,閥值下都是無用的部分。以後遍歷圖片,保留閥值上的顏色,將其置爲一種顏色,將閥值下的顏色置爲背景色。這樣圖片中就只有兩種顏色,就完成了二值化的過程。
在很多時候,驗證碼中會有躁點之類的噪音存在,因此在此也須要將這些噪音去除。在此介紹去除噪點的方法:判斷此像素的相鄰像素,若是相鄰超過N(這須要看具體狀況)個像素與此像素顏色不同,就能夠認爲此像素爲噪點,將其置爲背景色便可。下面是檢查相鄰像素的代碼,在檢查以前已經將圖片進行了二值化。
下面來進行第二步,字符分割
字符分割一直是驗證碼識別的重點和難點,只有將字符分割成功,纔有可能進行到下面的步驟。可是目前沒有通用的分割方法,通常是根據具體的狀況來具體應用。本文介紹一種簡單狀況下的處理方法:掃描法。使用這種方法的前提是驗證碼中各個字符沒有鏈接。效果以下:
分割後:
具體的方法是這樣的:
已知圖片的高爲y,寬爲x。咱們將圖片的左下角視爲座標(0,0),左上角座標視爲(0,y),右下角座標視爲(x,0)。
以後沿着圖片的x軸,在x軸上的某點,對0到y-1高度的像素進行遍歷,來獲取每一個字符的開始和結尾。若是某一列中像素都是背景色,同時下一列中有內容,則此列爲字符的開始。獲取字符結尾的原理與此類似。
在此步驟中通常作如下(不限於)幾件事情:
驗證碼中的字符通常會有各個角度的傾斜,從而相同的字符在通過不一樣角度的傾斜後,也會呈現出不一樣的姿態。扶正傾斜的字符,能夠減小字符傾斜對識別形成的影響。
扶正能夠採用旋轉卡殼算法。能夠將圖片旋轉,由-30度開始,到30度結束,選寬度最小的一張做爲扶正的圖片。
扶正的效果:
有些驗證碼中的字符會粗細不均,將其細化後,能夠減小採樣,從而減小粗細不均對識別形成的影響。
有些驗證碼中的相同的字符會有大小不一樣的形式,因此須要將其處理爲一種形式,理由同上。
這裏簡單介紹下縮放圖片的一個java開源庫--Scalr.使用很是方便,縮放代碼以下所示:
這裏就到了最後的一步,目前比較有效的方法是採用採用神經網絡進行識別,訓練量大的話識別率會很客觀。關於神經網絡在此不作贅述,網上關於神經網絡的資料員有不少,這裏介紹一個java的神經網絡庫:Encog。這裏是圖片識別的示例,修改下就可使用了。目前來看,識別效果還能夠。
以上就是驗證碼識別的一種方法,關於增強驗證碼安全的能夠閱讀參考資料中的文章,裏面總結的很全面,我就不在這裏獻醜了。
水平有限,多多指教。
謝謝
歡迎關注個人微博,ID:小牛_yetuweiba。
參考資料:
http://drops.wooyun.org/tips/141。
文中的思路主要來自此篇文章,這是一篇幾乎毫無水分的文章。在此感謝做者。
最後,博客園的markdown的語法真折磨人。