驗證碼圖片識別


因朋友需求,對某網站的驗證碼圖片進行自動識別,原以為是個復雜的問題,后來查看了網上的一些資料,總體思路上參考了:

http://www.cr173.com/html/16871_1.html

嘗試用Delphi做了Demo,過程如下

1、獲取到驗證碼圖片生成的URL,如http://www.aaa.bbb.cn/ValidateCode.aspx

2、使用TIdHTTP控件通過URL獲取圖片,由於URL獲取驗證碼圖片是以數據流形式傳遞過來的,所以處理非常方便,主要代碼如下:

procedure TfrmMain.Button1Click(Sender: TObject); 
var 
  ms: TMemoryStream; 
  pi : TPngImage; 
begin 
  ms := TMemoryStream.Create; 
  pi := TPngImage.Create; 
  try 
    try 
      { 獲取校驗圖片,存入數據流中 } 
      IdHTTP1.Get(Edit1.Text, ms); 
      { 從流中載入png圖片 } 
      ms.Position := 0; 
      pi.LoadFromStream(ms);

     { 顯示圖片 } 
      Image1.Picture.Graphic := pi; 
  …

end;

識別主要分為三個步驟:第一步進行圖片處理,最好形成二值化,第二步需要進行學習並保存特征碼,第三步完成正常的識別功能。

3、圖片處理

圖片處理過程包括:

(1)將png圖片轉換為bmp圖片,在Delphi下非常簡單:

bmp1.Assign(Image1.Picture.Graphic);

(2)進行圖片二值化

對於本次識別的圖片,非常簡單,如下圖:

image

進行色彩分析,將相同顏色的像素進行計數后發現只有三種顏色:背景色、干擾色和字體藍色。做二值化處理時就比較簡單了,逐個處理像素點,將干擾色處理成背景色:

 for w := 0 to ABmpDesc.Width -1 do 
    for h := 0 to ABmpDesc.Height -1 do 
    begin 
      c := ABmpDesc.Canvas.Pixels[w, h];

      { 不是字體顏色的都處理成背景色 } 
      if c <> AFontColor then 
        ABmpDesc.Canvas.Pixels[w, h] := ABkColor; 
    end;

效果如下:

image

(3)進行圖片分割

其實花時間最多的就是這步了,開始時考慮字符之間存在間隙,所以算法上以2個字符間的間隙為標准划分,結果發現存在多個字符連接在一起的情況,如下圖:

image

2個TT實際是連在一起的,中間沒有分割間隙,所以無法區分。后來又考慮采用等寬字符方式進行切割(網上常用算法),但是碰到了驗證碼圖片中的字符是不等寬的,還是不行。后采用了字符軌跡法,由於都是英文字符和數字,單個字符或數字的筆畫都是連在一起的,就把所有連在一起的筆畫內容識別為同一個字符。采用遞歸算法,取左上第一個字符的第一個像素,然后對該像素周圍8個像素進行掃描,記錄相鄰的像素,並對符合字體顏色的像素再次遞歸運算,直到沒有符合字體顏色的像素為止。效果還是可以,但是仍然沒有解決2個字符連在一起的情況,最后跳出這個思維圈子,干脆將連在一起的2個或多個字符共同識別為一個整體,即TT就當是一個字符處理,問題基本得到解決。

(4)進行分割后圖片特征碼提取

特征碼非常簡單,采用從上往下,從左向右依次獲取每個像素,如果是字體顏色像素則為1,否則為0。當然也可以采用其他算法的特征碼,只要能確定唯一性即可。然后將特征碼與字符關聯,並保存起來。

function GetbmpFlag(Abmp: TBitmap; AFontColor : TColor): String;
var
  w, h: Integer;
begin
  Result := '';
  { 獲取圖片特征碼 }
  for h := 0 to Abmp.Height -1 do
    for w := 0 to Abmp.Width -1 do
      if Abmp.Canvas.Pixels[w, h] = AFontColor then
        Result := Result + '0'
      else
        Result := Result + '1';
end;

4、學習

反復獲取驗證碼圖片,進行上述處理,並填寫人工識別后的驗證碼,以便軟件將字符對應的圖片特征碼與字符關聯起來,我的學習界面如下:

image

將學習好的特征碼保存到文件,以便在下次識別時載入。

5、正常識別

特征碼學習差不多后保存在磁盤文件上,當正式識別時,載入該特征碼,按照上述步驟進行處理:

(1)獲取驗證碼圖片

(2)二值化處理

(3)圖片分割

(4)獲取圖片特征碼

(5)根據圖片特征碼,在已學習的特征碼中進行查找,找到后返回其對應的字符,將所有分割后圖片的特征碼對應的字符組合起來就是驗證碼。

 

上述工作真正的難點在於2個:

1、二值化圖片

本次試驗的圖片比較簡單,如果遇到非常復雜的圖片,如:

1

且字體顏色還是隨機的,就比較麻煩了,必須對所有像素進行顏色統計,取其最多的4個顏色,我的統計圖如下:

image

顏色最多的4個即為字體顏色。但是也有特殊情況,如下圖:

2012090511294879164

其統計圖就比較雜亂了,如下圖:

image

字體顏色統計被背景顏色掩蓋了,按照上文提示,應采用HSL對色彩進行變化,然后進行統計,這項工作待有時間再進行。

 

2、圖片切割

本例中的圖片切割還是比較簡單的,對於復雜的、不規則的圖片,其切割可能更復雜。尤其是遇到多個字符上下部分位置有交叉,字符有隨機大小,字符與字符之間有粘連時,這種圖片切割更加復雜,這里不再討論,今后有時間再試試。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM