验证码识别

8/3/2015来源:C#应用人气:1859

验证码识别

Posted on 2014-10-29 23:39 gaogaolater 阅读(...) 评论(...) 编辑 收藏

  距离上次写博客又很长时间了,这个验证码识别模块其实自己早写出来就是懒的写博客,现在离职了有时间把它拿出来。 总体说来这个验证码还是有一定难度的:字母数量不固定、位置不固定、带倾斜角度、带粘连、有噪点和干扰线。所以识别率还是比较低的,有个十分之一吧,但是识别出来就可以了,反正是软件识别,又不是人识别。这个验证码识别模块是专门针对此类验证码优化的,所以如果想识别其他验证码估计稍改一下源码就行。

源代码

首先看界面:

界面有很多按钮,我按照顺序说一下,其实就是识别的顺序

1、获取验证码(动态从某网址获取)

2、去背景

3、去干扰

4、二值化

5、分割

6、识别

7、如果识别错误,同时某字母有识别的价值,就对应分割字母的顺序找到下面对应的框填上正确的字母,然后点击学习。下次再出现类似字母就可以正确识别了。

比如这次识别h错误,那就可以在对应的框中填写h然后点击学习。但是这个 h字母左上角有个黑色干扰块,没有学习的价值。

  

   下面贴上一些源代码,大家也可以点击上面的链接下载源代码查看,注意不能删除Debug下的Sample文件夹。代码里面都有注释:

1、去背景代码:

 原理:把图片中颜色数量最多的一部分看成背景并替换为白色,相当于去除背景。

 1         /// <summary> 2         /// 去背景 3         /// 把图片中最多的一部分颜色视为背景色 选出来后替换为白色 4         /// </summary> 5         /// <param name="sender"></param> 6         /// <param name="e"></param> 7         PRivate void btnDropBG_Click(object sender, EventArgs e) 8         { 9             if (picbox.Image == null)10             {11                 return;12             }13             Bitmap img = new Bitmap(picbox.Image);14             //key 颜色  value颜色对应的数量15             Dictionary<Color, int> colorDic = new Dictionary<Color, int>();16             //获取图片中每个颜色的数量17             for (var x = 0; x < img.Width; x++)18             {19                 for (var y = 0; y < img.Height; y++)20                 {21                     //删除边框22                     if (y == 0 || y == img.Height)23                     {24                         img.SetPixel(x, y, Color.White);25                     }26 27                     var color = img.GetPixel(x, y);28                     var colorRGB = color.ToArgb();29 30                     if (colorDic.ContainsKey(color))31                     {32                         colorDic[color] = colorDic[color] + 1;33                     }34                     else35                     {36                         colorDic[color] = 1;37                     }38                 }39             }40             //图片中最多的颜色41             Color maxColor = colorDic.OrderByDescending(o => o.Value).FirstOrDefault().Key;42             //图片中最少的颜色43             Color minColor = colorDic.OrderBy(o => o.Value).FirstOrDefault().Key;44 45             Dictionary<int[], double> maxColorDifDic = new Dictionary<int[], double>();46             //查找 maxColor 最接近颜色47             for (var x = 0; x < img.Width; x++)48             {49                 for (var y = 0; y < img.Height; y++)50                 {51                     maxColorDifDic.Add(new int[] { x, y }, GetColorDif(img.GetPixel(x, y), maxColor));52                 }53             }54             //去掉和maxColor接近的颜色 即 替换成白色55             var maxColorDifList = maxColorDifDic.OrderBy(o => o.Value).Where(o => o.Value < bjfz).ToArray();56             foreach (var kv in maxColorDifList)57             {58                 img.SetPixel(kv.Key[0], kv.Key[1], Color.White);59             }60             picbox.Image = img;61             pbNormal.Image = picbox.Image;62         }

2、去干扰代码、

