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

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

  这个系列我们玩玩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>切割图片

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

代码如下:

  1        /// <summary>
2 /// 按照 Y 轴线 切割
3 /// (丢弃等于号)
4 /// </summary>
5 /// <param name="?"></param>
6 /// <returns></returns>
7 public List<Bitmap> Crop_Y(Bitmap b)
8 {
9 var list = new List<Bitmap>();
10
11 //统计每一列的“1”的个数,方便切除
12 int[] cols = new int[b.Width];
13
14 /*
15 * 纵向切割
16 */
17 for (int x = 0; x < b.Width; x++)
18 {
19 for (int y = 0; y < b.Height; y++)
20 {
21 //获取当前像素点像素
22 var pixel = b.GetPixel(x, y);
23
24 //说明是黑色点
25 if (pixel.R == 0)
26 {
27 cols[x] = ++cols[x];
28 }
29 }
30 }
31
32 int left = 0, right = 0;
33
34 for (int i = 0; i < cols.Length; i++)
35 {
36 //说明该列有像素值(为了防止像素干扰,去噪后出现空白的问题,所以多判断一下,防止切割成多个)
37 if (cols[i] > 0 || (i + 1 < cols.Length && cols[i + 1] > 0))
38 {
39 if (left == 0)
40 {
41 //切下来图片的横坐标left
42 left = i;
43 }
44 else
45 {
46 //切下来图片的横坐标right
47 right = i;
48 }
49 }
50 else
51 {
52 //说明已经有切割图了,下面我们进行切割处理
53 if ((left > 0 || right > 0))
54 {
55 Crop corp = new Crop(new Rectangle(left, 0, right - left + 1, b.Height));
56
57 var small = corp.Apply(b);
58
59 //居中,将图片放在20*50的像素里面
60
61 list.Add(small);
62 }
63
64 left = right = 0;
65 }
66 }
67
68 return list;
69 }
70
71 /// <summary>
72 /// 按照 X 轴线 切割
73 /// </summary>
74 /// <param name="b"></param>
75 /// <returns></returns>
76 public List<Bitmap> Crop_X(List<Bitmap> list)
77 {
78 var corplist = new List<Bitmap>();
79
80 //再对分割的图进行上下切割,取出上下的白边
81 foreach (var segb in list)
82 {
83 //统计每一行的“1”的个数,方便切除
84 int[] rows = new int[segb.Height];
85
86 /*
87 * 横向切割
88 */
89 for (int y = 0; y < segb.Height; y++)
90 {
91 for (int x = 0; x < segb.Width; x++)
92 {
93 //获取当前像素点像素
94 var pixel = segb.GetPixel(x, y);
95
96 //说明是黑色点
97 if (pixel.R == 0)
98 {
99 rows[y] = ++rows[y];
100 }
101 }
102 }
103
104 int bottom = 0, top = 0;
105
106 for (int y = 0; y < rows.Length; y++)
107 {
108 //说明该行有像素值(为了防止像素干扰,去噪后出现空白的问题,所以多判断一下,防止切割成多个)
109 if (rows[y] > 0 || (y + 1 < rows.Length && rows[y + 1] > 0))
110 {
111 if (top == 0)
112 {
113 //切下来图片的top坐标
114 top = y;
115 }
116 else
117 {
118 //切下来图片的bottom坐标
119 bottom = y;
120 }
121 }
122 else
123 {
124 //说明已经有切割图了,下面我们进行切割处理
125 if ((top > 0 || bottom > 0) && bottom - top > 0)
126 {
127 Crop corp = new Crop(new Rectangle(0, top, segb.Width, bottom - top + 1));
128
129 var small = corp.Apply(segb);
130
131 corplist.Add(small);
132 }
133
134 top = bottom = 0;
135 }
136 }
137 }
138
139 return corplist;
140 }

<5> 图片精处理

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

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

 1         /// <summary>
