苏飞论坛

标题: C#识别验证码图片通用类(附源码下载) [打印本页]

作者: 站长苏飞    时间: 2012-11-30 17:05
标题: C#识别验证码图片通用类(附源码下载)
                                  C#识别验证码图片通用类(附源码下载)
封装后的类使用很简单,针对不同的验证码,相应继承修改某些方法,即可简单几句代码就可以实现图片识别了:
            GrayByPixels(); //灰度处理
            GetPicValidByValue(128, 4); //得到有效空间
            Bitmap[] pics = GetSplitPics(4, 1);     //分割
            string code = GetSingleBmpCode(pics, 128);   //得到代码串
具体使用,请参见我做的例子:投票程序源码
(, 下载次数: 3722)
(例子说明:使用进程投票,可自动清除Alert弹出窗口,可自动换IP,ADSL用户自行修改Restart.bat中第三行内容)
[C#] 纯文本查看 复制代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace BallotAiying2
{
    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(System.Drawing.Color posClr)
        {
            return (posClr.R * 19595 + posClr.G * 38469 + posClr.B * 7472) >> 16;
        }

        /// <summary>
        /// 灰度转换,逐点方式
        /// </summary>
        public void 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));
                }
            }
        }

        /// <summary>
        /// 去图形边框
        /// </summary>
        /// <param name="borderWidth"></param>
        public void 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));
                }
            }
        }

        /// <summary>
        /// 灰度转换,逐行方式
        /// </summary>
        public void 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));
                pixels = (byte)(Color.FromArgb(GrayValue, GrayValue, GrayValue)).ToArgb();      //Color转byte
            }

            bmpobj.UnlockBits(bmpData);
        }

        /// <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;
        }
    }
}


作者: Eagle    时间: 2012-12-1 11:24
这个类好!
作者: chengulv    时间: 2012-12-14 19:04
能识别多复杂的验证码?
作者: 站长苏飞    时间: 2012-12-14 21:03
chengulv 发表于 2012-12-14 19:04
能识别多复杂的验证码?

这个只适合新手练手用
作者: fisher    时间: 2013-7-3 00:35
http://captcha6.pbs.qunar.com/api/image?k={g3njj(t&_=0.6906372403567442

这种能否识别呢?
作者: 辉腾软件    时间: 2013-7-4 12:03
我只是路过打酱油的。
作者: 天山明月    时间: 2013-8-14 14:37
对于背景色比较单一的图片,这个类的确不错。
但是对于彩色背景色且背景颜色、位置随机变动的情况,去背景色有没有好的方法?


作者: hbird    时间: 2013-9-7 23:20
好东西
作者: Eagle    时间: 2013-10-29 16:52
真是难得给力的帖子啊,强烈支持楼主。
作者: arstum    时间: 2013-12-2 23:54
这种不需要打代码?神了 强烈支持楼主ing……
作者: sandy1231    时间: 2013-12-19 00:40
像现在的一些站群软件是否用的是国外人工打码?还是自己做识别程序的?

作者: 站长苏飞    时间: 2013-12-19 08:21
sandy1231 发表于 2013-12-19 00:40
像现在的一些站群软件是否用的是国外人工打码?还是自己做识别程序的?

有国内也有国外的

作者: (··)-Dark-    时间: 2013-12-19 20:45
有专门的打码平台。
作者: lcylcyll    时间: 2014-1-1 13:00
苏老大果然强的啊
作者: JackFamily    时间: 2014-1-14 10:33
我来标记一下   强烈支持楼主ing……
作者: vbnet10    时间: 2014-1-14 13:02
下载后顶贴是个好习惯
作者: ghostbb    时间: 2014-2-24 12:02
好帖,尤其是能给出如此详细注释的源码,楼主给力啊!
作者: 水中鱼    时间: 2014-3-6 09:39
这个验证码识别好像不行 非常清晰的 全字母的验证码都识别不了  飞哥能看看是什么问题吗
作者: atgu2je    时间: 2014-3-22 14:37
强烈支持楼主ing……
作者: 黄粱一梦    时间: 2014-4-8 13:02
非常感谢你帮了我的大忙,真的太感谢你啦!
作者: yongyuan824    时间: 2014-6-19 14:28
受教了,学习中……
作者: 孤独男孩    时间: 2014-6-22 11:20
非常感谢你帮了我的大忙,真的太感谢你啦!好东西
作者: Cheungnotes    时间: 2014-7-15 08:42
强烈支持楼主ing……
作者: youzis    时间: 2014-7-20 16:35
感谢老大! 苏飞 v5
作者: ♂.Smile    时间: 2014-9-24 10:26
强烈支持楼主ing……
作者: steavenhe    时间: 2014-9-26 15:40
来学习学习,正好要学习过验证码
作者: ching126    时间: 2014-11-28 16:19
强烈支持楼主ing……
作者: 小小鸟    时间: 2014-12-16 18:24
强烈支持楼主ing……
作者: 精彩    时间: 2014-12-19 19:48
感谢无私奉献!
作者: zhulinmails    时间: 2015-1-24 18:15
淡定,淡定,淡定……
作者: jerryhuangn    时间: 2015-2-11 10:09
看能不能用。多谢分享
作者: xz_whist    时间: 2015-3-14 22:37
强烈支持楼主ing……
作者: drifter    时间: 2015-3-31 11:16
强烈支持楼主ing……
作者: drifter    时间: 2015-3-31 11:34

作者: jerryhuangn    时间: 2015-5-11 10:59
验证码现在都好多干扰,有点难啊。
作者: atgu2je    时间: 2015-5-15 22:49
顶,好东西,学习了
作者: kwfkiss    时间: 2015-6-30 18:28
赞一个 拿回来试试
作者: kwfkiss    时间: 2015-7-3 14:55
强烈支持楼主ing……好样的
作者: yimo666    时间: 2015-12-4 11:12
eeeee。mark一下。
作者: 喂喂喂_w88Qj    时间: 2016-3-26 08:50
强烈支持楼主ing……
作者: sageyy    时间: 2016-10-11 15:37
神了 强烈支持楼主ing……
作者: hadwin_Y4Wm5    时间: 2016-11-3 12:09
我只是路过打酱油的。
作者: wwwce    时间: 2018-5-26 11:54
学习
作者: livehu5188    时间: 2021-8-15 19:58
新手 谢谢楼主分享啊
作者: workbaby    时间: 2022-5-29 17:21
这个真心不错
作者: ounce1988    时间: 2023-7-27 13:51
难得的好帖,学习




欢迎光临 苏飞论坛 (http://www.sufeinet.com/) Powered by Discuz! X3.4