zoukankan      html  css  js  c++  java
  • c#验证码识别、图片二值化、分割、分类、识别(转载)

    c# 验证码的识别主要分为预处理、分割、识别三个步骤

    首先我从网站上下载验证码

    处理结果如下:

    1.图片预处理,即二值化图片

    *就是将图像上的像素点的灰度值设置为0或255。

    原理如下:

    代码如下:

    #region 二值化图片
            /// <summary>
            /// 二值化图片
            /// 就是将图像上的像素点的灰度值设置为0或255
            /// </summary>
            /// <returns>处理后的验证码</returns>
            public Bitmap BinaryZaTion()
            {
                for (int x = 0; x < img.Width; x++)
                {
                    for (int y = 0; y < img.Height; y++)
                    {
                        __c = img.GetPixel(x, y);
                        //灰度值
                        int __tc = (__c.R + __c.G + __c.B) / 3;
                        //大于阙值 黑色
                        if (__tc > t)
                        {
                            img.SetPixel(x, y, Color.FromArgb(__c.A, b, b, b));
                            //黑色点个数自加
                            __blackNum++;
                        }
                        //大于阙值 白色
                        else
                        {
                            img.SetPixel(x, y, Color.FromArgb(__c.A, w, w, w));
                        }
                    }
                }
                return img;
            }
            #endregion


    二值化过后需要判断图片的黑白比列,若果黑色比白色多,需要对图片反色处理。

    代码如下:

     #region 是否需要反色
            /// <summary>
            /// 是否需要反色
            /// </summary>
            /// <returns>是否需要反色</returns>
            public bool IsNeedInverseColor()
            {
                if ((__blackNum * 1.0 / (img.Width * img.Height)) > 0.5)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            #endregion
    
            #region 反色
            /// <summary>
            /// 反色
            /// </summary>
            /// <returns>处理后的验证码</returns>
            public Bitmap InverseColor()
            {
                for (int x = 0; x < img.Width; x++)
                {
                    for (int y = 0; y < img.Height; y++)
                    {
                        __c = img.GetPixel(x, y);
                        img.SetPixel(x, y, Color.FromArgb(__c.A, w - __c.R, w - __c.G, w - __c.B));
                    }
                }
                return img;
            }
            #endregion


    处理结果如下:

    2.图片分割

    我的做法是先每一竖行判断是否是纯白色行,不是的话记录当前x坐标,然后没以横行判断是否纯白色行,这样就能的到每一个数字的区域,然后将区域画出来。

    代码如下:

     #region 分割图片
            /// <summary>
            /// 分割图片
            /// </summary>
            /// <returns>处理后的验证码</returns>
            public Bitmap CutImg()
            {
                //Y轴分割
                CutY();
                //区域个数
                __count = 0;
                if (XList.Count > 1)
                {
                    //x起始值
                    int __start = XList[0];
                    //x结束值
                    int __end = XList[XList.Count - 1];
                    //x索引
                    int __idx = 0;
                    while (__start != __end)
                    {
                        //区域宽度
                        int __w = __start;
                        //区域个数自加
                        __count++;
                        while (XList.Contains(__w) && __idx < XList.Count)
                        {
                            //区域宽度自加
                            __w++;
                            //x索引自加
                            __idx++;
                        }
                        //区域X轴坐标
                        int x = __start;
                        //区域Y轴坐标
                        int y = 0;
                        //区域宽度
                        int width = __w - __start;
                        //区域高度
                        int height = img.Height;
                        /*
                         * X轴分割当前区域
                         */
                        CutX(img.Clone(new Rectangle(x, y, width, height), img.PixelFormat));
                        if (YList.Count > 1 && YList.Count != img.Height)
                        {
                            int y1 = YList[0];
                            int y2 = YList[YList.Count - 1];
                            if (y1 != 1)
                            {
                                y = y1 - 1;
                            }
                            height = y2 - y1 + 1;
                        }
                        //GDI+绘图对象
                        Graphics g = Graphics.FromImage(img);
                        g.SmoothingMode = SmoothingMode.HighQuality;
                        g.CompositingMode = CompositingMode.SourceOver;
                        g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        //画出验证码区域
                        g.DrawRectangle(new Pen(Brushes.Green), new Rectangle(x, y, width, height));
                        g.Dispose();
                        //起始值指向下一组
                        if (__idx < XList.Count)
                        {
                            __start = XList[__idx];
                        }
                        else
                        {
                            __start = __end;
                        }
    
                    }
                }
                return img;
            }
            #endregion
    
            #region Y轴字符分割图片
            /// <summary>
            /// 得到Y轴分割点
            /// 判断每一竖行是否有黑色
            /// 有则添加
            /// </summary>
            /// <param name="img">要验证的图片</param>
            private void CutY()
            {
                XList.Clear();
                for (int x = 0; x < img.Width; x++)
                {
                    isWhilteLine = false;
                    for (int y = 0; y < img.Height; y++)
                    {
                        __c = img.GetPixel(x, y);
                        if (__c.R == w)
                        {
                            isWhilteLine = true;
                        }
                        else
                        {
                            isWhilteLine = false;
                            break;
                        }
                    }
                    if (!isWhilteLine)
                    {
                        XList.Add(x);
                    }
                }
            }
            #endregion
    
            #region X轴字符分割图片
            /// <summary>
            /// 得到X轴分割点
            /// 判断每一横行是否有黑色
            /// 有则添加
            /// </summary>
            /// <param name="tempImg">临时区域</param>
            private void CutX(Bitmap tempImg)
            {
                YList.Clear();
                for (int x = 0; x < tempImg.Height; x++)
                {
                    isWhilteLine = false;
                    for (int y = 0; y < tempImg.Width; y++)
                    {
                        __c = tempImg.GetPixel(y, x);
                        if (__c.R == w)
                        {
                            isWhilteLine = true;
                        }
                        else
                        {
                            isWhilteLine = false;
                            break;
                        }
                    }
                    if (!isWhilteLine)
                    {
                        YList.Add(x);
                    }
                }
                tempImg.Dispose();
            }
            #endregion

    效果如下:


    3.识别

    识别呢就是提取出图片的特征

    我的做法是将图片数字区域逐一分成4*4的区域,计算出各个区域的黑色点所占的百分比,然后将计算出来的结果和以前计算的特征进行比较,求出欧氏距离 d = sqrt( (x1-x2)^2+(y1-y2)^2 )最小的一个作为结果。

    部分代码如下:

    #region 黑色像素比列
            /// <summary>
            /// 计算黑色像素比列
            /// </summary>
            /// <param name="tempimg"></param>
            /// <returns></returns>
            private double PixlPercent(Bitmap tempimg)
            {
                int temp = 0;
                int w_h = tempimg.Width * tempimg.Height;
                for (int x = 0; x < tempimg.Width; x++)
                {
                    for (int y = 0; y < tempimg.Height; y++)
                    {
                        __c = tempimg.GetPixel(x, y);
                        if (__c.R == b)
                        {
                            temp++;
                        }
                    }
                }
                tempimg.Dispose();
                double result = temp * 1.0 / w_h;
                result = result.ToString().Length > 3 ? Convert.ToDouble(result.ToString().Substring(0, 3)) : result;
                return result;
            }
            #endregion

    效果如下:

    本代码只做研究学习之用。

    新手上路,有任何建议、意见联系 pigkeli@qq.com 。

    转载:http://www.cnblogs.com/riasky/p/3473365.html

  • 相关阅读:
    一个秒杀系统的设计
    2018年终总结-从我所在的团队回首一年技术变迁
    温习LOGO语言
    微信公众平台配置-笔记
    Spring mongotemplate使用
    三种方法实现MNIST 手写数字识别
    Python 实现0-1背包
    Python 实现快速排序和随机快速排序
    Spring+SpringMVC+Mybatis搭建的网站的处理流程总结
    Mybatis功能架构及执行流程
  • 原文地址:https://www.cnblogs.com/ningyanbo/p/3511627.html
Copyright © 2011-2022 走看看