zoukankan      html  css  js  c++  java
  • 验证码处理类:UnCodebase.cs + BauDuAi 读取验证码的值(并非好的解决方案)

    主要功能:变灰,去噪,等提高清晰度等

    代码类博客,无需多说,如下:

        public class UnCodebase
        {
            public Bitmap bmpobj;
    
            public UnCodebase(Bitmap pic)
            {
                bmpobj = new Bitmap(pic); //转换为Format32bppRgb
            }
    
            /// <summary>
            /// 根据RGB,计算灰度值
            /// </summary>
            /// <param name="posClr">Color值</param>
            /// <returns>灰度值,整型</returns>
            private int GetGrayNumColor(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;
            }
    
            /// <summary>
            /// 去图形边框
            /// </summary>
            /// <param name="borderWidth"></param>
            public Bitmap ClearPicBorder(int borderWidth)
            {
                for (int i = 0; i < bmpobj.Height; i++)
                {
                    for (int j = 0; j < bmpobj.Width; j++)
                    {
                        if (i < borderWidth || j < borderWidth || j > bmpobj.Width - 1 - borderWidth ||
                            i > bmpobj.Height - 1 - borderWidth)
                            bmpobj.SetPixel(j, i, Color.FromArgb(255, 255, 255));
                    }
                }
                return bmpobj;
            }
    
            /// <summary>
            /// 灰度转换,逐行方式
            /// </summary>
            public Bitmap GrayByLine()
            {
                Rectangle rec = new Rectangle(0, 0, bmpobj.Width, bmpobj.Height);
                BitmapData bmpData = bmpobj.LockBits(rec, ImageLockMode.ReadWrite, bmpobj.PixelFormat);
                // PixelFormat.Format32bppPArgb);
                //    bmpData.PixelFormat = PixelFormat.Format24bppRgb;
                IntPtr scan0 = bmpData.Scan0;
                int len = bmpobj.Width * bmpobj.Height;
                int[] pixels = new int[len];
                Marshal.Copy(scan0, pixels, 0, len);
    
                //对图片进行处理
                int GrayValue = 0;
                for (int i = 0; i < len; i++)
                {
                    GrayValue = GetGrayNumColor(Color.FromArgb(pixels[i]));
                    pixels[i] = (byte)(Color.FromArgb(GrayValue, GrayValue, GrayValue)).ToArgb(); //Color转byte
                }
    
                bmpobj.UnlockBits(bmpData);
                return bmpobj;
            }
    
            /// <summary>
            /// 得到有效图形并调整为可平均分割的大小
            /// </summary>
            /// <param name="dgGrayValue">灰度背景分界值</param>
            /// <param name="CharsCount">有效字符数</param>
            /// <returns></returns>
            public void GetPicValidByValue(int dgGrayValue, int CharsCount)
            {
                int posx1 = bmpobj.Width;
                int posy1 = bmpobj.Height;
                int posx2 = 0;
                int posy2 = 0;
                for (int i = 0; i < bmpobj.Height; i++) //找有效区
                {
                    for (int j = 0; j < bmpobj.Width; j++)
                    {
                        int pixelValue = bmpobj.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;
                        }
                        ;
                    }
                    ;
                }
                ;
                // 确保能整除
                int Span = CharsCount - (posx2 - posx1 + 1) % CharsCount; //可整除的差额数
                if (Span < CharsCount)
                {
                    int leftSpan = Span / 2; //分配到左边的空列 ,如span为单数,则右边比左边大1
                    if (posx1 > leftSpan)
                        posx1 = posx1 - leftSpan;
                    if (posx2 + Span - leftSpan < bmpobj.Width)
                        posx2 = posx2 + Span - leftSpan;
                }
                //复制新图
                Rectangle cloneRect = new Rectangle(posx1, posy1, posx2 - posx1 + 1, posy2 - posy1 + 1);
                bmpobj = bmpobj.Clone(cloneRect, bmpobj.PixelFormat);
            }
    
            /// <summary>
            /// 得到有效图形,图形为类变量
            /// </summary>
            /// <param name="dgGrayValue">灰度背景分界值</param>
            /// <param name="CharsCount">有效字符数</param>
            /// <returns></returns>
            public void GetPicValidByValue(int dgGrayValue)
            {
                int posx1 = bmpobj.Width;
                int posy1 = bmpobj.Height;
                int posx2 = 0;
                int posy2 = 0;
                for (int i = 0; i < bmpobj.Height; i++) //找有效区
                {
                    for (int j = 0; j < bmpobj.Width; j++)
                    {
                        int pixelValue = bmpobj.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);
                bmpobj = bmpobj.Clone(cloneRect, bmpobj.PixelFormat);
            }
    
            /// <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);
            }
    
            /// <summary>
            /// 平均分割图片
            /// </summary>
            /// <param name="RowNum">水平上分割数</param>
            /// <param name="ColNum">垂直上分割数</param>
            /// <returns>分割好的图片数组</returns>
            public Bitmap[] GetSplitPics(int RowNum, int ColNum)
            {
                if (RowNum == 0 || ColNum == 0)
                    return null;
                int singW = bmpobj.Width / RowNum;
                int singH = bmpobj.Height / ColNum;
                Bitmap[] PicArray = new Bitmap[RowNum * ColNum];
    
                Rectangle cloneRect;
                for (int i = 0; i < ColNum; i++) //找有效区
                {
                    for (int j = 0; j < RowNum; j++)
                    {
                        cloneRect = new Rectangle(j * singW, i * singH, singW, singH);
                        PicArray[i * RowNum + j] = bmpobj.Clone(cloneRect, bmpobj.PixelFormat); //复制小块图
                    }
                }
                return PicArray;
            }
    
            /// <summary>
            /// 返回灰度图片的点阵描述字串,1表示灰点,0表示背景
            /// </summary>
            /// <param name="singlepic">灰度图</param>
            /// <param name="dgGrayValue">背前景灰色界限</param>
            /// <returns></returns>
            public 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;
            }
    
            /// <summary>
            /// 去掉噪点
            /// </summary>
            /// <param name="dgGrayValue"></param>
            /// <param name="MaxNearPoints"></param>
            public Bitmap ClearNoise(int dgGrayValue, int MaxNearPoints)
            {
                Color piexl;
                int nearDots = 0;
                int XSpan, YSpan, tmpX, tmpY;
                //逐点判断
                for (int i = 0; i < bmpobj.Width; i++)
                    for (int j = 0; j < bmpobj.Height; j++)
                    {
                        piexl = bmpobj.GetPixel(i, j);
                        if (piexl.R < dgGrayValue)
                        {
                            nearDots = 0;
                            //判断周围8个点是否全为空
                            if (i == 0 || i == bmpobj.Width - 1 || j == 0 || j == bmpobj.Height - 1) //边框全去掉
                            {
                                bmpobj.SetPixel(i, j, Color.FromArgb(255, 255, 255));
                            }
                            else
                            {
                                if (bmpobj.GetPixel(i - 1, j - 1).R < dgGrayValue) nearDots++;
                                if (bmpobj.GetPixel(i, j - 1).R < dgGrayValue) nearDots++;
                                if (bmpobj.GetPixel(i + 1, j - 1).R < dgGrayValue) nearDots++;
                                if (bmpobj.GetPixel(i - 1, j).R < dgGrayValue) nearDots++;
                                if (bmpobj.GetPixel(i + 1, j).R < dgGrayValue) nearDots++;
                                if (bmpobj.GetPixel(i - 1, j + 1).R < dgGrayValue) nearDots++;
                                if (bmpobj.GetPixel(i, j + 1).R < dgGrayValue) nearDots++;
                                if (bmpobj.GetPixel(i + 1, j + 1).R < dgGrayValue) nearDots++;
                            }
    
                            if (nearDots < MaxNearPoints)
                                bmpobj.SetPixel(i, j, Color.FromArgb(255, 255, 255)); //去掉单点 && 粗细小3邻边点
                        }
                        else //背景
                            bmpobj.SetPixel(i, j, Color.FromArgb(255, 255, 255));
                    }
                return bmpobj;
            }
    
            /// <summary>
            /// 扭曲图片校正
            /// </summary>
            public Bitmap ReSetBitMap()
            {
                Graphics g = Graphics.FromImage(bmpobj);
                Matrix X = new Matrix();
                //  X.Rotate(30);
                X.Shear((float)0.16666666667, 0); //  2/12
                g.Transform = X;
                // Draw image
                //Rectangle cloneRect = GetPicValidByValue(128);  //Get Valid Pic Rectangle
                Rectangle cloneRect = new Rectangle(0, 0, bmpobj.Width, bmpobj.Height);
                Bitmap tmpBmp = bmpobj.Clone(cloneRect, bmpobj.PixelFormat);
                g.DrawImage(tmpBmp,
                    new Rectangle(0, 0, bmpobj.Width, bmpobj.Height),
                    0, 0, tmpBmp.Width,
                    tmpBmp.Height,
                    GraphicsUnit.Pixel);
    
                return tmpBmp;
            }
    
            // <summary>
            /// 得到灰度图像前景背景的临界值 最大类间方差法,yuanbao,2007.08
            /// </summary>
            /// <returns>前景背景的临界值</returns>
            public int GetDgGrayValue()
            {
                int[] pixelNum = new int[256];           //图象直方图,共256个点
                int n, n1, n2;
                int total;                              //total为总和,累计值
                double m1, m2, sum, csum, fmax, sb;     //sb为类间方差,fmax存储最大方差值
                int k, t, q;
                int threshValue = 1;                      // 阈值
                int step = 1;
                //生成直方图
                for (int i = 0; i < bmpobj.Width; i++)
                {
                    for (int j = 0; j < bmpobj.Height; j++)
                    {
                        //返回各个点的颜色,以RGB表示
                        pixelNum[bmpobj.GetPixel(i, j).R]++;            //相应的直方图加1
                    }
                }
                //直方图平滑化
                for (k = 0; k <= 255; k++)
                {
                    total = 0;
                    for (t = -2; t <= 2; t++)              //与附近2个灰度做平滑化,t值应取较小的值
                    {
                        q = k + t;
                        if (q < 0)                     //越界处理
                            q = 0;
                        if (q > 255)
                            q = 255;
                        total = total + pixelNum[q];    //total为总和,累计值
                    }
                    pixelNum[k] = (int)((float)total / 5.0 + 0.5);    //平滑化,左边2个+中间1个+右边2个灰度,共5个,所以总和除以5,后面加0.5是用修正值
                }
                //求阈值
                sum = csum = 0.0;
                n = 0;
                //计算总的图象的点数和质量矩,为后面的计算做准备
                for (k = 0; k <= 255; k++)
                {
                    sum += (double)k * (double)pixelNum[k];     //x*f(x)质量矩,也就是每个灰度的值乘以其点数(归一化后为概率),sum为其总和
                    n += pixelNum[k];                       //n为图象总的点数,归一化后就是累积概率
                }
    
                fmax = -1.0;                          //类间方差sb不可能为负,所以fmax初始值为-1不影响计算的进行
                n1 = 0;
                for (k = 0; k < 256; k++)                  //对每个灰度(从0到255)计算一次分割后的类间方差sb
                {
                    n1 += pixelNum[k];                //n1为在当前阈值遍前景图象的点数
                    if (n1 == 0) { continue; }            //没有分出前景后景
                    n2 = n - n1;                        //n2为背景图象的点数
                    if (n2 == 0) { break; }               //n2为0表示全部都是后景图象,与n1=0情况类似,之后的遍历不可能使前景点数增加,所以此时可以退出循环
                    csum += (double)k * pixelNum[k];    //前景的“灰度的值*其点数”的总和
                    m1 = csum / n1;                     //m1为前景的平均灰度
                    m2 = (sum - csum) / n2;               //m2为背景的平均灰度
                    sb = (double)n1 * (double)n2 * (m1 - m2) * (m1 - m2);   //sb为类间方差
                    if (sb > fmax)                  //如果算出的类间方差大于前一次算出的类间方差
                    {
                        fmax = sb;                    //fmax始终为最大类间方差(otsu)
                        threshValue = k;              //取最大类间方差时对应的灰度的k就是最佳阈值
                    }
                }
                return threshValue;
            }
    
            /// <summary>
            /// 3×3中值滤波除杂,yuanbao,2007.10
            /// </summary>
            /// <param name="dgGrayValue"></param>
            public void ClearNoise(int dgGrayValue)
            {
                int x, y;
                byte[] p = new byte[9]; //最小处理窗口3*3
                byte s;
                //byte[] lpTemp=new BYTE[nByteWidth*nHeight];
                int i, j;
    
                //--!!!!!!!!!!!!!!下面开始窗口为3×3中值滤波!!!!!!!!!!!!!!!!
                for (y = 1; y < bmpobj.Height - 1; y++) //--第一行和最后一行无法取窗口
                {
                    for (x = 1; x < bmpobj.Width - 1; x++)
                    {
                        //取9个点的值
                        p[0] = bmpobj.GetPixel(x - 1, y - 1).R;
                        p[1] = bmpobj.GetPixel(x, y - 1).R;
                        p[2] = bmpobj.GetPixel(x + 1, y - 1).R;
                        p[3] = bmpobj.GetPixel(x - 1, y).R;
                        p[4] = bmpobj.GetPixel(x, y).R;
                        p[5] = bmpobj.GetPixel(x + 1, y).R;
                        p[6] = bmpobj.GetPixel(x - 1, y + 1).R;
                        p[7] = bmpobj.GetPixel(x, y + 1).R;
                        p[8] = bmpobj.GetPixel(x + 1, y + 1).R;
                        //计算中值
                        for (j = 0; j < 5; j++)
                        {
                            for (i = j + 1; i < 9; i++)
                            {
                                if (p[j] > p[i])
                                {
                                    s = p[j];
                                    p[j] = p[i];
                                    p[i] = s;
                                }
                            }
                        }
                        //      if (bmpobj.GetPixel(x, y).R < dgGrayValue)
                        bmpobj.SetPixel(x, y, Color.FromArgb(p[4], p[4], p[4]));    //给有效值付中值
                    }
                }
            }
        }
    View Code

    上述代码用于变灰,去噪点等功能,下面我们结合BaiDuAi 来实现读取验证码的功能<实验证明,baiduAi提供的Api仅仅能读取比较清晰的文字,像验证码这种,读取的不是太好>

    namespace BaiduAi.ORC
    {
        class Program
        {
            static string APP_ID = "";
            static string API_KEY = "";
            static string SECRET_KEY = "";
    
            static void Main(string[] args)
            {
                string Pth = Environment.CurrentDirectory;
                Image img = Image.FromFile(Pth + "/ajax.png");
                Bitmap bitmap = new Bitmap(img);
                UnCodebase Ub = new UnCodebase(bitmap);
                bitmap = Ub.GrayByPixels();
                bitmap.Save(Pth + "/he.png");
                int GV = Ub.GetDgGrayValue();
                Ub.GetPicValidByValue(bitmap, GV);
                Ub.ClearNoise(GV, 2);
                bitmap.Save(Pth + "/12.png");
                GeneralBasicDemo();
                Console.ReadKey();
            }
    
            public static void GeneralBasicDemo()
            {
                string Pth = Environment.CurrentDirectory;
                Image img = Image.FromFile(Pth + "/12.png");
                Bitmap bitmap = new Bitmap(img);
                UnCodebase Ub = new UnCodebase(bitmap);
                Ub.ClearNoise(10000, 400000);
                bitmap.Save(Pth + "/ajax1.png");
                //
                var client = new Baidu.Aip.Ocr.Ocr(API_KEY, SECRET_KEY);
                client.Timeout = 60000;  // 修改超时时间
                var image = File.ReadAllBytes(Pth + "/ajax.png");
                // 调用通用文字识别, 图片参数为本地图片,可能会抛出网络等异常,请使用try/catch捕获
                var result = client.GeneralBasic(image);
                Console.WriteLine(result);
                // 如果有可选参数
                var options = new Dictionary<string, object>{
            {"language_type", "CHN_ENG"},
            {"detect_direction", "true"},
            {"detect_language", "true"},
            {"probability", "true"}
        };
                // 带参数调用通用文字识别, 图片参数为本地图片
                result = client.GeneralBasic(image, options);
                Console.WriteLine(result);
            }
            public static void GeneralBasicUrlDemo()
            {
                var client = new Baidu.Aip.Ocr.Ocr(API_KEY, SECRET_KEY);
                client.Timeout = 60000;  // 修改超时时间
                var url = "http://www.xiaozhu.com/ajax.php?op=AJAX_GetVerifyCode&nocache=1524468631393";
    
                // 调用通用文字识别, 图片参数为远程url图片,可能会抛出网络等异常,请使用try/catch捕获
                var result = client.GeneralBasicUrl(url);
                Console.WriteLine(result);
                // 如果有可选参数
                var options = new Dictionary<string, object>{
            {"language_type", "CHN_ENG"},
            {"detect_direction", "true"},
            {"detect_language", "true"},
            {"probability", "true"}
        };
                // 带参数调用通用文字识别, 图片参数为远程url图片
                result = client.GeneralBasicUrl(url, options);
                Console.WriteLine(result);
            }
        }
    }

    上述的AppID AppKey等是百度开发者相关的参数!

    首先我们来看看验证的原图:

    这样一个彩色的验证码,

    变灰和去噪点处理后,变成了这样:

    彩色的字母变成了灰色/黑色

    最后调用百度的接口,读取图片的内容!

    验证码的内容是AvHv

    Api读成了:aviv 和 H 两个部分,而且还多了. : 等符号、所有本篇并非读取验证码的解决方案!

    此外说说BaiduAi : http://ai.baidu.com/

    看到了吗?各种人工智能!百度还是相当牛逼的!呵呵呵!上述验证码识别用到的是文字识别  所谓文字识别,百度提供了识别车牌号,身份证号,税务号等等,总之,我认为所谓的车牌号。身份证号等都应该是非常清晰的图片!而不像验证码,他亲妈都认不出来!特别是12306的!擦X

    有时间在研究这些东西吧!  

    @陈卧龙的博客

  • 相关阅读:
    PCB设计实战项目指导班26层板的设计
    AT2171 [AGC007D] Shik and Game 题解
    UVA11327 Enumerating Rational Numbers 题解
    P6222 「P6156 简单题」加强版 题解
    CF702F TShirts 题解
    P3747 [六省联考 2017] 相逢是问候 题解
    『学习笔记』PollardRho 算法 题解
    P7453 [THUSCH2017] 大魔法师 题解
    CF1575L Longest Array Deconstruction 题解
    最大公约数之和
  • 原文地址:https://www.cnblogs.com/chenwolong/p/UnCodebase.html
Copyright © 2011-2022 走看看