驗證碼識別,最新Discuz驗證碼和PhpWind驗證碼的識別

 http://www.51yzm.com/site.asp?ID=3

 

無憂驗證碼識別   |  2008-10-9 4:35:14
需驗證碼識別,對常用論壇的驗證碼識別的時候大家用來做羣發是最合適不過了。一個非常有意義的參考

需驗證碼識別,對常用論壇的驗證碼識別的時候大家用來做羣發是最合適不過了。一個非常有意義的參考

注:非crazycoder原裝,文章是轉載的,原文出處不祥了,很多地方都有,找不到原出處了

驗證碼(captcha)是伴隨自動提交程序(spam)的出現而出現的。現在各種論壇、博客、投票等程序都帶有驗證碼功能。大部分驗證碼都比較容 易識別,只需要簡單對照一下特徵碼就可以得到百分之百準確的結果。也有稍微複雜一點的,比如phpwind和discuz的驗證碼。

前段時間做了phpwind和discuz的驗證碼識別,phpwind6.0以前的驗證碼和discuz最新的驗證碼如果在不改變後臺驗證碼配置的情況下,識別正確率幾乎可以達到100%,現在跟大家分享一下識別方法。

驗證碼識別一般分爲以下幾個步驟:

  1. 取出字模
  2. 二值化
  3. 計算特徵
  4. 對照樣本

各種驗證碼在具體的步驟上操作會有所不同。

我的程序是用VC++寫的,這裏不貼詳細代碼了,只講識別方法。

先說phpwind驗證碼的識別方法:

具體分爲這幾步:

  1. 把圖片橫向等寬分爲4塊
  2. 找出每塊圖片中分佈最多的一種顏色
  3. 與已有樣本比較得出結果

因爲這個驗證碼的字符分佈幾乎是等寬的,所以我們首先把圖片切爲4份,這樣方便取出每一個字符。分成4塊後,通過每一塊中的顏色值對比可以很快得到 字符的特徵。因爲每一塊中字符的顏色值比雜點顏色值要多很多,而且字符是純色的,所以只要統計出最多的一種顏色,然後去除其它顏色就可以得到只有字符的幹 淨圖片。然後對圖片二值化(即構造一個二維數組對應圖片上有顏色的點,把有顏色的點的數組值置爲1,無顏色的置爲0),與樣本比對即可得到字符。當然首先 要得到樣本。樣本的製作與上面分析的步驟一致。經過測試,上面這種方法的識別率是100%的,不會有差錯。

discuz的驗證碼識別較之phpwind要稍難一點。因爲圖片帶有不太容易去掉的背景。字符也不是單純的字符,有陰影邊框,而且不等寬,位置不確定。我們具體分爲以下幾步:

  1. 去除背景色
  2. 分出每一個字符區域
  3. 用輪廓法(berg)得到特徵碼
  4. 與樣本比較得出結果

這個背景色是漸變的而字符的顏色是不變的。首先去除對角線上找不到相同顏色的點,然後統計出每一種顏色佔用的區域的寬度和高度。去除佔用區域高度小 於圖片總高度1/5或大於圖片總高度2/3的點,因爲一個字符不可能達到這種尺寸。再去除密度(即顏色點數/顏色所佔的區域寬高的積)小於15%的點。剩 下的就只有乾淨的字符的顏色點了。

把這些點分爲4份。(分割的辦法爲從左到右用一條豎直的線掃描,掃描線經過的連續區域就是字符區域。)分成4個字符塊後,我們就可以對每一個字符塊進行輪廓特徵取值。

什麼是輪廓法?我是由berg(berg是網易社區的牛人,對我幫助不少)那裏獲知驗證碼識別中的輪廓法。即將一個字模點陣,以四條直線由上下左右 4個方向向字符中心掃描,遇到點即停下,把每一條線通過的路徑長度記下。然後以比路徑長度和其它一些相關的參數得到正確的字符。

