Aforge.net之旅——开篇:从识别验证码开始

  时间过得真快啊,转眼今年就要过去了,大半年都没有写博客了,要说时间嘛,花在泡妹子和搞英语去了,哈哈。。。前几天老大问我

怎么这么长时间都没写博客了,好吧,继续坚持,继续分享我的心得体会。

  这个系列我们玩玩aforge.net,套用官方都话就是一个专门为开发者和研究者基于C#框架设计的,这个框架提供了不同的类库和关于类库的

资源,还有很多应用程序例子,包括计算机视觉与人工智能,图像处理,神经网络,遗传算法,机器学习,机器人等领域,这个系列研究的重点

就是瞎几把搞下AForge.Imaging这个命名空间下面的东东,下载网址:http://www.aforgenet.com/framework/downloads.html

    对了,不知道有多少公司是用得仕卡作为员工的福利卡,我们公司就是这样的,每个月公司都会充值一些money,然后我们这些屁码农每个

月15号就都开心的去看看发了多少。

上去看了后,哟呵~ 还有个90年代的验证码,我想这年头估计找到这样验证码的网站已经不多了,如果懂一点图像处理都话,这张验证码

跟没有一个样,谢谢。。。这篇我们看看怎么去识别它。

 

一: 验证码处理

1.  一般处理原则

    这种验证码为什么说跟没有一样,第一点:字体规范工整,第二点:不旋转扭曲粘连,第三点:字体颜色单一,下面看处理步骤

这里要注意的是,aforge只接受像素格式为24/32bpp的像素格式图片,所以处理前,先进行格式转化。

//转化图片像素格式
            var bnew = new Bitmap(b.Width, b.Height, PixelFormat.Format24bppRgb);

            Graphics g = Graphics.FromImage(bnew);

            g.DrawImage(b, 0, 0);

            g.Dispose();

 

 <1>图片灰度化

    这是图像识别通常都要走的第一步,图片灰度化有助于减少后续对rgb的计算量,同时也方便我们进行二值化,在aforge中我们有

专门的类一步搞定,简洁方便。

            //灰度化
            b = new Grayscale(0.2125, 0.7154, 0.0721).Apply(b);

<2>二值化

  二值化顾名思义就是二种值,比如非白即黑,非黑即白,那么白和黑的标准就需要提供一个阈值,大于或者小于怎么样,在aforge同样

也有相似的类进行处理

            //二值化
            b = new Threshold(50).Apply(b);

<3> 去噪点

  从上面的图片可以发现有很多红点点,搞得像皮肤病一样,仔细观察可以看到这种噪点具有独立,体积小的特征,所以判断的标准就是如果

图中某个区块的大小在我设置的阈值内,就将其去掉,同样也有专门的类进行处理。

            //去噪点
            new BlobsFiltering(1, 1, b.Width, b.Height).Apply(b);

  这里具体怎么传递参数,后续系列会慢慢解读。

<4>切割图片

   切图片的好处在于我们需要知道真正要识别的元素的有效范围是多大,同时也方便我们将这些图片作为模板保存下来。

代码如下:

/// <summary>
        /// 按照 Y 轴线 切割
        /// (丢弃等于号)
        /// </summary>
        /// <param name="?"></param>
        /// <returns></returns>
        public List<Bitmap> Crop_Y(Bitmap b)
        {
            var list = new List<Bitmap>();

            //统计每一列的“1”的个数,方便切除
            int[] cols = new int[b.Width];

            /*
             *  纵向切割
             */
            for (int x = 0; x < b.Width; x++)
            {
                for (int y = 0; y < b.Height; y++)
                {
                    //获取当前像素点像素
                    var pixel = b.GetPixel(x, y);

                    //说明是黑色点
                    if (pixel.R == 0)
                    {
                        cols[x] = ++cols[x];
                    }
                }
            }

            int left = 0, right = 0;

            for (int i = 0; i < cols.Length; i++)
            {
                //说明该列有像素值(为了防止像素干扰,去噪后出现空白的问题,所以多判断一下,防止切割成多个)
                if (cols[i] > 0 || (i + 1 < cols.Length && cols[i + 1] > 0))
                {
                    if (left == 0)
                    {
                        //切下来图片的横坐标left
                        left = i;
                    }
                    else
                    {
                        //切下来图片的横坐标right
                        right = i;
                    }
                }
                else
                {
                    //说明已经有切割图了,下面我们进行切割处理
                    if ((left > 0 || right > 0))
                    {
                        Crop corp = new Crop(new Rectangle(left, 0, right - left + 1, b.Height));

                        var small = corp.Apply(b);

                        //居中,将图片放在20*50的像素里面

                        list.Add(small);
                    }

                    left = right = 0;
                }
            }

            return list;
        }

        /// <summary>
        /// 按照 X 轴线 切割
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        public List<Bitmap> Crop_X(List<Bitmap> list)
        {
            var corplist = new List<Bitmap>();

            //再对分割的图进行上下切割,取出上下的白边
            foreach (var segb in list)
            {
                //统计每一行的“1”的个数,方便切除
                int[] rows = new int[segb.Height];

                /*
                 *  横向切割
                 */
                for (int y = 0; y < segb.Height; y++)
                {
                    for (int x = 0; x < segb.Width; x++)
                    {
                        //获取当前像素点像素
                        var pixel = segb.GetPixel(x, y);

                        //说明是黑色点
                        if (pixel.R == 0)
                        {
                            rows[y] = ++rows[y];
                        }
                    }
                }

                int bottom = 0, top = 0;

                for (int y = 0; y < rows.Length; y++)
                {
                    //说明该行有像素值(为了防止像素干扰,去噪后出现空白的问题,所以多判断一下,防止切割成多个)
                    if (rows[y] > 0 || (y + 1 < rows.Length && rows[y + 1] > 0))
                    {
                        if (top == 0)
                        {
                            //切下来图片的top坐标
                            top = y;
                        }
                        else
                        {
                            //切下来图片的bottom坐标
                            bottom = y;
                        }
                    }
                    else
                    {
                        //说明已经有切割图了,下面我们进行切割处理
                        if ((top > 0 || bottom > 0) && bottom - top > 0)
                        {
                            Crop corp = new Crop(new Rectangle(0, top, segb.Width, bottom - top + 1));

                            var small = corp.Apply(segb);

                            corplist.Add(small);
                        }

                        top = bottom = 0;
                    }
                }
            }

            return corplist;
        }

<5> 图片精处理

  这里要注意的是,比如数字“2”,切除上下左右的空白后,再加上噪点的干扰,不一定每次切下来的图片大小都一样,所以这里

为了方便更好的识别,我们需要重置下图片的大小,并且将“数字2”进行文字居中。

/// <summary>
        /// 重置图片的指定大小并且居中
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public List<Bitmap> ToResizeAndCenterIt(List<Bitmap> list, int w = 20, int h = 20)
        {
            List<Bitmap> resizeList = new List<Bitmap>();

            for (int i = 0; i < list.Count; i++)
            {
                //反转一下图片
                list[i] = new Invert().Apply(list[i]);

                int sw = list[i].Width;
                int sh = list[i].Height;

                Crop corpFilter = new Crop(new Rectangle(0, 0, w, h));

                list[i] = corpFilter.Apply(list[i]);

                //再反转回去
                list[i] = new Invert().Apply(list[i]);

                //计算中心位置
                int centerX = (w - sw) / 2;
                int centerY = (h - sh) / 2;

                list[i] = new CanvasMove(new IntPoint(centerX, centerY), Color.White).Apply(list[i]);

                resizeList.Add(list[i]);
            }

            return resizeList;
        }

其实精处理后,这些图片就可以作为我们的模板库的图片了,可以将每张模板图都标记下具体的数字,后续我们再遇到时,计算下其相似度

就可以了,下面就是已经制作好的模板。

<6> 模板匹配识别

  既然模板图片都制作好了,一切都差不多水到渠成了,下次来的验证码我都切好后做成精图片后跟模板进行匹配,在afroge里面

有一个ExhaustiveTemplateMatching,专门用来进行模板匹配用的,很方便。

 ExhaustiveTemplateMatching templateMatching = new ExhaustiveTemplateMatching(0.9f);

这里的0.9f就是设定的阈值,只有大于0.9的阈值,我才认为该模板与目标图片相似,然后在所有大于0.9的相似度中取到最大的一个作为

我们最后识别的图像。

var files = Directory.GetFiles(Environment.CurrentDirectory + "\\Template\\");

            var templateList = files.Select(i => { return new Bitmap(i); }).ToList();
            var templateListFileName = files.Select(i => { return i.Substring(30, 1); }).ToList();

            var result = new List<string>();

            ExhaustiveTemplateMatching templateMatching = new ExhaustiveTemplateMatching(0.9f);

            //这里面有四张图片,进行四张图的模板匹配
            for (int i = 0; i < list.Count; i++)
            {
                float max = 0;
                int index = 0;

                for (int j = 0; j < templateList.Count; j++)
                {
                    var compare = templateMatching.ProcessImage(list[i], templateList[j]);

                    if (compare.Length > 0 && compare[0].Similarity > max)
                    {
                        //记录下最相似的
                        max = compare[0].Similarity;
                        index = j;
                    }
                }

                result.Add(templateListFileName[index]);
            }

最后的效果还是不错的,识别率基本100%吧。

时间: 2024-10-30 09:58:08

Aforge.net之旅——开篇:从识别验证码开始的相关文章

压力测试 识别验证码-asp.net 如何自动识别验证码自动登录?

