程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> php實現驗證碼的識別(中級篇)

php實現驗證碼的識別(中級篇)

編輯:關於PHP編程

  在上篇文章 <php實現驗證碼的識別 (初級篇 ) http://www.BkJia.com/kf/201203/123439.html > 中,講了如何識別簡單的驗證,這裡的簡單只的是驗證碼有數字和字母組成,格式統一,每次出現位置固定。這篇文章將繼續深入研究識別驗證碼,這次識別的目標是,驗證碼有字符和數字組成,驗證碼存在旋轉(可能左右都旋轉),位置不固定,存在字符與字符之間的粘連,且驗證碼有更強的干擾素。這篇文章講解的方法,並不是萬能的解決方案,並且提供代碼不能直接解決你的問題,這裡僅僅是方法,具體需求讀者自己解決,需要說明的是,識別驗證碼與具體的編程語言無關,這裡只是使用 php 語言實現,使用這裡介紹的方法,你可以使用任何語言實現。

 這篇文章逐步講解識別驗證碼過程中的各個步驟。 


 \

如上圖,隨後的講解我們都圍繞此圖展開。
 一:拿到一個驗證碼的,第一眼我們首先要做的工作是,二值化。把驗證碼的部分用 1 表示,背景部分用 0 表示出來,識別方法很簡單,我們打印出驗證碼正張圖片的 RGB ,然後分析其規律即可,通過 RGB 碼,我們很容易分辨出上面這張圖片的 R 值大於 120 , G 和 B 的值小於 80 ,所以依據這個規則我們很容易把上面的圖片二值化。再看初級篇中識別的兩張圖 

\  \

 剛看上去,感覺很復雜。驗證碼的圖片每次背景色都不相同,且不是單色,各個驗證碼數字的顏色每次也各不相同。貌似很難二值化,其實我們打印出其 RGB 值很容易就發現。無論驗證數字顏色如何變化,該數字的 RGB 值總有一個值小於 125 ,所以通過如下判斷

$rgbarray['red'] < 125 || $rgbarray['green']<125|| $rgbarray['blue'] < 125

我們就很容易分辨出哪裡是數字,哪裡是背景。

  我們能夠找到這些規律的因素是,在制作驗證碼的干擾素時,為了使干擾素不影響數字的顯示效果,必須使用干擾素的 RGB 和數字 RGB 相互獨立,互不干擾。只要懂得這個規律,我們就很容易實現二值化。

  我們找到的 120 , 80 , 125 等阈值,可能和實際的 RGB 有出入,所以,有時二值化後,會有部分地方出現 1 ,對於驗證碼上固定位置顯示數字,這種干擾沒有太大意義。但是對於驗證碼位置不確定的圖片來說,在我們切割字符時,很可能造成干擾。所以,在二值化後要進行去噪出來。

  二:接下來我們進行第二個步驟,出噪。出燥的原理很簡單,就是把孤立的有效的值去掉,如果噪點比較高,要求的效率也比較高的話,這裡面也有很多工作要做。幸好這裡我們不要求這麼高深,我們使用最簡單的方法就可以,如果一個點為 1 則判斷這個點的上下左右上左上右下左下右 8 個方位上數字是否為 1 ,如果不為 1 ,就認為是一個燥點,直接設置為 1 即可。

  \


 

如上圖所示,我們使用此方法很容易發現紅色方框部分的 1 為燥點,直接設置為 1 即可。

在判斷時我們使用了一個技巧,有時候的噪點可能是兩個連續的 1 ,所以我們

[php:collapse] + expand sourceview plaincopyprint?$num = 0; 
if($data[$i][$j] == 1) 

    // 上  
    if(isset($data[$i-1][$j])){ 
        $num = $num + $data[$i-1][$j]; 
    } 
    // 下  
    if(isset($data[$i+1][$j])){ 
        $num = $num + $data[$i+1][$j]; 
    } 
    // 左  
    if(isset($data[$i][$j-1])){ 
        $num = $num + $data[$i][$j-1]; 
    } 
    // 右  
    if(isset($data[$i][$j+1])){ 
        $num = $num + $data[$i][$j+1]; 
    } 
    // 上左  
    if(isset($data[$i-1][$j-1])){ 
        $num = $num + $data[$i-1][$j-1]; 
    } 
    // 上右  
    if(isset($data[$i-1][$j+1])){ 
        $num = $num + $data[$i-1][$j+1]; 
    } 
    // 下左  
    if(isset($data[$i+1][$j-1])){ 
        $num = $num + $data[$i+1][$j-1]; 
    } 
    // 下右  
    if(isset($data[$i+1][$j+1])){ 
        $num = $num + $data[$i+1][$j+1]; 
    } 

