• 简单验证码识别



      最近几天比较空闲,于是也模仿网上的文章搞了搞验证码识别,当然是那些工整,规则,无码,无干扰,灰常纯净与单纯的验证码....
      当然也看了下网上找到的复杂的验证码(车牌号)识别资料,无奈做为一个半路出家,江湖四流的程序员,面对那么多数学公式只能做罢,一直以自己英语不好而痛心疾首,今天又认识到数学更是障碍, 记的前阵只有人说一个英语不好的程序员能走多远,现在我知道,一个英语不好但是数学很好的程序员能走很远,比英语好但数学不好的程序员要远多了,哎....

     步骤

          1.获取验证码图片
      2.灰度化与二值化图片
          3.切割图片
          4.建立特征库(这里使用每个像素二值化后的0,1字符串)
          5.使用特征库来识别图片

        1.获取图片:
         HttpWebRequest req = HttpWebRequest.Create("http://www.0576sy.cn/vcode.asp") as HttpWebRequest;
                Bitmap bmp=new Bitmap(  req.GetResponse().GetResponseStream());

       2.灰度化:
          首先解释下所谓的黑白图片。其实更准确地应该叫256级灰度图。当一个颜色点的R=G=B时,就是我们所谓的“灰色”。由于RGB的取值范围在[0,255],所以一共只有256种可能。

    所以彩色图片转为黑白图片的原理非常简单。只要扫描彩图的每一点,让输出图对应点的R=G=B就成了。现在问题的关键就是如何取值了。

    一般有两种,一种是彩图RGB三分量的算数平均值,另一种是加权平均值。加权平均是考虑到人类眼睛对不同分量的敏感程度。

     代码1(使用指针)

            /**//// <summary>
            /// 变成黑白图
            /// </summary>
            /// <param name="bmp">原始图</param>
            /// <param name="mode">模式。0:加权平均  1:算数平均</param>
            /// <returns></returns>
            private Bitmap ToGray(Bitmap bmp,int mode)
            {
                if (bmp == null)
                {
                    return null;
                }

                int w = bmp.Width;
                int h = bmp.Height;
                try
                {
                    byte newColor = 0;
                    BitmapData srcData = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                    unsafe
                    {
                        byte* p = (byte*)srcData.Scan0.ToPointer();
                        for (int y = 0; y < h; y++)
                        {
                            for (int x = 0; x < w; x++)
                            {

                                if (mode == 0) // 加权平均
                                {
                                    newColor = (byte)((float)p[0] * 0.114f + (float)p[1] * 0.587f + (float)p[2] * 0.299f);
                                }
                                else    // 算数平均
                                {
                                    newColor = (byte)((float)(p[0] + p[1] + p[2]) / 3.0f);
                                }
                                p[0] = newColor;
                                p[1] = newColor;
                                p[2] = newColor;

                                p += 3;
                            }
                            p += srcData.Stride - w * 3;
                        }
                        bmp.UnlockBits(srcData);
                        return bmp;
                    }
                }
                catch
                {
                    return null;
                }

            }

     代码二:

      使用Bitmap的 GetPixel与SetPixel ,验证码都是小图片,像素不多因此一般应用速度可以接受
            public void GrayByPixels(Bitmap bmp)
            {
                for (int i = 0; i < bmp.Height; i++)
                {
                    for (int j = 0; j < bmp.Width; j++)
                    {
                        Color pixel = bmp.GetPixel(j, i);
                        int tmpValue = (pixel.R * 19595 + pixel.G * 38469 + pixel.B * 7472) >> 16;
                      //除于2 ^ 16 次方,也就是按加权方式进行
                        bmp.SetPixel(j, i, Color.FromArgb(tmpValue, tmpValue, tmpValue));
                    }
                }
            }

     3.切割:

        代码1: 找出图片最左,最上,最右,最下的四个有效果点,按照这个矩形切割 

            /// <summary>
            /// 得到有效图形,图形由外面传入
            /// </summary>
            /// <param name="dgGrayValue">灰度背景分界值</param>
            /// <param name="CharsCount">有效字符数</param>
            /// <returns></returns>
            public Bitmap GetPicValidByValue(Bitmap singlepic, int dgGrayValue)
            {
                int posx1 = singlepic.Width; int posy1 = singlepic.Height;
                int posx2 = 0; int posy2 = 0;
                for (int i = 0; i < singlepic.Height; i++) //找有效区
                {
                    for (int j = 0; j < singlepic.Width; j++)
                    {
                        int pixelValue = singlepic.GetPixel(j, i).R;
                        if (pixelValue < dgGrayValue) //根据灰度值
                        {
                            if (posx1 > j) posx1 = j;
                            if (posy1 > i) posy1 = i;

                            if (posx2 < j) posx2 = j;
                            if (posy2 < i) posy2 = i;
                        };
                    };
                };
                //复制新图
                Rectangle cloneRect = new Rectangle(posx1, posy1, posx2 - posx1 + 1, posy2 - posy1 + 1);
                return singlepic.Clone(cloneRect, singlepic.PixelFormat);
            }

        固定切割比较简单,使用Bitmap.Clone 就可以完成,具体查看Clone的函数声明

       4.建立特征库: 这里使用矩阵来记录

               /// <summary>
            /// 返回灰度图片的点阵描述字串,1表示灰点,0表示背景
            /// </summary>
            /// <param name="singlepic">灰度图</param>
            /// <param name="dgGrayValue">背前景灰色界限</param>
            /// <returns></returns>
            public static string GetSingleBmpCode(Bitmap singlepic, int dgGrayValue)
            {
                Color piexl;
                string code = "";
                for (int posy = 0; posy < singlepic.Height; posy++)
                    for (int posx = 0; posx < singlepic.Width; posx++)
                    {
                        piexl = singlepic.GetPixel(posx, posy);
                        if (piexl.R < dgGrayValue) // Color.Black )
                            code = code + "1";
                        else
                            code = code + "0";
                    }
                return code;
            }

        最后每个切割出来的图片都会得出 011000111.... 这样的字符串,按0~9的顺序分别建立特征库即可

      看这个验证码:
      一个简单的验证码
     这个好象是动易早年asp产品中的一个验证码,其中的4个数字多是固定出现的,图片是40x10(像素),每个数字站10x10个像素,不过上面加入了少量的干扰像素,干扰像素很少最多一次刷出了6个点, 另外这些噪音很难去处,因为数字本身的像素就很稀薄,用网上找的"中值滤波"什么的一搞数字就没了,再考虑单独出现的像素基本在1,2个点,其他4,5个点都连在数字上,那么对比一个无干扰的数字图片段(10x10 ---100个像素),有干扰点所造成的像素差异应该在6%以内, 后来又对比了全部无干扰数字图片段的(0,1,2.....9等标准数字) 像素二值化后的0,1字符串,发现他们之间最接进的是 3,跟8,字符串中有93%的位是一样的, 基于上面分析于是选择94%作为分界点,将采集到的图片二值化后的字符串跟标准库中的字符串进行对比,如果两者有94%(这里就是94个像素)相同就当这两个图片是一样的.
     

    参考:
    车牌识别及验证码识别的一般思路
    http://blog.csdn.net/gisfarmer/archive/2009/02/05/3863630.aspx
    C# 图片处理之:彩色图片转为黑白图
    http://blog.csdn.net/ki1381/archive/2007/03/04/1520544.aspx
    用于验证码图片识别的类(C#源码)
    http://www.cnblogs.com/yuanbao/archive/2007/09/25/905322.html

  • 相关阅读:
    新院址运行统计
    游标使用之四
    游标使用之三
    css基础知识
    javascript基础知识
    [每日一题2020.06.20]BFS
    白嫖一个免费域名并解析到博客园
    [每日一题2020.06.19]leetcode #84 #121 单调栈
    操作系统---文件管理
    [每日一题2020.06.18]leetcode #3 hash_map实现滑动窗口
  • 原文地址:https://www.cnblogs.com/wdfrog/p/1451254.html
Copyright © 2020-2023  润新知