Aforge.net之旅——開篇:從識別驗證碼開始


  時間過得真快啊,轉眼今年就要過去了,大半年都沒有寫博客了,要說時間嘛,花在泡妹子和搞英語去了,哈哈。。。前幾天老大問我

怎么這么長時間都沒寫博客了,好吧,繼續堅持,繼續分享我的心得體會。

  這個系列我們玩玩aforge.net,套用官方都話就是一個專門為開發者和研究者基於C#框架設計的,這個框架提供了不同的類庫和關於類庫的

資源,還有很多應用程序例子,包括計算機視覺與人工智能,圖像處理,神經網絡,遺傳算法,機器學習,機器人等領域,這個系列研究的重點

就是瞎幾把搞下AForge.Imaging這個命名空間下面的東東,下載網址:http://www.aforgenet.com/framework/downloads.html

    對了,不知道有多少公司是用得仕卡作為員工的福利卡,我們公司就是這樣的,每個月公司都會充值一些money,然后我們這些屁碼農每個

月15號就都開心的去看看發了多少。

上去看了后,喲呵~ 還有個90年代的驗證碼,我想這年頭估計找到這樣驗證碼的網站已經不多了,如果懂一點圖像處理都話,這張驗證碼

跟沒有一個樣,謝謝。。。這篇我們看看怎么去識別它。

 

一: 驗證碼處理

1.  一般處理原則

    這種驗證碼為什么說跟沒有一樣,第一點:字體規范工整,第二點:不旋轉扭曲粘連,第三點:字體顏色單一,下面看處理步驟

這里要注意的是,aforge只接受像素格式為24/32bpp的像素格式圖片,所以處理前,先進行格式轉化。

            //轉化圖片像素格式
            var bnew = new Bitmap(b.Width, b.Height, PixelFormat.Format24bppRgb);

            Graphics g = Graphics.FromImage(bnew);

            g.DrawImage(b, 0, 0);

            g.Dispose();

 

 <1>圖片灰度化

    這是圖像識別通常都要走的第一步,圖片灰度化有助於減少后續對rgb的計算量,同時也方便我們進行二值化,在aforge中我們有

專門的類一步搞定,簡潔方便。

            //灰度化
            b = new Grayscale(0.2125, 0.7154, 0.0721).Apply(b);


<2>二值化

  二值化顧名思義就是二種值,比如非白即黑,非黑即白,那么白和黑的標准就需要提供一個閾值,大於或者小於怎么樣,在aforge同樣

也有相似的類進行處理

            //二值化
            b = new Threshold(50).Apply(b);

<3> 去噪點

  從上面的圖片可以發現有很多紅點點,搞得像皮膚病一樣,仔細觀察可以看到這種噪點具有獨立,體積小的特征,所以判斷的標准就是如果

圖中某個區塊的大小在我設置的閾值內,就將其去掉,同樣也有專門的類進行處理。

            //去噪點
            new BlobsFiltering(1, 1, b.Width, b.Height).Apply(b);

  這里具體怎么傳遞參數,后續系列會慢慢解讀。

<4>切割圖片

   切圖片的好處在於我們需要知道真正要識別的元素的有效范圍是多大,同時也方便我們將這些圖片作為模板保存下來。

代碼如下:

  1        /// <summary>
  2         /// 按照 Y 軸線 切割
  3         /// (丟棄等於號)
  4         /// </summary>
  5         /// <param name="?"></param>
  6         /// <returns></returns>
  7         public List<Bitmap> Crop_Y(Bitmap b)
  8         {
  9             var list = new List<Bitmap>();
 10 
 11             //統計每一列的“1”的個數,方便切除
 12             int[] cols = new int[b.Width];
 13 
 14             /*
 15              *  縱向切割
 16              */
 17             for (int x = 0; x < b.Width; x++)
 18             {
 19                 for (int y = 0; y < b.Height; y++)
 20                 {
 21                     //獲取當前像素點像素
 22                     var pixel = b.GetPixel(x, y);
 23 
 24                     //說明是黑色點
 25                     if (pixel.R == 0)
 26                     {
 27                         cols[x] = ++cols[x];
 28                     }
 29                 }
 30             }
 31 
 32             int left = 0, right = 0;
 33 
 34             for (int i = 0; i < cols.Length; i++)
 35             {
 36                 //說明該列有像素值(為了防止像素干擾,去噪后出現空白的問題,所以多判斷一下,防止切割成多個)
 37                 if (cols[i] > 0 || (i + 1 < cols.Length && cols[i + 1] > 0))
 38                 {
 39                     if (left == 0)
 40                     {
 41                         //切下來圖片的橫坐標left
 42                         left = i;
 43                     }
 44                     else
 45                     {
 46                         //切下來圖片的橫坐標right
 47                         right = i;
 48                     }
 49                 }
 50                 else
 51                 {
 52                     //說明已經有切割圖了,下面我們進行切割處理
 53                     if ((left > 0 || right > 0))
 54                     {
 55                         Crop corp = new Crop(new Rectangle(left, 0, right - left + 1, b.Height));
 56 
 57                         var small = corp.Apply(b);
 58 
 59                         //居中,將圖片放在20*50的像素里面
 60 
 61                         list.Add(small);
 62                     }
 63 
 64                     left = right = 0;
 65                 }
 66             }
 67 
 68             return list;
 69         }
 70 
 71         /// <summary>
 72         /// 按照 X 軸線 切割
 73         /// </summary>
 74         /// <param name="b"></param>
 75         /// <returns></returns>
 76         public List<Bitmap> Crop_X(List<Bitmap> list)
 77         {
 78             var corplist = new List<Bitmap>();
 79 
 80             //再對分割的圖進行上下切割,取出上下的白邊
 81             foreach (var segb in list)
 82             {
 83                 //統計每一行的“1”的個數,方便切除
 84                 int[] rows = new int[segb.Height];
 85 
 86                 /*
 87                  *  橫向切割
 88                  */
 89                 for (int y = 0; y < segb.Height; y++)
 90                 {
 91                     for (int x = 0; x < segb.Width; x++)
 92                     {
 93                         //獲取當前像素點像素
 94                         var pixel = segb.GetPixel(x, y);
 95 
 96                         //說明是黑色點
 97                         if (pixel.R == 0)
 98                         {
 99                             rows[y] = ++rows[y];
100                         }
101                     }
102                 }
103 
104                 int bottom = 0, top = 0;
105 
106                 for (int y = 0; y < rows.Length; y++)
107                 {
108                     //說明該行有像素值(為了防止像素干擾,去噪后出現空白的問題,所以多判斷一下,防止切割成多個)
109                     if (rows[y] > 0 || (y + 1 < rows.Length && rows[y + 1] > 0))
110                     {
111                         if (top == 0)
112                         {
113                             //切下來圖片的top坐標
114                             top = y;
115                         }
116                         else
117                         {
118                             //切下來圖片的bottom坐標
119                             bottom = y;
120                         }
121                     }
122                     else
123                     {
124                         //說明已經有切割圖了,下面我們進行切割處理
125                         if ((top > 0 || bottom > 0) && bottom - top > 0)
126                         {
127                             Crop corp = new Crop(new Rectangle(0, top, segb.Width, bottom - top + 1));
128 
129                             var small = corp.Apply(segb);
130 
131                             corplist.Add(small);
132                         }
133 
134                         top = bottom = 0;
135                     }
136                 }
137             }
138 
139             return corplist;
140         }

 

<5> 圖片精處理

  這里要注意的是,比如數字“2”,切除上下左右的空白后,再加上噪點的干擾,不一定每次切下來的圖片大小都一樣,所以這里

為了方便更好的識別,我們需要重置下圖片的大小,並且將“數字2”進行文字居中。

 1         /// <summary>
 2         /// 重置圖片的指定大小並且居中
 3         /// </summary>
 4         /// <param name="list"></param>
 5         /// <returns></returns>
 6         public List<Bitmap> ToResizeAndCenterIt(List<Bitmap> list, int w = 20, int h = 20)
 7         {
 8             List<Bitmap> resizeList = new List<Bitmap>();
 9 
10 
11             for (int i = 0; i < list.Count; i++)
12             {
13                 //反轉一下圖片
14                 list[i] = new Invert().Apply(list[i]);
15 
16                 int sw = list[i].Width;
17                 int sh = list[i].Height;
18 
19                 Crop corpFilter = new Crop(new Rectangle(0, 0, w, h));
20 
21                 list[i] = corpFilter.Apply(list[i]);
22 
23                 //再反轉回去
24                 list[i] = new Invert().Apply(list[i]);
25 
26                 //計算中心位置
27                 int centerX = (w - sw) / 2;
28                 int centerY = (h - sh) / 2;
29 
30                 list[i] = new CanvasMove(new IntPoint(centerX, centerY), Color.White).Apply(list[i]);
31 
32                 resizeList.Add(list[i]);
33             }
34 
35             return resizeList;
36         }

其實精處理后,這些圖片就可以作為我們的模板庫的圖片了,可以將每張模板圖都標記下具體的數字,后續我們再遇到時,計算下其相似度

就可以了,下面就是已經制作好的模板。

<6> 模板匹配識別

  既然模板圖片都制作好了,一切都差不多水到渠成了,下次來的驗證碼我都切好后做成精圖片后跟模板進行匹配,在afroge里面

有一個ExhaustiveTemplateMatching,專門用來進行模板匹配用的,很方便。

 ExhaustiveTemplateMatching templateMatching = new ExhaustiveTemplateMatching(0.9f);

這里的0.9f就是設定的閾值,只有大於0.9的閾值,我才認為該模板與目標圖片相似,然后在所有大於0.9的相似度中取到最大的一個作為

我們最后識別的圖像。

 1            var files = Directory.GetFiles(Environment.CurrentDirectory + "\\Template\\");
 2 
 3             var templateList = files.Select(i => { return new Bitmap(i); }).ToList();
 4             var templateListFileName = files.Select(i => { return i.Substring(30, 1); }).ToList();
 5 
 6             var result = new List<string>();
 7 
 8             ExhaustiveTemplateMatching templateMatching = new ExhaustiveTemplateMatching(0.9f);
 9 
10             //這里面有四張圖片,進行四張圖的模板匹配
11             for (int i = 0; i < list.Count; i++)
12             {
13                 float max = 0;
14                 int index = 0;
15 
16                 for (int j = 0; j < templateList.Count; j++)
17                 {
18                     var compare = templateMatching.ProcessImage(list[i], templateList[j]);
19 
20                     if (compare.Length > 0 && compare[0].Similarity > max)
21                     {
22                         //記錄下最相似的
23                         max = compare[0].Similarity;
24                         index = j;
25                     }
26                 }
27 
28                 result.Add(templateListFileName[index]);
29             }

最后的效果還是不錯的,識別率基本100%吧。

 


免責聲明!

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



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