if($num == 0){ 
    $data[$i][$j] = 0; 

$num = 0;
if($data[$i][$j] == 1)
{
 // 上
 if(isset($data[$i-1][$j])){
  $num = $num + $data[$i-1][$j];
 }
 // 下
 if(isset($data[$i+1][$j])){
  $num = $num + $data[$i+1][$j];
 }
 // 左
 if(isset($data[$i][$j-1])){
  $num = $num + $data[$i][$j-1];
 }
 // 右
 if(isset($data[$i][$j+1])){
  $num = $num + $data[$i][$j+1];
 }
 // 上左
 if(isset($data[$i-1][$j-1])){
  $num = $num + $data[$i-1][$j-1];
 }
 // 上右
 if(isset($data[$i-1][$j+1])){
  $num = $num + $data[$i-1][$j+1];
 }
 // 下左
 if(isset($data[$i+1][$j-1])){
  $num = $num + $data[$i+1][$j-1];
 }
 // 下右
 if(isset($data[$i+1][$j+1])){
  $num = $num + $data[$i+1][$j+1];
 }
}
if($num == 0){
 $data[$i][$j] = 0;
}


我們計算這個點的 8 個方向上的值之和,最後我們判斷他們的和是否小於特定的阈值
 三:經過去噪後,我們就得到干淨的二值化的數據,接下來要做的就是切割字符了。切割字符的方法有很多種,這裡我采用最簡單的一種,先垂直方向切割成為字符,然後在水平方向去掉多於的 0000 ,如下圖

  \


 

第一步切割紅線部分,第二步切割藍線部分,這樣就可以得到獨立的字符了。但是像下面這種情況

  \

按上面的方法會把 dw 字符切割成一個字符,這是錯誤的切割,所以這裡我們涉及到粘連字符的切割。
 四:粘連字符切割,制作驗證碼時,規則字符的粘連很容易分割開,如果字符本身有縮放,變形就很難處理,經過分析,我們可以發現,上面的字符粘連屬於很簡單的方式,只是規則字符的粘連,所以處理這種情況,我們也使用很簡單的處理方式。當完成分割操作後,我們不能馬上確定分割的部分就為一個字符,要進行驗證,驗證的關鍵因素就是,切割下來的字符的寬是否大於阈值,這個阈值的取捨標准是,一個字符無論怎麼旋轉變形都不會大於這個阈值,所以,如果我們切割的塊大於這個阈值,就可以認為這是一個粘連字符;如果大於兩個阈值之和,就認為是三個字符粘連,以此類推。知道這個規則後,切割粘連字符也就很簡單了。如果我們發現是粘連字符塊,直接平分這個塊為兩個或者多個新的塊就可以。當然為了更好的還原字符,我一般都采用平分 +1 , -1 對字符塊的部分進行適當的補充。
 五:經過上面四個步驟,我們就可以提取出比較純的字符塊了,接下來要做就是匹配字符了。對於旋轉字符的特征碼建立,有很多種方法,這裡就不做深入研究了。我這裡使用的最簡單的方式,為所有字符的所有情況建立匹配庫,所以在我提供的代碼種增加了 study 操作,其目的就是,先有人手工識別圖片的驗證碼,然後通過 study 方法,寫入特征碼庫。這樣寫入的圖片數據越多,驗證識別的准確行也就越高。
 好了,經過以上步驟,我們基本上可以識別現在互聯網上大部分的驗證碼,這裡我們都是使用的最簡單的方法,沒有使用任何 OCR 知識。這些方法,應該屬於非 OCR 領域的頂峰了,要想識別更加復雜的驗證碼,那就需要更多的 OCR 知識了。有機會的話,我會在高級篇中一一做介紹。
 下面是一些容易識別的驗證碼,希望引起網站管理者的重視。
 
  
 \



 

制作驗證碼的一些建議
 對於識別驗證碼的程序來說,最難得部分是驗證字符的切割和特征碼的建立,而國內很多程序員只做驗證碼時,總是喜歡在驗證碼加很多干擾素,干擾線,影響效果不說,還達不到很好的效果;所以,要想使自己驗證碼難於本識別,只做下面兩點就夠了
1 :字符粘連,最好所有的字符都有粘連的部分;
2 :不要使用規格字符,驗證碼的各個部分使用不同比例的縮放或者旋轉。
只要做到這兩點,或者這兩點的變形,識別程序就很難識別。我們看看, yahoo 和 google 的驗證碼就知道,白字黑底,卻很難被識別。

Goole:

  \


yahoo:  


 \


源文件下:點擊下載http://www.BkJia.com/uploadfile/2012/0316/20120316111107739.rar


 摘自  ugg的專欄 



 


 剛看上去,感覺很復雜。驗證碼的圖片每次背景色都不相同,且不是單色,各個驗證碼數字的顏色每次也各不相同。貌似很難二值化,其實我們打印出其 RGB 值很容易就發現。無論驗證數字顏色如何變化,該數字的 RGB 值總有一個值小於 125 ,所以通過如下判斷

$rgbarray['red'] < 125 || $rgbarray['green']<125|| $rgbarray['blue'] < 125

我們就很容易分辨出哪裡是數字,哪裡是背景。

  我們能夠找到這些規律的因素是,在制作驗證碼的干擾素時,為了使干擾素不影響數字的顯示效果,必須使用干擾素的 RGB 和數字 RGB 相互獨立,互不干擾。只要懂得這個規律,我們就很容易實現二值化。

  我們找到的 120 , 80 , 125 等阈值,可能和實際的 RGB 有出入,所以,有時二值化後,會有部分地方出現 1 ,對於驗證碼上固定位置顯示數字,這種干擾沒有太大意義。但是對於驗證碼位置不確定的圖片來說,在我們切割字符時,很可能造成干擾。所以,在二值化後要進行去噪出來。

  二:接下來我們進行第二個步驟,出噪。出燥的原理很簡單,就是把孤立的有效的值去掉,如果噪點比較高,要求的效率也比較高的話,這裡面也有很多工作要做。幸好這裡我們不要求這麼高深,我們使用最簡單的方法就可以,如果一個點為 1 則判斷這個點的上下左右上左上右下左下右 8 個方位上數字是否為 1 ,如果不為 1 ,就認為是一個燥點,直接設置為 1 即可。

 

 

 剛看上去,感覺很復雜。驗證碼的圖片每次背景色都不相同,且不是單色,各個驗證碼數字的顏色每次也各不相同。貌似很難二值化,其實我們打印出其 RGB 值很容易就發現。無論驗證數字顏色如何變化,該數字的 RGB 值總有一個值小於 125 ,所以通過如下判斷

$rgbarray['red'] < 125 || $rgbarray['green']<125|| $rgbarray['blue'] < 125

我們就很容易分辨出哪裡是數字,哪裡是背景。

  我們能夠找到這些規律的因素是,在制作驗證碼的干擾素時,為了使干擾素不影響數字的顯示效果,必須使用干擾素的 RGB 和數字 RGB 相互獨立,互不干擾。只要懂得這個規律,我們就很容易實現二值化。

  我們找到的 120 , 80 , 125 等阈值,可能和實際的 RGB 有出入,所以,有時二值化後,會有部分地方出現 1 ,對於驗證碼上固定位置顯示數字,這種干擾沒有太大意義。但是對於驗證碼位置不確定的圖片來說,在我們切割字符時,很可能造成干擾。所以,在二值化後要進行去噪出來。

  二:接下來我們進行第二個步驟,出噪。出燥的原理很簡單,就是把孤立的有效的值去掉,如果噪點比較高,要求的效率也比較高的話,這裡面也有很多工作要做。幸好這裡我們不要求這麼高深,我們使用最簡單的方法就可以,如果一個點為 1 則判斷這個點的上下左右上左上右下左下右 8 個方位上數字是否為 1 ,如果不為 1 ,就認為是一個燥點,直接設置為 1 即可。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved