用 aforge.net 小试一下验证码识别

今天来小玩一下 aforge.net 套用官方的话就是一个专门为开发者和研究者基于C#框架设计的,这个框架提供了不同的类库和关于类库的资源,还有很多应用程序例子,包括计算机视觉与人工智能,图像处理,神经网络,遗传算法,机器学习,机器人等领域,下载网址:http://www.aforgenet.com/framework/downloads.html

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

上去看了后,哟呵~ 还有个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% 吧。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: AForge.NET是一个开放源代码的计算机视觉和人工智能框架。它提供了一系列功能强大的工具和算法,用于图像处理、机器学习、机器视觉和模式识别等领域。在AForge.NET中,也可以使用其提供的工具和算法进行条码识别。 条码识别是通过对图像进行分析和处理,解码出条码中存储的信息。AForge.NET提供了用于条码识别的类库和方法。 首先,可以使用AForge.NET中的图像处理工具对图像进行预处理,例如灰度化、二值化等操作,以提高条码识别的准确性。 其次,AForge.NET中的条码识别方法可以对预处理后的图像进行分析和解码。它支持多种常见的1D和2D条码类型,例如EAN-13、QR码等。 最后,可以通过AForge.NET提供的接口将条码识别结果集成到自己的应用程序中。可以根据需要,将识别结果作为文本、数字等形式进行处理和展示,以满足不同的应用需求。 总之,AForge.NET是一个功能强大的框架,可以用于多个领域的图像处理和模式识别任务,包括条码识别。使用AForge.NET进行条码识别可以通过预处理图像和解码条码信息来实现。 ### 回答2: AForge.NET是一个开源的计算机视觉和人工智能框架,它提供了一个用于图像处理和分析的强大工具集。在AForge.NET中,也包含了用于条码识别的功能。 使用AForge.NET进行条码识别可以通过以下几个步骤完成: 1. 导入AForge.NET库:在使用AForge.NET进行条码识别之前,需要首先导入相应的库文件。可以从AForge.NET官方网站下载最新版本的库文件并添加到项目中。 2. 选择适当的条码识别算法:AForge.NET提供了多种条码识别算法,例如一维条码识别(如Code39、Code128)和二维条码识别(如QR码、Data Matrix)。用户可以根据需要选择适当的算法。 3. 预处理图像:在进行条码识别之前,通常需要对图像进行预处理,以提高识别准确率。预处理步骤可能包括灰度化、降噪、二值化等操作。 4. 执行条码识别:使用选定的条码识别算法,对预处理后的图像进行条码识别。AForge.NET提供了相应的函数和方法来实现这一步骤。识别结果通常包括条码的类型和解码后的数据。 5. 处理识别结果:根据需要,可以进一步处理识别结果,例如将解码后的数据展示给用户或进行进一步的处理操作。 综上所述,AForge.NET是一个强大的计算机视觉框架,它提供了丰富的功能来进行条码识别。用户可以根据自己的需求选择适当的条码识别算法,并使用AForge.NET提供的函数和方法来实现条码识别。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值