2 /// 重置图片的指定大小并且居中
3 /// </summary>
4 /// <param name="list"></param>
5 /// <returns></returns>
6 public List<Bitmap> ToResizeAndCenterIt(List<Bitmap> list, int w = 20, int h = 20)
7 {
8 List<Bitmap> resizeList = new List<Bitmap>();
9
10
11 for (int i = 0; i < list.Count; i++)
12 {
13 //反转一下图片
14 list[i] = new Invert().Apply(list[i]);
15
16 int sw = list[i].Width;
17 int sh = list[i].Height;
18
19 Crop corpFilter = new Crop(new Rectangle(0, 0, w, h));
20
21 list[i] = corpFilter.Apply(list[i]);
22
23 //再反转回去
24 list[i] = new Invert().Apply(list[i]);
25
26 //计算中心位置
27 int centerX = (w - sw) / 2;
28 int centerY = (h - sh) / 2;
29
30 list[i] = new CanvasMove(new IntPoint(centerX, centerY), Color.White).Apply(list[i]);
31
32 resizeList.Add(list[i]);
33 }
34
35 return resizeList;
36 }

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

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

<6> 模板匹配识别

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

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

 ExhaustiveTemplateMatching templateMatching = new ExhaustiveTemplateMatching(0.9f);

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

我们最后识别的图像。

 1            var files = Directory.GetFiles(Environment.CurrentDirectory + "\\Template\\");
2
3 var templateList = files.Select(i => { return new Bitmap(i); }).ToList();
4 var templateListFileName = files.Select(i => { return i.Substring(30, 1); }).ToList();
5
6 var result = new List<string>();
7
8 ExhaustiveTemplateMatching templateMatching = new ExhaustiveTemplateMatching(0.9f);
9
10 //这里面有四张图片,进行四张图的模板匹配
11 for (int i = 0; i < list.Count; i++)
12 {
13 float max = 0;
14 int index = 0;
15
16 for (int j = 0; j < templateList.Count; j++)
17 {
18 var compare = templateMatching.ProcessImage(list[i], templateList[j]);
19
20 if (compare.Length > 0 && compare[0].Similarity > max)
21 {
22 //记录下最相似的
23 max = compare[0].Similarity;
24 index = j;
25 }
26 }
27
28 result.Add(templateListFileName[index]);
29 }

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

 
 
分类: 图形图像