原理:如果一个像素和周围上下左右四个像素点中的两面或三面颜色差别都很大,则认为这个点是噪点或干扰线。看到网上资料中有用中值滤波算法的,但是效果不好。

  1         /// <summary>  2         /// 去干扰  3         /// </summary>  4         /// <param name="sender"></param>  5         /// <param name="e"></param>  6         private void btnDropDisturb_Click(object sender, EventArgs e)  7         {  8             if (picbox.Image == null)  9             { 10                 return; 11             } 12             Bitmap img = new Bitmap(picbox.Image); 13             byte[] p = new byte[9]; //最小处理窗口3*3 14             byte s; 15             //去干扰线 16             for (var x = 0; x < img.Width; x++) 17             { 18                 for (var y = 0; y < img.Height; y++) 19                 { 20                     Color currentColor = img.GetPixel(x, y); 21                     int color = currentColor.ToArgb(); 22                     23                     if (x > 0 && y > 0 && x < img.Width - 1 && y < img.Height - 1) 24                     { 25                         #region 中值滤波效果不好 26                         ////取9个点的值 27                         //p[0] = img.GetPixel(x - 1, y - 1).R; 28                         //p[1] = img.GetPixel(x, y - 1).R; 29                         //p[2] = img.GetPixel(x + 1, y - 1).R; 30                         //p[3] = img.GetPixel(x - 1, y).R; 31                         //p[4] = img.GetPixel(x, y).R; 32                         //p[5] = img.GetPixel(x + 1, y).R; 33                         //p[6] = img.GetPixel(x - 1, y + 1).R; 34                         //p[7] = img.GetPixel(x, y + 1).R; 35                         //p[8] = img.GetPixel(x + 1, y + 1).R; 36                         ////计算中值 37                         //for (int j = 0; j < 5; j++) 38                         //{ 39                         //    for (int i = j + 1; i < 9; i++) 40                         //    { 41                         //        if (p[j] > p[i]) 42                         //        { 43                         //            s = p[j]; 44                         //            p[j] = p[i]; 45                         //            p[i] = s; 46                         //        } 47                         //    } 48                         //} 49                         ////      if (img.GetPixel(x, y).R < dgGrayValue) 50                         //img.SetPixel(x, y, Color.FromArgb(p[4], p[4], p[4]));    //给有效值付中值 51                         #endregion 52  53                         //上 x y+1 54                         double upDif = GetColorDif(currentColor, img.GetPixel(x, y + 1)); 55                         //下 x y-1 56                         double downDif = GetColorDif(currentColor, img.GetPixel(x, y - 1)); 57                         //左 x-1 y 58                         double leftDif = GetColorDif(currentColor, img.GetPixel(x - 1, y)); 59                         //右 x+1 y 60                         double rightDif = GetColorDif(currentColor, img.GetPixel(x + 1, y)); 61                         //左上 62                         double upLeftDif = GetColorDif(currentColor, img.GetPixel(x - 1, y + 1)); 63                         //右上 64                         double upRightDif = GetColorDif(currentColor, img.GetPixel(x + 1, y + 1)); 65                         //左下 66                         double downLeftDif = GetColorDif(currentColor, img.GetPixel(x - 1, y - 1)); 67                         //右下 68                         double downRightDif = GetColorDif(currentColor, img.GetPixel(x + 1, y - 1)); 69  70                         ////四面色差较大 71                         //if (upDif > threshold && downDif > threshold && leftDif > threshold && rightDif > threshold) 72                         //{ 73                         //    img.SetPixel(x, y, Color.White); 74                         //} 75                         //三面色差较大 76                         if ((upDif > threshold && downDif > threshold && leftDif > threshold) 77                             || (downDif > threshold && leftDif > threshold && rightDif > threshold) 78                             || (upDif > threshold && leftDif > threshold && rightDif > threshold) 79                             || (upDif > threshold && downDif > threshold && rightDif > threshold)) 80                         { 81                             img.SetPixel(x, y, Color.White); 82                         } 83  84                         List<int[]> xLine = new List<int[]>(); 85                         //去横向干扰线  原理 如果这个点上下有很多白色像素则认为是干扰 86                         for (var x1 = x + 1; x1 < x + 10; x1++) 87                         { 88                             if (x1