简单的纯数字图像(如电话号码、数字验证码)识别
又到岁末,大家都忙着捞年底最后一桶金,我也不例外,忙着采集数据,不过有时候需要付出一点点时间而已。
在本案例中,我遇到了一个纯数字的电话号码变成了图片需要采集过来,在原网页上以<img src="一个JSP文件地址加一串密码" />的形式展现给我们,在采集的时候,有人建议我绕过去,直接采图片算了,不过本着对品质的追求,还是觉得应该做到采集的同时转化为文本。
我的思路是这样的,先处理保存0-9及“-”的黑白图片到本地磁盘,并分别取名为0.gif,1.gif....9.gif,-.gif,之后采集图片流到内存中,处理成黑白图片后,按长度等分切割,并与本地图片循环比对。这种情况也仅适合于“纯数字的简单”图片。请注意,在本案例中,没有纹路识别,只有像素比对。
于是,试验品开始了:
首先,得到远端图片的地址,并根据这个地址得到Response出来的图片(注,这是一个流,并非一个真正的图片文件,就像网站上的图片验证码一样。)。
在这里我用到了HttpWebRequest,但是发现直接代入图片地址后GET到的是空白,于是加参数.Referer = "http://该网站的域名",好了,现在远端给了我图片的流。
本段伪代码如下:
2 objRequest.Timeout = 10000;//设置超时10秒
3 objRequest.Referer = "http://被采网站的域名/";
4 HttpWebResponse objResponse = (HttpWebResponse)objRequest.GetResponse();
5 System.IO.Stream resStream = objResponse.GetResponseStream();
6 从以上代码中,我得到这样一副图片:
7 //保存图片的代码也供上。
8 //System.Drawing.Image i = System.Drawing.Image.FromStream(resStream);
9 //i.Save(@"c:\x.gif ", System.Drawing.Imaging.ImageFormat.Gif);
10 //resStream.Close();
11 //i.Dispose();
第二步,图片流得到了,接下来是处理这副图片了。不过在这之前,我还有件重要的事情要做,因为是纯数字的图片,并且可能区号和电话之间有“-”符号,所以我必须在本地保存了这些图片的黑白样品,这个过程很简单,就是用PHOTOSHOP去色,然后到调整亮度/对比度,各增加100,即可得到一张黑白的图片,之后将其切分为10*20的小图,分别取名为0.gif,1.gif...9.gif,-.gif一共11个图片。
,之后,我的处理流程是:图片流到内存====》变灰处理=====》加亮度,对比度=====》变黑白处理=====》切分并和本地这11张图片比对
2 //第一步 变灰度图
3 iGetPhoto = ToGray(iGetPhoto);
4 //第二步 增加亮度100
5 iGetPhoto = KiLighten(iGetPhoto, 100);
6 //第三步增加对比度100
7 iGetPhoto = KiContrast(iGetPhoto, 100);
8 //第四步 变黑白
9 iGetPhoto = ToBlackWhite(iGetPhoto);
四个函数体:
2 /// 图片变成灰度
3 /// </summary>
4 /// <param name="b"></param>
5 /// <returns></returns>
6 public Bitmap ToGray(Bitmap b) {
7 for (int x = 0; x < b.Width; x++)
8 {
9 for (int y = 0; y < b.Height; y++)
10 {
11 Color c = b.GetPixel(x, y);
12 int luma = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);//转换灰度的算法
13 b.SetPixel(x, y, Color.FromArgb(luma, luma, luma));
14 }
15 }return b;
16 }
17 /// <summary>
18 /// 图像变成黑白
19 /// </summary>
20 /// <param name="b"></param>
21 /// <returns></returns>
22 public Bitmap ToBlackWhite(Bitmap b) {
23 for (int x = 0; x < b.Width; x++)
24 {
25 for (int y = 0; y < b.Height; y++)
26 {
27 Color c = b.GetPixel(x, y);
28 if (c.R < (byte)255)
29 {
30 b.SetPixel(x, y, Color.FromArgb(0, 0, 0));
31 }
32 }
33 }return b;
34 }
35 /// <summary>
36 /// 图像亮度调整
37 /// </summary>
38 /// <param name="b"></param>
39 /// <param name="degree"></param>
40 /// <returns></returns>
41 public Bitmap KiLighten(Bitmap b, int degree)
42 {
43
44 if (b == null)
45 {
46
47 return null;
48
49 }
50
51
52
53 if (degree < -255) degree = -255;
54
55 if (degree > 255) degree = 255;
56
57
58
59 try
60 {
61
62
63
64 int width = b.Width;
65
66 int height = b.Height;
67
68
69
70 int pix = 0;
71
72
73
74 BitmapData data = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
75
76
77
78 unsafe
79 {
80
81 byte* p = (byte*)data.Scan0;
82
83 int offset = data.Stride - width * 3;
84
85 for (int y = 0; y < height; y++)
86 {
87
88 for (int x = 0; x < width; x++)
89 {
90
91 // 处理指定位置像素的亮度
92
93 for (int i = 0; i < 3; i++)
94 {
95
96 pix = p[i] + degree;
97
98
99
100 if (degree < 0) p[i] = (byte)Math.Max(0, pix);
101
102 if (degree > 0) p[i] = (byte)Math.Min(255, pix);
103
104
105
106 } // i
107
108 p += 3;
109
110 } // x
111
112 p += offset;
113
114 } // y
115
116 }
117
118
119
120 b.UnlockBits(data);
121
122
123
124 return b;
125
126 }
127
128 catch
129 {
130
131 return null;
132
133 }
134
135
136
137 }
138
139
140 /// <summary>
141
142 /// 图像对比度调整
143
144 /// </summary>
145
146 /// <param name="b">原始图</param>
147
148 /// <param name="degree">对比度[-100, 100]</param>
149
150 /// <returns></returns>
151
152 public Bitmap KiContrast(Bitmap b, int degree)
153 {
154
155 if (b == null)
156 {
157
158 return null;
159
160 }
161
162
163
164 if (degree < -100) degree = -100;
165
166 if (degree > 100) degree = 100;
167
168
169
170 try
171 {
172
173
174
175 double pixel = 0;
176
177 double contrast = (100.0 + degree) / 100.0;
178
179 contrast *= contrast;
180
181 int width = b.Width;
182
183 int height = b.Height;
184
185 BitmapData data = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
186
187 unsafe
188 {
189
190 byte* p = (byte*)data.Scan0;
191
192 int offset = data.Stride - width * 3;
193
194 for (int y = 0; y < height; y++)
195 {
196
197 for (int x = 0; x < width; x++)
198 {
199
200 // 处理指定位置像素的对比度
201
202 for (int i = 0; i < 3; i++)
203 {
204
205 pixel = ((p[i] / 255.0 - 0.5) * contrast + 0.5) * 255;
206
207 if (pixel < 0) pixel = 0;
208
209 if (pixel > 255) pixel = 255;
210
211 p[i] = (byte)pixel;
212
213 } // i
214
215 p += 3;
216
217 } // x
218
219 p += offset;
220
221 } // y
222 }
223 b.UnlockBits(data);
224 return b;
225 }catch
226 {
227 return null;
228 }
229 }
第三步,所有的准备工作已经完成了,开始比对!内存中有了一副黑白的数字图,它的尺寸是140*20,并且左边空出来7像素,右侧待定,具体看电话号码有几位,可能是3像素,也可能是13像素;本地磁盘中有了0-9.gif,它们的尺寸是10*20,现在要做的就是比对:比对代码如下:
2 Bitmap[] numColl = {
3 new Bitmap(("/Temp/0.gif").ToServerPath()),
4 new Bitmap(("/Temp/1.gif").ToServerPath()),
5 new Bitmap(("/Temp/2.gif").ToServerPath()),
6 new Bitmap(("/Temp/3.gif").ToServerPath()),
7 new Bitmap(("/Temp/4.gif").ToServerPath()),
8 new Bitmap(("/Temp/5.gif").ToServerPath()),
9 new Bitmap(("/Temp/6.gif").ToServerPath()),
10 new Bitmap(("/Temp/7.gif").ToServerPath()),
11 new Bitmap(("/Temp/8.gif").ToServerPath()),
12 new Bitmap(("/Temp/9.gif").ToServerPath()),
13 new Bitmap(("/Temp/-.gif").ToServerPath())
14 };
2 /// 比较原图和每个小样图,并给出数字结果
3 /// </summary>
4 /// <param name="iGetPhoto"></param>
5 /// <param name="numColl"></param>
6 /// <returns></returns>
7 public string ComparePic(Bitmap iGetPhoto/*原图*/, Bitmap[] numColl/*小图样图集*/) {
8 int numCount = 13;
9 string result = string.Empty;
10 for (int i = 0; i < numCount; i++)
11 {
12 int x = i * 10 + 7;//原始图的开始取像素位置
13 Bitmap perBmp = new Bitmap(10, 20);
14 Graphics gPhoto = Graphics.FromImage(perBmp);
15 gPhoto.Clear(Color.White);
16 gPhoto.DrawImage(iGetPhoto/*原图*/, 0, 0,/*目标位置*/ new Rectangle(new Point(x, 0), new Size(10, 20))/*源位置*/, GraphicsUnit.Pixel);
17 for (int j = 0; j < 11; j++)//这是数字样图的集合循环
18 {
19 bool isTrue = true;//接下来循环小图的每一个像素,与大图中裁出的小图作比较,只要一个像素不对,就OVER
20 for (int n = 0; n < 20; n++)
21 {
22 for (int m = 0; m < 10; m++)
23 {
24 Color point1 = perBmp.GetPixel(m, n);
25 Color point2 = numColl[j].GetPixel(m, n);
26 if (point1.ToArgb() != point2.ToArgb())
27 {
28 isTrue = false;
29 }
30 }
31 }
32 if (isTrue)
33 {
34 result += j == 10 ? "-" : j.ToString();
35 break;
36 }
37 }
38 perBmp.Dispose();
39 gPhoto.Dispose();
40 }
41 return result;
42 }
最后,把零散的调用封装成调用的入口函数:
2 public string GetPicTel(string url)
3 {
4 HttpWebRequest objRequest = (HttpWebRequest)WebRequest.Create(url);
5 objRequest.Timeout = 10000;//设置尾5秒
6 objRequest.Referer = "http://你要偷图片的网站域名";
7 try
8 {
9 HttpWebResponse objResponse = (HttpWebResponse)objRequest.GetResponse();
10 //System.IO.Stream resStream = objResponse.GetResponseStream();
11 //System.Drawing.Image i = System.Drawing.Image.FromStream(resStream);
12 //i.Save(@"c:\x.gif ", System.Drawing.Imaging.ImageFormat.Gif);
13 //resStream.Close();
14 //i.Dispose();
15
16 System.IO.Stream resStream = objResponse.GetResponseStream();
17 Bitmap iGetPhoto = new Bitmap(resStream);
18 //第一步 变灰度图
19 iGetPhoto = ToGray(iGetPhoto);
20 //第二步 增加亮度100
21 iGetPhoto = KiLighten(iGetPhoto, 100);
22 //第三步增加对比度100
23 iGetPhoto = KiContrast(iGetPhoto, 100);
24 //第四步 变黑白
25 iGetPhoto = ToBlackWhite(iGetPhoto);
26
27
28
29 //测试图片的结果
30 //iGetPhoto.Save(@"c:\x.gif ", System.Drawing.Imaging.ImageFormat.Gif);
31 //resStream.Close();
32 //return string.Empty;
33 Bitmap[] numColl = {
34 new Bitmap(("/Temp/0.gif").ToServerPath()),
35 new Bitmap(("/Temp/1.gif").ToServerPath()),
36 new Bitmap(("/Temp/2.gif").ToServerPath()),
37 new Bitmap(("/Temp/3.gif").ToServerPath()),
38 new Bitmap(("/Temp/4.gif").ToServerPath()),
39 new Bitmap(("/Temp/5.gif").ToServerPath()),
40 new Bitmap(("/Temp/6.gif").ToServerPath()),
41 new Bitmap(("/Temp/7.gif").ToServerPath()),
42 new Bitmap(("/Temp/8.gif").ToServerPath()),
43 new Bitmap(("/Temp/9.gif").ToServerPath()),
44 new Bitmap(("/Temp/-.gif").ToServerPath())
45 };
46 return ComparePic(iGetPhoto, numColl);
47
48
49 }
50 catch (Exception ex)
51 {
52 return string.Empty;
53 }
54 }
另外,要说明的是,有些验证码(不带扭曲),有倾斜或上下波动的也可以用这种方法搞定,只是需要再多动一点点脑筋.但是带扭曲效果的验证码就是非常专业的事情了,不过我们只用来做采集,不是爆破专家,这种方式应该基本满足应用了.
希望本文可以抛砖引玉,帮你采集到你需要的数据,当然,尽可能地支持别人的版权!也正是因为版权,恕我无法给出原始图片地址.
本文来自http://corecainiao.cnblogs.com/如需转载请标明出处。
转载于:https://www.cnblogs.com/CoreCaiNiao/archive/2011/12/26/2302141.html
简单的纯数字图像(如电话号码、数字验证码)识别相关推荐
- 按键精灵+大漠插件简单数字验证码识别实践笔记
因为资源短缺,公司用了一个很老的系统分配资源,每个项目每天都要经历上演一次像抢火车票一样的经历,而往往又空手而归,搞得大家疲惫不堪.而其中的关键在于几个简单的数字验证码的识别,于是在业余时间看了一些验 ...
- 【Python5】图像操作,数字验证码识别,图像拼接/保存器
文章目录 1.安装 2.画图 3.几何变换 3.1 位计算 3.2 遮挡 3.3 通道切分合并 3.4 金字塔 3.5 缩放 3.6 平移 3.7 旋转 3.8 仿射变换 3.9 透视变换 4.形态学 ...
- 【Matlab验证码识别】遗传算法和最大熵优化+大津法(OTSU)+自定义阈值数字验证码识别【含GUI源码 1694期】
一.代码运行视频(哔哩哔哩) [Matlab验证码识别]遗传算法和最大熵优化+大津法(OTSU)+自定义阈值数字验证码识别[含GUI源码 1694期] 二.matlab版本及参考文献 1 matlab ...
- 【python OpenCV3.3 图像处理教程:直线检测、圆检测、对象测量、腐蚀、膨胀等形态学操作、数字验证码识别、人脸检测
1. 直线检测 Hough Line Transform:前提:边缘检测已经完成,基于霍夫变换 1.1 原理 可以通过(theta,r)唯一表示一个点. 把过三个点的全部直线以某一角度全部计算出来,如 ...
- 验证码识别 matlab,MATLAB数字验证码识别
文件名大小更新时间 MATLAB数字验证码识别[GUI,详细解析,论wen]02020-08-03 MATLAB数字验证码识别[GUI,详细解析,论wen]\Databse02020-08-01 MA ...
- 基于CNN的四位数字验证码识别
前言 验证码技术作为一种反自动化技术,使得很多程序的自动化工作止步.今天作者采用一些数字图像处理和CNN方法来识别较为简单的数字验证码 实验步骤 实验步骤主要围绕以下展开 图像预处理即滤除噪声和字符分 ...
- 数字验证码识别完成自动化登录
一.人工方式处理数字验证码 通过selenium打开浏览器获取验证码,然后进行人工输入,从而实现登录 访问的学习通网页链接: xxt_link = r'https://passport2.chaoxi ...
- 【验证码识别】基于遗传算法优化OUST结合BP神经网络实现数字验证码识别含Matlab源码
1 简介 本项目基于MATLAB完成数字验证码识别的GUI设计,图像处理,验证码生成.识别等功能.采用BP神经网络来实现对验证码图像的识别.验证码的识别,大概分为图片预处理.分割字符.识别字符三个过程 ...
- cnn 验证集 参与训练吗_一个简单的零基础的机器学习教程之二,字母数字验证码识别...
一.前言 基于前面我发的贴子 土味程序员:一个简单的零基础的机器学习教程,Pytorch搭建Faster R-CNN目标检测平台zhuanlan.zhihu.com 一个非常震撼的目标检测的例子.上 ...
最新文章
- 反恐精英代码_反恐精英20周年,为什么沙漠2(dust2)地图玩家们一直玩不腻?...
- 存储mysql数据存在特殊字符时处理_SQL数据库对于保存特殊字符的解决办法
- Mac(OS X)安装、配置并使用MySQL数据库
- 适用于应用程序错误的AWS警报
- response和request
- Python Tricks(十三)—— 欧几里得算法
- 20200620每日一句
- linux gcc换成c99标准,关于GCC和C99中可变参数宏
- Mcafee(麦咖啡) 无法升级的解决办法 附:进程详解,设置指南
- SQL优化案例-自定义函数索引(五)
- 通过nali命令统计访问的IP输入地理区域等作用
- Fabric官方教程(release 2.2)翻译及总结——使用CouchDB
- oracle中间人投毒漏洞,‘TNS Listener’远程数据投毒漏洞
- Java数据库插入记录的语句-单引号-双引号values('username+'-'+password
- 拓扑家族的“新贵”——管理型网络拓扑
- sqlserver2000 详解
- flutter widget super(key: key)的作用(五)
- mysql关联删除(删除不存在另一张表的记录)
- HTML5自造字,电脑中的造字程序怎么用啊怎么造字
- 银行RPA的5个案例场景展示
热门文章
- java学习4-Maven的发布war并部署到tomcat
- Hadoop 源码目录树
- 上传文件到服务器端后进一步推送到sftp服务器
- java 导出excel学习小片段
- 周末爬山之圈门-潭柘寺
- 百万数据php7取出循环_Thinkphp5 分批批量导出百万条数据记录的Code,不用PHPEXCEL哦!...
- python matlibplot_python matlibplot绘制3D图形
- moco常用配置参数及实战
- APP自动化测试系列之获取Android的Activity 和 Package
- 加密钱包和借记卡提供商Swipe即将发布V2版本