C#简单数字验证码解析

10 篇文章 0 订阅

原文地址:http://www.cnblogs.com/ivanyb/archive/2011/11/25/2262964.html

这几天都在研究验证码解析,写了一个DEMO,对于纯数字且生成位置变化频率较低的图片识别效果还算满意,准确率在80%以上,更高级别的验证码还有待研究。

CSharp简单数字验证码解析.rar

 

具体实现思路:以4位数字的验证码为例

1、人工将验证码的4位数字每位对应的代码存入数据库中,每位存入0-9对应的代码,每个数可以多存这样可以提高识别率;

2、获取验证码image以后,对其进行去背景、灰度处理、去噪点处理、分片处理以后生成每位数字对应的代码;

3、去背景色,这一步的目的是把验证码和背景颜色区别开来。

去除背景的算法,依赖于验证码图像的特征:

1、首先需要知道背景色  
  最简单的方法就是把最左上角的点的量化值作为背景色。
  优化一点可以取图像矩形的topleft,topright,bottomleft,bottomright这4个点比对。
  或者取更边界上更多点比对。

2、扫描m*n图像矩形,从每个具有背景色的点出发找到整个连接块,设置matrix[i,j]=0。
  这是一个很简单的带剪枝的DFS算法,很快就能把背景色去除,本例用第二种。

4、去噪声:这一步要取出图像上的孤立点。这些孤立点被认为是噪声。
  孤立点的定义:某个点,周围没有与该点等值的点。
  或者某个连接块,该连接块的元素的个数小于某个给定值K, 把元素个数很小的连接块也定义为孤立点,有助于去处噪声。
  去噪声算法:参照去背景算法。

5、图像锐化:图像锐化的目的是增强边界。这一步是可选的。看验证码的情况,这一步可以跳过。

6、图片有效区域截取:这个操作是将图片除验证码字符以外的边框去掉,只留下验证码字符图片,这样保证分片的准确性。

7、图片分片处理,这个处理是将整个图片分割成单个字符图片。

1、连接块法:找到矩阵中除背景外所有的连接块,把每个连接块作为一个子图。
  不适用于子图存在断裂的情形。
   实现:带剪枝的DFS。

2、子图分割:如果验证码是定长的,且字符之间等距。
  可以用一个简单的垂直分割把子图提取出来。
  这种方法适用于子图断裂,用连接块法提取失败的情形。 本例用第二种。

3、有某些类型的验证码用上面2个方法都难以提取子图

8、拿分片图像生成的代码(eg:000111110011…..)与DB中已有代码相比较,取得相似度最高的即要验证码的字符;

 

注:如果DB的样本越多,识别的准确率也越高,但是速度会相应变慢

 

主要实现方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/// <summary>
         /// 根据RGB,计算灰度值
         /// </summary>
         /// <param name="posClr">Color值</param>
         /// <returns>灰度值,整型</returns>
         private  int  GetGrayNumColor(System.Drawing.Color posClr)
         {
             return  (posClr.R * 19595 + posClr.G * 38469 + posClr.B * 7472) >> 16;
         }
 
         /// <summary>
         /// 灰度转换,逐点方式
         /// </summary>
         public  Bitmap GrayByPixels()
         {
             for  ( int  i = 0; i < bmpobj.Height; i++)
             {
                 for  ( int  j = 0; j < bmpobj.Width; j++)
                 {
                     int  tmpValue = GetGrayNumColor(bmpobj.GetPixel(j, i));
                     bmpobj.SetPixel(j, i, Color.FromArgb(tmpValue, tmpValue, tmpValue));
                 }
             }
             return  bmpobj;
         }

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
/// <summary>
         /// 得到图片有效区域,使切分图片更加精确
         /// </summary>
         /// <param name="_bitmap"></param>
         /// <returns></returns>
         private  Bitmap CutMap(Bitmap _bitmap)
         {
             Rectangle rg = new  Rectangle( int .Parse(updX.Value.ToString()), int .Parse(updY.Value.ToString()), _bitmap.Width - int .Parse(updW.Value.ToString()), _bitmap.Height - int .Parse(updH.Value.ToString()));
             //Rectangle rg = new Rectangle(1, 0, _bitmap.Width - 10, _bitmap.Height );
             Bitmap bitmap = _bitmap.Clone(rg, _bitmap.PixelFormat);
             return  bitmap;
 
         }

 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/// <summary>
         /// 切分图片
         /// </summary>
         /// <param name="_bitmap"></param>
         /// <param name="row"></param>
         /// <param name="col"></param>
         /// <returns></returns>
         private  Bitmap[] SplitImg(Bitmap _bitmap, int  row, int  col)
         {
             int  singW = _bitmap.Width / row;
             int  singH = _bitmap.Height / col;
             Bitmap[] arrmap = new  Bitmap[row * col];
             Rectangle rect;
             for  ( int  i = 0; i < col; i++)
             {
                 for  ( int  j = 0; j < row; j++)
                 {
                     rect = new  Rectangle(j * singW, i * singH, singW, singH);
                     arrmap[i * row + j] = _bitmap.Clone(rect, _bitmap.PixelFormat);
                 }
             }
 
             return  arrmap;
         }

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/// <summary>
         /// 获取数字对应的二值化代码
         /// </summary>
         /// <param name="_bitmap"></param>
         /// <param name="p"></param>
         /// <returns></returns>
         private  string  GetCodebybitmap(Bitmap _bitmap, Panel p)
         {
             StringBuilder code = new  StringBuilder();
             Graphics g = p.CreateGraphics();
             for  ( int  i = 0; i < _bitmap.Width; i++)
             {
                 for  ( int  j = 0; j < _bitmap.Height; j++)
                 {
                     int  r = _bitmap.GetPixel(i, j).R;
                     if  (r < 100) //常用的是灰度128
                     {
                         code.Append( "1" );
                         g.DrawString( "-" , new  Font( "宋体" , 12), new  SolidBrush(Color.Blue), new  Rectangle(i * 5, j * 5, 12, 12));
                     }
                     else
                     {
                         code.Append( "0" );
                     }
                 }
             }
 
             return  code.ToString();
 
         }

效果:

image

人生无处不PK

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值