Aforge.net 一个专门为开发者和研究者基于C#框架设计的更多相关文章

  1. AForge.NET是一个专门为开发者和研究者基于C#框架设计的视频录像

    AForge.NET是一个专门为开发者和研究者基于C#框架设计的,他包括计算机视觉与人工智能,图像处理,神经网络,遗传算法,机器学习,模糊系统,机器人控制等领域.这个框架由一系列的类库组成.主要包括有 ...

  2. 一个资深iOS开发者对于React Native的看法

    一个资深iOS开发者对于React Native的看法 当我第一次尝试ReactNative的时候,我觉得这只是网页开发者涉足原生移动应用领域的歪门邪道.   我认为一个js开发者可以使用javasc ...

  3. 如何成为一个Linux内核开发者

    你想知道如何成为一个Linux内核开发者么?或者你的老板告诉你,“去为这个设备写一个Linux驱动.“这篇文档的目的,就是通过描述你需要 经历的过程和提示你如何和社区一起工作,来教给你为达到这些目的所 ...

  4. 一个web前端开发者的日常唠叨

    时间飞逝,距离上一次更新博客已经过去了三个月,上一篇博客的发布时间停留在了4月4日. 近来三个月没有更新博客,深感抱歉和愧疚.停更博客就意味着学习的越来越少,作为一个普通的前端开发者来说这是万万不可取 ...

  5. 12小时包你学会基于ReactMix框架的ReactNativeApp开发(二)基于Css+HTML写第一个app页面

    上一篇文章,大家对于ReactMix(https://github.com/xueduany/react-mix)框架有了一个基本认识,知道我们是一个语法糖,帮助大家基于一套代码,所有平台都能跑.那么 ...

  6. 10个专属于移动app开发者的最佳移动JavaScript框架

    1.Titanium Mobile JavaScript Frameworks Titanium Mobile JavaScript框架是移动应用开发者(Android & iOS)首选的最优 ...

  7. 一个技术汪的开源梦 —— 基于 .Net Core 的公共组件之 Http 请求客户端

    一个技术汪的开源梦 —— 目录 想必大家在项目开发的时候应该都在程序中调用过自己内部的接口或者使用过第三方提供的接口,咱今天不讨论 REST ,最常用的请求应该就是 GET 和 POST 了,那下面开 ...

  8. 介绍一个非常好用的跨平台C++开源框架:openFrameworks

    介绍一个非常好用的跨平台C++开源框架:openFrameworks 简介 首先需要说明的一点是: openFrameworks 设计的初衷不是为计算机专业人士准备的, 而是为艺术专业人士准备的, 就 ...

  9. 【niubi-job——一个分布式的任务调度框架】----框架设计原理以及实现

    引言 niubi-job的框架设计是非常简单实用的一套设计,去掉了很多其它调度框架中,锦上添花但并非必须的组件,例如MQ消息通讯组件(kafka等).它的框架设计核心思想是,让每一个jar包可以相对之 ...

随机推荐

  1. OCP读书笔记(24) - 题库(ExamD)

    327.You have a database with the following tablespaces: SYSTEM, SYSAUX, UNDO, USERS, TEMP.You want t ...

  2. neu1458 方格取数 dp解法

    题意: 有N * N个格子,每一个格子里有正数或者0,从最左上角往最右下角走,仅仅能向下和向右,一共走两次(即从左上角走到右下角走两趟),把全部经过的格子的数加起来,求最大值SUM,且两次假设经过同一 ...

  3. 《python源代码分析》笔记 pythonVM一般表达式

    本文senlie原版的.转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.字节码指令 LOAD_CONST:从consts表中读取序号为i的元素并压入到执行时栈中 ...

  4. C#:winform项目在win7,xp32位和64位都能执行

    vs中项目配置管理器活动解决方式平台选择X86平台.

  5. maven_修改setting ,改为自己私服或者OSC开源中国 [为解决sqlite-jdbc 在中央仓库找不到]

    因为项目要使用到sqlite ,虽然有现成的jar,但是考虑的项目的易用统一管理,决定还是用maven 结果纠结了半天 sqlite-jdbc 在maven默认的仓库根本找不着,于是乎修改 setti ...

  6. [注意事项&amp;车轮]java源代码 产生局部javadoc api档

    随着Eclipse书写java码时间,有时候,因为我们不知道java函数返回.通过鼠标移动到java该功能,假设它javadoc相关内容将被显示. 但是,并非所有java代码javadoc:连装jav ...

  7. 【转】Appium根据xpath获取控件实例随笔

    原文地址:http://blog.csdn.net/zhubaitian/article/details/39754233 如文章<Appium基于安卓的各种FindElement的控件定位方法 ...

  8. 【百度地图API】如何利用自己的数据制作社交地图?只显示可视区域内的标注

    原文:[百度地图API]如何利用自己的数据制作社交地图?只显示可视区域内的标注 摘要:如果你自己的数据已经超过1万个,如何进行合理的显示?除了聚合marker外,还有一个办法.那就是,只显示可视区域内 ...

  9. sonp跨域请求

    sonp跨域请求学习笔记   前言 ajax,用苍白的话赞扬:很好. 我们可以使用ajax实现异步获取数据,减少服务器运算时间,大大地改善用户体验:我们可以使用ajax实现小系统组合大系统:我们还可以 ...

  10. ArcGIS Runtime SDKs v10.2.4最新(Android、iOS、OSX和.NET)

    ArcGIS Runtime SDKs v10.2.4最新,它包含:Android.iOS.OS X和.NET四大平台,用户和开发人员可以登录Esri最新的SDK安装包.或者通过云盘下载(http:/ ...