问题描述 asp.net 如何自动识别验证码自动登录? asp.net 如何自动识别验证码自动登录?想做下压力测试,需要不停的虚拟账户登录进系统测试 解决方案 不同网站的验证码有不同的算法识别验证码.简单的验证码可以通过调用第三方识别引擎如Tesseract 来训练识别.(可以参考http://blog.csdn.net/cownew/article/details/8850353)复杂的一般需要自己动手写代码来识别.

c#中如何识别验证码,不要调用ocr的

问题描述 在做一个小软件需要自动实现验证码的识别,网上搜了很多,都没有得到满意的效果.希望大神们可以给我一个比较好的demo 解决方案 解决方案二:百度一大堆解决方案三:该回复于2014-01-19 22:30:12被版主删除解决方案四:识别验证码的过程就叫OCRO=光学OpticalC=字符CharacterR=识别Recognition你说我要识别文字,不用"识别文字",这是唱哪一出?解决方案五:用OCR能够识别就已经是幸运的了,根本大多数连这个都没法用,楼主不要异想天开了.解决方

Delphi实现自动发贴和识别验证码

这是去年编写的一个delphi小程序,当时有个宁波的朋友让我帮他写个软件,要求如下: 能够在xxxx网站上的各个交易区,实现自动发帖. xxxx是一个游戏点卡交易站点,他们按照省份进行划分交易区域,信息发布者每次只能在 一个省份发布信息.当然可能他们也是出于某种目的,比如防止信息泛滥.发布者发布信息 的页面都有一个图形验证码,只有填写正确的验证码才能完成整个流程. 当时他是一直用着,现在是否还在用不得而知了,把这段代码放出来纯粹是与大家交流学 习,不要作恶. 登录网站,自动填写网页数据,并提交,

识别验证码 高手帮忙啊!急急急

问题描述 谁能帮忙把这验证码识别出来啊! 解决方案 解决方案二:自己顶一个解决方案三:48对吗?每天回帖即可获得10分可用分!解决方案四:嗯嗯识别类似这种计算的计算可能10+2=?.10-3=?这种的解决方案五:算术类的验证码?解决方案六:比较麻烦.你看看网站一些C#有源代码的识别图像的代码,看看能不能把字符都识别出来,然后根据字符特性变成就可以.解决方案七:这个还真不好搞,首先得识别转换成表达式,然后还要解析表达式.第一个好办点,第二个头大的要死,搞点复杂的公式呢解决方案八:计算类的,给出结果

怎么识别验证码??????????

问题描述 像这样的验证码[img=http://www.ibcbet.com/login_code.aspx][/img]怎么识别?怎么分割有效区域和提取特征码?各位大虾们赐教下,最好有代码参考下 解决方案 解决方案二:该回复于2012-04-16 10:52:53被版主删除解决方案三:这些图片都是通过你的后台程序生成的(往图片上写字),然后将图片输出给前台,同时你也知道图片中的内容(你之前往图片中写过什么自然自己心里很清楚)解决方案四:希望对你有帮助http://www.51yzm.com/I

验证码识别,发票编号识别(转)

   毕业设计做了一个简单的研究下验证码识别的问题,并没有深入的研究,设计图形图像的东西,水很深,神经网络,机器学习,都很难.这次只是在传统的方式下分析了一次. 今年工作之后再也没有整理过,前几天一个家伙要这个demo看下,我把一堆东西收集,打包给他了,他闲太乱了,我就整理记录下.这也是大学最后的一次作业,里面有很多记忆和怀念. 这个demo的初衷不是去识别验证码,是把验证的图像处理方式用到其他方面,车票,票据等. 这里最后做了一个发票编号识别的的案例: 地址:http://v.youku.co

一个验证码识别的代码

字体固定,位置固定,干扰点和字体颜色深度没有交叉,比如下面的样例,是我前几天帮朋友写投票机刷票时碰到的一个具体案例. 基本就三步,确定特征码-分割图片-逐个匹配,代码很简单,不超过100行 using System; using System.Collections.Generic; using System.Text; using System.Drawing; namespace BmpNumber { class Number { //数字特征库 static int[,] _num0 =

php制作的简单验证码识别代码_php实例

一直想写这个,过了很久今天兴趣来了索性记录下. 验证码 全自动区分计算机和人类的公开图灵测试(英语:Completely Automated Public Turing test to tell Computers and Humans Apart,简称CAPTCHA),俗称验证码,是一种区分用户是计算机和人的公共全自动程序.在CAPTCHA测试中,作为服务器的计算机会自动生成一个问题由用户来解答.这个问题可以由计算机生成并评判,但是必须只有人类才能解答.由于计算机无法解答CAPTCHA的问题,

php实现验证码的识别(中级篇)

 在上篇文章 <php实现验证码的识别 (初级篇 ) > 中,讲了如何识别简单的验证,这里的简单只的是验证码有数字和字母组成,格式统一,每次出现位置固定.这篇文章将继续深入研究识别验证码,这次识别的目标是,验证码有字符和数字组成,验证码存在旋转(可能左右都旋转),位置不固定,存在字符与字符之间的粘连,且验证码有更强的干扰素.这篇文章讲解的方法,并不是万能的解决方案,并且提供代码不能直接解决你的问题,这里仅仅是方法,具体需求读者自己解决,需要说明的是,识别验证码与具体的编程语言无关,这里只是使用