因朋友需求,對某網站的驗證碼圖片進行自動識別,原以為是個復雜的問題,后來查看了網上的一些資料,總體思路上參考了:
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)進行圖片二值化
對於本次識別的圖片,非常簡單,如下圖:
進行色彩分析,將相同顏色的像素進行計數后發現只有三種顏色:背景色、干擾色和字體藍色。做二值化處理時就比較簡單了,逐個處理像素點,將干擾色處理成背景色:
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;
效果如下:
(3)進行圖片分割
其實花時間最多的就是這步了,開始時考慮字符之間存在間隙,所以算法上以2個字符間的間隙為標准划分,結果發現存在多個字符連接在一起的情況,如下圖:
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、學習
反復獲取驗證碼圖片,進行上述處理,並填寫人工識別后的驗證碼,以便軟件將字符對應的圖片特征碼與字符關聯起來,我的學習界面如下:
將學習好的特征碼保存到文件,以便在下次識別時載入。
5、正常識別
特征碼學習差不多后保存在磁盤文件上,當正式識別時,載入該特征碼,按照上述步驟進行處理:
(1)獲取驗證碼圖片
(2)二值化處理
(3)圖片分割
(4)獲取圖片特征碼
(5)根據圖片特征碼,在已學習的特征碼中進行查找,找到后返回其對應的字符,將所有分割后圖片的特征碼對應的字符組合起來就是驗證碼。
上述工作真正的難點在於2個:
1、二值化圖片
本次試驗的圖片比較簡單,如果遇到非常復雜的圖片,如:
且字體顏色還是隨機的,就比較麻煩了,必須對所有像素進行顏色統計,取其最多的4個顏色,我的統計圖如下:
顏色最多的4個即為字體顏色。但是也有特殊情況,如下圖:
其統計圖就比較雜亂了,如下圖:
字體顏色統計被背景顏色掩蓋了,按照上文提示,應采用HSL對色彩進行變化,然后進行統計,這項工作待有時間再進行。
2、圖片切割
本例中的圖片切割還是比較簡單的,對於復雜的、不規則的圖片,其切割可能更復雜。尤其是遇到多個字符上下部分位置有交叉,字符有隨機大小,字符與字符之間有粘連時,這種圖片切割更加復雜,這里不再討論,今后有時間再試試。





