从识别验证码开始
时间过得真快啊,转眼今年就要过去了,大半年都没有写博客了,要说时间嘛,花在泡妹子和搞英语去了,哈哈。。。前几天老大问我
怎么这么长时间都没写博客了,好吧,继续坚持,继续分享我的心得体会。
这个系列我们玩玩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