用 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){//切下来图片的横坐标leftleft = i;}else{//切下来图片的横坐标rightright = 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% 吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309068.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

国标转区位码电路设计及汉字显示

区位码国际码-2020H&#xff0c;由于采用加法器实现&#xff0c;因此用补码形式进行表示&#xff0c;区位码 国际码FFFF-2020H0001H国际码dfe0。 从网上找下机内码转化的软件&#xff0c;将一段自选文字输入该软件&#xff0c;进行十六进制的机内码转化。由于一个汉字是由四个十…

【WPF】DataGrid多表头的样式设计

需求在使用WPF开发时&#xff0c;使用DataGrid列表显示数据时&#xff0c;有些字段可以进行分组显示&#xff0c;用于更好的表达它们之间存在的某种关系&#xff0c;因此就考虑到要对DataGrid的表头进行扩展&#xff0c;可以显示多行表头&#xff0c;让这些有关联的字段内容显示…

异步清零和同步置数/清零的区别

同步&#xff0c;异步是对于时钟而言的。 同步指的是&#xff0c;状态的变化需要等待时钟有效沿来触发&#xff0c;所有动作同时跟随这个时钟变化&#xff0c;而异步时&#xff0c;状态变化不依赖与时钟。 异步清零说的是&#xff0c;你需要对一个计数器在满足某种条件时想要…

如何使用ABP进行软件开发之基础概览

ABP框架简述1&#xff09;简介在.NET众多的技术框架中&#xff0c;ABP框架&#xff08;本系列中指aspnetboilerplate项目&#xff09;以其独特的魅力吸引了一群优秀开发者广泛的使用。在该框架的赋能之下&#xff0c;开发者可根据需求通过官方网站【https://aspnetboilerplate.…

模2加法,模2减法,模2除法

十进制的除法&#xff0c;大家都会做&#xff1a;列个竖式&#xff0c;商&#xff0c;写在上面&#xff0c;上个几&#xff0c;再用被除数减去积&#xff0c;求得余数…。 二进制的除法&#xff0c;和十进制的计算方法相同&#xff0c;也要列出个竖式计算。 二进制的除法&…

《Unit Testing》2.1 伦敦学派如何做隔离

针对单元测试的定义&#xff0c;主要有两种看法&#xff1a;经典学派。经典学派之所以经典&#xff0c;是因为这原本就是人们做单元测试和测试驱动开发的方式伦敦学派。伦敦学派扎根于伦敦的编程社区。单元测试的定义单元测试有很多定义&#xff0c;但是所有的定义都有三个重要…

找出第i个小元素(算法导论第三版9.2-4题)

找出第i个小元素(算法导论第三版9.2-4题) 期望时间复杂度&#xff1a;Θ(n) 最坏情况的时间复杂度Θ(n^2) int randomized_select_based_loop(int *array,int start,int end,int index) {while (true){if(start end)return array[start];int middle randomized_partition(a…

C++实现数组模拟链表(实现链表的增删功能)

代码如下: #include <iostream> using namespace std; const int N 100;struct Node {int data;int next; };class ArrayList { private:Node node[N];int maxSize;//数组容量int idx;//接下来要插入的结点的下标int len;//链表长度public:void initList(){node[0].nex…

Gartner:容器采用将迅速增长,但不会很快有利可图

导语容器的未来可期&#xff0c;到2024年&#xff0c;所有应用程序中的15&#xff05;将在容器中运行&#xff0c;而这一数据今天仅为5&#xff05;&#xff0c;但当前变现还比较难。正文近日&#xff0c;Gartner公司发表其首次为软件容器管理软件和服务市场做的预测。Gartner说…

快速排序在最坏的情况下时间复杂度(Ω(nlgn)(算法导论第三版9.3-3))

快速排序在最坏的情况下时间复杂度Ω(nlgn) 1⃣️在元素各异时或者少量相等&#xff08;元素个数n>70) 时间复杂度Ω(nlgn) void quick_sort_by_median(int *array,int start,int end) {if(start<end){int median select(array,start,end,(end - start 1)/2 (end - …

线性表的定义与操作-顺序表,链式表(C语言)

顺序表: typedef int Position; typedef struct LNode *List; struct LNode {ElementType Data[MAXSIZE];Position Last; };/* 初始化 */ List MakeEmpty() {List L;L (List)malloc(sizeof(struct LNode));L->Last -1;return L; }/* 查找 */ #define ERROR -1Position Fi…

【Azure Show】|第三期 人工智能大咖与您分享!嘉宾陈海平胡浩陈堰平

欢迎来到Azure Show!Azure ShowHello,大家好&#xff0c;又来到新的一期的Azure Show!本期是人工智能专场&#xff0c;我们邀请到微软Data&AI的解决方案架构师陈堰平&#xff0c;Tensorflow.NET 作者陈海平&#xff0c;还有微软人工智能方向最有价值专家胡浩和大家分享人工…

确定S中最接近中位数的k个元素(算法导论第三版9.3-7)

确定S中最接近中位数的k个元素 &#xff08;算法导论第三版9.3-7题&#xff09; 时间复杂度O(n) vector<int> k_elements_closest_to_median(int *array,int start,int end,int k) {vector<int> result;int median select(array,start,end,(end - start 1)/2 …

深入探究ASP.NET Core异常处理中间件

前言全局异常处理是我们编程过程中不可或缺的重要环节。有了全局异常处理机制给我们带来了很多便捷&#xff0c;首先我们不用满屏幕处理程序可能出现的异常&#xff0c;其次我们可以对异常进行统一的处理&#xff0c;比如收集异常信息或者返回统一的格式等等。ASP.NET Core为我…

找出有序数组X和Y中所有元素的中位数(X,Y分别含n个元素)(算法导论第三版9.3-8)

找出有序数组X和Y中所有元素的中位数&#xff08;X&#xff0c;Y分别含n个元素&#xff09; &#xff08;算法导论第三版9.3-8&#xff09; 时间复杂度O&#xff08;lgn&#xff09; int find_median_two_ordered_arrays(int *array_a,int *array_b,int length) {int a_start…

有序序列中的i个最大数(算法导论思考题9-1)

有序序列中的i个最大数 &#xff08;算法导论思考题9-1&#xff09; a 时间复杂度O(nlgni) //总共时间复杂度O(nlgni) vector<int> i_largest_number_in_ordered_sequence_a(int *array,int length,int i){vector<int>result;//时间复杂度O(nlgn)quick_sort_by_m…

.NET Core加解密实战系列之——消息摘要与数字签名算法

简介加解密现状&#xff0c;编写此系列文章的背景&#xff1a;需要考虑系统环境兼容性问题&#xff08;Linux、Windows&#xff09;语言互通问题&#xff08;如C#、Java等&#xff09;&#xff08;加解密本质上没有语言之分&#xff0c;所以原则上不存在互通性问题&#xff09;…

堆栈的定义与操作-顺序存储,链式存储(C语言)

顺序存储&#xff1a; typedef int Position; struct SNode {ElementType *Data; /* 存储元素的数组 */Position Top; /* 栈顶指针 */int MaxSize; /* 堆栈最大容量 */ }; typedef struct SNode *Stack;Stack CreateStack( int MaxSize ) {Stack S (Stack)malloc(…

快速排序和选择模版类

快速排序和选择模版类 template<typename T> void insert_sort(T *array,int start,int end) {for (int i start 1; i < end 1; i) {int j i - 1 ;T key array[i];while (j > start && key < array[j]){array[j1] array[j];j--;}array[j1] key…

造轮子-AgileConfig一个基于.NetCore开发的轻量级配置中心

微服务确实是行业的一个趋势&#xff0c;我自己也在把一些项目往微服务架构迁移。玩微服务架构配置中心是一个绕不过去的东西&#xff0c;有很多大牌的组件可以选&#xff0c;比如spring-cloud-config&#xff0c;apoll&#xff0c;disconf等等。而我为什么还要造一个轮子呢&am…