我稍微變換了一下輪廓法。即把4個方向上的路徑長度變爲波的形式。波峯記爲1,波谷記爲0,最後得到一個由1和0組成的特徵串,與樣本串比較即可得 到匹配結果。有幾個字符,如V和Y、H和M、4和6等,得到的特徵串可能是一樣的,這樣需要通過其它的一些參數來輔助得到結果。

下面是我計算的特徵串和字符的對照樣本:
10-10-10-10- X 
1-1010-1-10101- W 
-1010--- W 
1--1-101- T 
-1-1010-10- R 
--10-10- R 
101-101-1010-1010- Q 
-1-101-1- P 
--1-1- P 
-10--1010- M 
-10-10-10- K 
10-10-1-1- J 
10-10--- J 
101-101-1010-10- G 
--101-1- F 
--1010-- E 
101-101-10101-101- C 
101-10-10-10- C 
-1-10101-1- B 
---- B 
10101-101-101-101- 9 
1---10- 9 
-101--- 8 
10--1-101- 7 
-1-10-- 6 
1-101-10-101- 4 
1010---- 3 
1010-101-1010-- 2 
10--10-- 2 
//below is equivocal
1-10-1-101- V  //Y
10-10-10-- G  //Q
-10--10- H  //M
10101-101-10101-101- 3  //8
101-101-101-101- 4  //6

 

上面這種方法,對discuz的默認驗證碼,即如圖所示的驗證碼識別正確率爲100%

 

上面對phpwind和discuz的驗證碼識別方法均沒有用到高級的算法,更加沒有用到人工智能的知識,不免有點遺憾,不過準確率相當高,也容易看懂。

在實際應用中可能遇到一些問題,比如discuz驗證碼可以在後臺設爲gif圖片格式。如何把gif動畫中那一個字符幀轉爲bmp圖片呢?下面是VC裏面的方法:

BOOL CCaptchaBreak::Gif2Bmp(CString &sPath)
{
 ULONG_PTR   GdippToken;   
 GdiplusStartupInput   GdippStart;   
 GdiplusStartup(&GdippToken,&GdippStart,0);
 BSTR bsTemp = sPath.AllocSysString();
 Bitmap   bmp(bsTemp);
 ::SysFreeString(bsTemp);

 int   FrameCount,FramePos,size,pause;   
 PropertyItem*   pPropItem;   
 GUID   pageGuid;   
 GUID*   pDimID;   
 UINT   count;  

 count=bmp.GetFrameDimensionsCount();  

 pDimID=new GUID[count];  

 bmp.GetFrameDimensionsList(pDimID,count);   
 FrameCount=bmp.GetFrameCount(&pDimID[0]);

 if (1==FrameCount) //if is bmp then exit
 {
  delete[]pDimID;   
  return FALSE;
 }

 size=bmp.GetPropertyItemSize(PropertyTagFrameDelay);   
 pPropItem=(PropertyItem*)malloc(size);  

 bmp.GetPropertyItem(PropertyTagFrameDelay,size,pPropItem);   
 delete[]pDimID;  

 pageGuid=FrameDimensionTime;   
 FramePos=0;

 int iFontFramePos = 0;
 int iMaxPause = 0;
 while (FramePos

 return TRUE;
}

BOOL CCaptchaBreak::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
 UINT  num = 0;          // number of image encoders
 UINT  size = 0;         // size of the image encoder array in bytes

 ImageCodecInfo* pImageCodecInfo = NULL;

 GetImageEncodersSize(&num, &size);
 if(size == 0)
  return FALSE; 

 pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
 if(pImageCodecInfo == NULL)
  return FALSE; 

 GetImageEncoders(num, size, pImageCodecInfo);

 for(UINT j = 0; j < num; ++j)
 {
  if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
  {
   *pClsid = pImageCodecInfo[j].Clsid;
   free(pImageCodecInfo);
   return TRUE;  // Success
  }    
 }

 free(pImageCodecInfo);
 return FALSE;  
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章