zoukankan      html  css  js  c++  java
  • 简单验证码的识别:Bitmap类的使用

      验证码的智能识别是一项比较复杂的工作,甚至需要掌握点图像学的知识。

      当然对于写程序的来说不用那么深入,只需要掌握几个常规步骤就行了。

      验证码图像识别步骤:1、获取图像  2、清除边框  3、灰度处理  4、二值化处理  5、噪点处理  6、图像分割  7、识别单个数字  8、拼接验证码

    一、获取图像

      图像一般是远程的,所以需要用到WebRequest:

         public Bitmap GetImg(string imgUrl)
            {
                WebRequest wreq = WebRequest.Create(imgUrl);
                wreq.Timeout = 10000;
                HttpWebResponse wresp = (HttpWebResponse)wreq.GetResponse();
                Stream s = wresp.GetResponseStream();
                return new Bitmap(s);
            }

    二、清除边框

      很多验证码周围都有一圈黑色的边框,因此需要用到以下操作:

            public Bitmap ClearBorder(Bitmap bm)
            {
                //去边框 width
                for (int i = 0; i < bm.Width; i++)
                {
                    bm.SetPixel(i, 0, Color.White);
                    bm.SetPixel(i, bm.Height - 1, Color.White);
                }
                //去边框 height
                for (int j = 0; j < bm.Height; j++)
                {
                    bm.SetPixel(0, j, Color.White);
                    bm.SetPixel(bm.Width - 1, j, Color.White);
                }
                return bm;
            }    

    三、灰度处理

      所谓的灰度处理即让五彩缤纷的图像变成深浅度不同的灰色图像。之所以如此是为了接下去的二值化处理。先看灰度处理:

            public Bitmap MakeGray(Bitmap bm)
            {
                for (int i = 0; i < bm.Width; i++)
                {
                    for (int j = 0; j < bm.Height; j++)
                    {
                        Color c = bm.GetPixel(i, j);//原始背景颜色
                        int gray = (int)(c.R * 0.11 + c.G * 0.59 + c.B * 0.3);//计算灰度
                        bm.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
                    }
                }
                return bm;
            }

      它的原理是遍历图像上的像素点,根据当前像素点的RGB颜色得到灰度,然后将灰度重新赋给当前像素点。

      灰度处理通常有以下三个方法(本例采用的公式2.2):

        clip_image006 (2.1)

        clip_image008 (2.2)

        clip_image010 (2.3)

      公式(2.1)取RGB通道的平均值,得到的图像相对比较柔和,同时也缩小了目标和背景的平均亮度差,不利于后续的阀值处理。

      公式(2.2)考虑了人眼对绿色的适应度最强,蓝色次之,红色最差。在处理绿色调和蓝色调的验证码图像时,公式(2.2)的效果令人满意,但在处理红色调的图像时,因为公式中红色的权值很小,灰度化后目标像素和背景像素的亮度差值被严重缩小,效果还不如公式(2.1)。

      公式(2.3)基于一个前提,那就是有限保留目标像素的亮度信息,利于后续的阀值分割。

      有关理论方面的可以参考此链接:http://www.cnblogs.com/chaosimple/archive/2013/07/18/3197720.html (感谢作者提供宝贵的资料)

    四、二值化处理

      二值化处理即让所有深浅度不同的灰色像素点变为黑白两种像素点,即二值化。

      在此需要找到一个临界值。大于该值的为白(背景),小于的为白(验证码)。

            public Bitmap MakeBlackWhite(Bitmap bm)
            {
                for (int i = 0; i < bm.Width; i++)
                {
                    for (int j = 0; j < bm.Height; j++)
                    {
                        Color c = bm.GetPixel(i, j);//背景颜色
                        if (c.B > 37)  //当前像素点与临界值判断
                        {
                            bm.SetPixel(i, j, Color.White);
                        }
                        else
                        {
                            bm.SetPixel(i, j, Color.Black);
                        }
                    }
                }
                return bm;
            }

    五、噪点处理

      所谓的噪点处理,就是把一些零零碎碎的点去掉,使其得到干净整洁的图像。

      

            public Bitmap ClearPieces(Bitmap bm)
            {
                for (int i = 1; i < bm.Width - 1; i++)
                {
                    for (int j = 1; j < bm.Height - 1; j++)
                    {
                        Color c = bm.GetPixel(i, j);//原始背景颜色
                        Color cUp = bm.GetPixel(i, j - 1);
                        Color cDown = bm.GetPixel(i, j + 1);
                        Color cLeft = bm.GetPixel(i - 1, j);
                        Color cRight = bm.GetPixel(i + 1, j);
                        //Response.Write(c.R + "  " + c.G + "  " + c.B + "  <br />");
                        if (c.R == 0 && cUp.R != 0 && cDown.R != 0 && cLeft.R != 0 && cRight.R != 0)
                        {
                            bm.SetPixel(i, j, Color.White);
                        }
                    }
                }
                return bm;
            }    

    六、图像切割

        public Bitmap SplitImg(Bitmap bm,int pointX,int pointY)
            {
                Bitmap first = new Bitmap(cutWidth, cutHeight, PixelFormat.Format32bppRgb);for (int i = 0; i < first.Width; i++)
                {
                    for (int j = 0; j < first.Height; j++)
                    {
                        Color c = bm.GetPixel(pointX + i, pointY + j);
                        first.SetPixel(i, j, c);
                    }
                }
           return first; }

      这样就得到了验证码中的只包含一个数字的图片。

    七、识别单个数字

    public string GetOneNumber(Bitmap first)
            {
                StringBuilder strFir = new StringBuilder("");
                for (int i = 0; i < first.Width; i++)
                {
                    for (int j = 0; j < first.Height; j++)
                    {
                        Color c = bm.GetPixel( i,  j);
                        if (c.R == 0)
                        {
                            strFir.Append("0");
                        }
                        else
                        {
                            strFir.Append("1");
                        }
                    }
                }
                int result = 0;
                string num = "";
                List<string> numbers = verifyHelper.GetList();
                for (int j = 0; j < numbers.Count(); j++)
                {
                    result = 0;
                    for (int i = 0; i < strFir.Length; i++)
                    {
                        if (strFir[i] == numbers[j][i])
                        {
                            result++;
                        }
                        if (result > 110)
                        {
                            num = j.ToString();
                            return num;
                        }
    
                    }
                }
                return "-1";    

    八、最后拼接

                result += GetOneNumber(bm, 8, 4);
                result += GetOneNumber(bm, 20, 2);
                result += GetOneNumber(bm, 35, 5);
                result += GetOneNumber(bm, 45, 2);

    综合起来需要做的操作是

            public string GetNumbers(string imgUrl)
            {
                Bitmap bm = new Bitmap(GetImgStream(imgUrl));
    
                bm = ClearBorder(bm);
                bm = MakeGray(bm);
                bm = MakeBlackWhite(bm);
                bm = ClearPieces(bm);
    
                string result = "";
                result += GetOneNumber(bm, 8, 4);
                result += GetOneNumber(bm, 20, 2);
                result += GetOneNumber(bm, 35, 5);
                result += GetOneNumber(bm, 45, 2);
                if(result.Contains("-1"))
                {
                    return "-1";
                }
                else
                {
                    return result;
                }
            }
  • 相关阅读:
    原单,尾货的科普贴
    c code
    考试
    一个笔试题
    注意自己的聊天内容可能招致被拐卖儿童
    酷壳网陈皓:开发者实用学习资源汇总[转]
    性格测试
    最实用的心理调节技巧,让你的情感细胞提升一下吧!
    Makefile教程
    Extjs中的迭代
  • 原文地址:https://www.cnblogs.com/dengshaojun/p/4081878.html
Copyright © 2011-2022 走看看