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 。


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM