本文乃Siliphen原創,轉載請註明出處:http://blog.csdn.net/stevenkylelee/
我的驗證碼識別實踐一共有3篇文章。
下一篇(驗證碼識別實踐2):http://blog.csdn.net/stevenkylelee/article/details/8270069
把最近學的一些知識總結了下。
然後,寫了這個麼一個小程序。
這個小程序的作用是,識別出簡單的驗證碼。
程序運行截圖如下:
語言C#。
用C++寫的話,調用OpenCV庫,做這個就沒有什麼難度了
所以用C#,自己手寫算法的實現,鍛鍊一下。呵呵。
本程序的下載地址:http://download.csdn.net/detail/stevenkylelee/4852518
本程序對於如下幾種驗證碼的識別率達到:100%
呵呵。不信?你下載下來試試看。。
網址1,https://www.ed3688.com/sb2/me/generate_validation_code.jsp
截圖:
網址2:http://www.sbobet.com/zh-cn/resource/captcha/sign-in.jpg?634900445434772000
截圖:
網址3:http://www.ibc168.com/login_code.aspx?
截圖:
(注意,要識別這個驗證碼的話,需要在程序界面上選擇:“定點1”,否者不能識別)
考慮到做這種程序需要做大量的實驗和測試
爲了方便性我在程序上做了圖片下載功能,
可以直接把驗證碼下載下來識別。
當然,這個是C#的優點了。
要是用C++不借助第三方庫,
直接Socket Http請求下載圖片,可要麻煩死。
本程序對於下面這個驗證碼,也有一定的識別率。但很低
網址4:http://88cp.me/tpl/commonFile/images/gdpic/macpic.php?SR=d590fc460740e24e7af4
截圖:
其原因,我在如下解說。
總結:
驗證碼的識別。最主要有2大步驟。
1.字符的分割
2.字符的分類
字符的分割,其實是一個廣義概念。
我最初以爲把字符所在的那個子圖給“摳”出來,就算是分割了。
其實不然,分割有:閾值分割,自適應閾值分割,提取連通分量,查找輪廓等
這些操作都最終都圍繞着把字符的“形狀”信息給提取出來的目的
閾值分割是讓圖像的信息減少,從而使後續操作簡單。
(只處理二值圖像當然簡單了)
有些分割,會直接用到彩色圖像。比如:字符具有某種顏色,
那麼,就提取這種顏色的位置連通分量。
字符分類的話。就是把字符信息作爲某種算法(或者稱爲分類器)的輸入
然後,返回出這個形狀屬於那種分類(字符)
我做的這個識別程序,主要流程如下:
1.圖像預處理。
2.字符分割
3.對分割後的信息提取特徵
4.用特徵和樣本進行匹配
1.圖像預處理。
我的圖像預處理,就是二值化圖像。
然後,統計一下,白色和黑色的比例。決定是否反轉圖像的顏色。
爲什麼要反轉圖像顏色呢。因爲,有些驗證碼的字符的顏色是淺色背景是深色,
而有些是字符深色背景淺色。爲了使後續的操作簡單。
把它們都統一處理成字符黑色背景白色。
我的處理是,對於整個圖像,如果黑色比例比白色多
那麼,就認爲黑色是背景。對整個圖像進行顏色反轉。
2.字符分割
字符的分割,我用的是提取連通分量的做法。
連通分量(Connected Component)是圖論上的說法,
好像到了圖像處理的書,一般都叫連通區域(Connected Region)
(這2個說法都是等價的吧?呵呵,我不知道,期待你來回答我)
提取連通分量的實現一般都是 DFS(深度優先搜索)算法啦。
我寫的算法用的是8鄰域連通,
把純黑色的像素都提取出來。
(實際上有一個回調函數,可以在算法外部決定提取什麼顏色)
返回的是這些像素的點的座標。
(有座標就足夠了,已經能夠表達形狀了,這一步後,根本不需要字符的顏色信息)
數據結構如下:List<Point> Region ;
如上圖,
界面左邊的圖像是原圖。
先對左邊的原圖像進行二值化處理。
然後,提取連通分量。
界面右邊的圖像,用於調試。
我把提取到的每個獨立的連通分量都染成了紅色。
並且,遍歷了那些連通分量上的點,計算出最小包圍矩形。
矩形用藍色顯示。
提取連通分量有一個好處,就是不管字符在圖像的什麼位置
都可以“抓”到它。當然,這個是需要有顏色信息分明的前提的。
3.對分割後的信息提取特徵
提取到連通分量後,就可以計算特徵了。
特徵計算目的就是把高維度的表示降成低維度的表示。
我的理解,就是說,“去掉很多細節表示,只留下個大概模糊的輪廓描述”
特徵提取,方法很多。比如:矩(Moment)
因爲我水平有限。!- -
So,這裏使用的是一種簡單的“N*M比例特徵法“
就是把連通分量按照每個點的幾何位置信息先套上一個最小包圍矩形
然後,把這個矩形分割爲N行M列的小格子。
再然後,把連通分量的點按照位置信息歸類進對應的小格子中。
最後,計算小格子中的點的數量與小格子的面積的比值。
每個小格子最後對應一個標量。
我是5*5切分,所以,最後25個標量,
組成一個25維的向量作爲一個連通分量的特徵。
4.用特徵和樣本進行匹配
最後一步,分類。也就是識別。
分類器搞到很複雜的有什麼:支持向量機,人工神經網絡 等
同樣是水平有限,這裏,我實現了最簡單的分類:最近鄰法
最近鄰法就是說,把要匹配的特徵和樣本庫中的所有樣本特徵進行計算
取歐氏距離最短的那個樣本的類別作爲輸出
最後說下,
爲什麼會對網址4的驗證碼識別率很低呢
最主要的原因出在分割這個環節上。如下圖:
如果能正確分割出字符,獲取其形狀描述(點集合)
那麼,就可以達到100%識別。
我實現的只是簡單的閾值化。沒有用自適應閾值。
所以,閾值後,不一定會”凸顯“字符的輪廓。
其實,這個碼可能用自適應閾值也不好處理,
因爲,字符灰度值有可能比局部計算出來的閾值灰度值低或高
所以,到底定義比自適應閾值的閾值是高還是低呢?
如果捨得花費功夫的話,用一些統計學的方法
應該可以大幅度提高識別率,我個人認爲。。。