又到岁末,大家都忙着捞年底最后一桶金,我也不例外,忙着采集数据,不过有时候需要付出一点点时间而已。

在本案例中,我遇到了一个纯数字的电话号码变成了图片需要采集过来,在原网页上以<img src="一个JSP文件地址加一串密码" />的形式展现给我们,在采集的时候,有人建议我绕过去,直接采图片算了,不过本着对品质的追求,还是觉得应该做到采集的同时转化为文本。

我的思路是这样的,先处理保存0-9及“-”的黑白图片到本地磁盘,并分别取名为0.gif,1.gif....9.gif,-.gif,之后采集图片流到内存中,处理成黑白图片后,按长度等分切割,并与本地图片循环比对。这种情况也仅适合于“纯数字的简单”图片。请注意,在本案例中,没有纹路识别,只有像素比对。

于是,试验品开始了:
首先,得到远端图片的地址,并根据这个地址得到Response出来的图片(注,这是一个流,并非一个真正的图片文件,就像网站上的图片验证码一样。)。

在这里我用到了HttpWebRequest,但是发现直接代入图片地址后GET到的是空白,于是加参数.Referer = "http://该网站的域名",好了,现在远端给了我图片的流。


本段伪代码如下:

View Code

 1 HttpWebRequest objRequest = (HttpWebRequest)WebRequest.Create("图片地址");
 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张图片比对

View Code

1                 Bitmap iGetPhoto = new Bitmap(resStream);
2                 //第一步 变灰度图
3                 iGetPhoto = ToGray(iGetPhoto);
4                 //第二步 增加亮度100
5                 iGetPhoto = KiLighten(iGetPhoto, 100);
6                 //第三步增加对比度100
7                 iGetPhoto = KiContrast(iGetPhoto, 100);
8                 //第四步 变黑白
9                 iGetPhoto = ToBlackWhite(iGetPhoto);

四个函数体:

View Code

  1         /// <summary>
  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,现在要做的就是比对:比对代码如下:

View Code

 1                 //读取物理磁盘的文件到内存,注意这个.ToServerPath()是扩展方法,它的原型是HttpContext.Server.Mappath("xxx")
 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                 };

View Code

 1         /// <summary>
 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         }

最后,把零散的调用封装成调用的入口函数:

View Code

 1         //入口函数
 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

简单的纯数字图像(如电话号码、数字验证码)识别相关推荐

  1. 按键精灵+大漠插件简单数字验证码识别实践笔记

    因为资源短缺,公司用了一个很老的系统分配资源,每个项目每天都要经历上演一次像抢火车票一样的经历,而往往又空手而归,搞得大家疲惫不堪.而其中的关键在于几个简单的数字验证码的识别,于是在业余时间看了一些验 ...

  2. 【Python5】图像操作,数字验证码识别,图像拼接/保存器

    文章目录 1.安装 2.画图 3.几何变换 3.1 位计算 3.2 遮挡 3.3 通道切分合并 3.4 金字塔 3.5 缩放 3.6 平移 3.7 旋转 3.8 仿射变换 3.9 透视变换 4.形态学 ...

  3. 【Matlab验证码识别】遗传算法和最大熵优化+大津法(OTSU)+自定义阈值数字验证码识别【含GUI源码 1694期】

    一.代码运行视频(哔哩哔哩) [Matlab验证码识别]遗传算法和最大熵优化+大津法(OTSU)+自定义阈值数字验证码识别[含GUI源码 1694期] 二.matlab版本及参考文献 1 matlab ...

  4. 【python OpenCV3.3 图像处理教程:直线检测、圆检测、对象测量、腐蚀、膨胀等形态学操作、数字验证码识别、人脸检测

    1. 直线检测 Hough Line Transform:前提:边缘检测已经完成,基于霍夫变换 1.1 原理 可以通过(theta,r)唯一表示一个点. 把过三个点的全部直线以某一角度全部计算出来,如 ...

  5. 验证码识别 matlab,MATLAB数字验证码识别

    文件名大小更新时间 MATLAB数字验证码识别[GUI,详细解析,论wen]02020-08-03 MATLAB数字验证码识别[GUI,详细解析,论wen]\Databse02020-08-01 MA ...

  6. 基于CNN的四位数字验证码识别

    前言 验证码技术作为一种反自动化技术,使得很多程序的自动化工作止步.今天作者采用一些数字图像处理和CNN方法来识别较为简单的数字验证码 实验步骤 实验步骤主要围绕以下展开 图像预处理即滤除噪声和字符分 ...

  7. 数字验证码识别完成自动化登录

    一.人工方式处理数字验证码 通过selenium打开浏览器获取验证码,然后进行人工输入,从而实现登录 访问的学习通网页链接: xxt_link = r'https://passport2.chaoxi ...

  8. 【验证码识别】基于遗传算法优化OUST结合BP神经网络实现数字验证码识别含Matlab源码

    1 简介 本项目基于MATLAB完成数字验证码识别的GUI设计,图像处理,验证码生成.识别等功能.采用BP神经网络来实现对验证码图像的识别.验证码的识别,大概分为图片预处理.分割字符.识别字符三个过程 ...

  9. cnn 验证集 参与训练吗_一个简单的零基础的机器学习教程之二,字母数字验证码识别...

    一.前言 基于前面我发的贴子 土味程序员:一个简单的零基础的机器学习教程,Pytorch搭建Faster R-CNN目标检测平台​zhuanlan.zhihu.com 一个非常震撼的目标检测的例子.上 ...

最新文章

  1. 反恐精英代码_反恐精英20周年,为什么沙漠2(dust2)地图玩家们一直玩不腻?...
  2. 存储mysql数据存在特殊字符时处理_SQL数据库对于保存特殊字符的解决办法
  3. Mac(OS X)安装、配置并使用MySQL数据库
  4. 适用于应用程序错误的AWS警报
  5. response和request
  6. Python Tricks(十三)—— 欧几里得算法
  7. 20200620每日一句
  8. linux gcc换成c99标准,关于GCC和C99中可变参数宏
  9. Mcafee(麦咖啡) 无法升级的解决办法 附:进程详解,设置指南
  10. SQL优化案例-自定义函数索引(五)
  11. 通过nali命令统计访问的IP输入地理区域等作用
  12. Fabric官方教程(release 2.2)翻译及总结——使用CouchDB
  13. oracle中间人投毒漏洞,‘TNS Listener’远程数据投毒漏洞
  14. Java数据库插入记录的语句-单引号-双引号values('username+'-'+password
  15. 拓扑家族的“新贵”——管理型网络拓扑
  16. sqlserver2000 详解
  17. flutter widget super(key: key)的作用(五)
  18. mysql关联删除(删除不存在另一张表的记录)
  19. HTML5自造字,电脑中的造字程序怎么用啊怎么造字
  20. 银行RPA的5个案例场景展示

热门文章

  1. java学习4-Maven的发布war并部署到tomcat
  2. Hadoop 源码目录树
  3. 上传文件到服务器端后进一步推送到sftp服务器
  4. java 导出excel学习小片段
  5. 周末爬山之圈门-潭柘寺
  6. 百万数据php7取出循环_Thinkphp5 分批批量导出百万条数据记录的Code,不用PHPEXCEL哦!...
  7. python matlibplot_python matlibplot绘制3D图形
  8. moco常用配置参数及实战
  9. APP自动化测试系列之获取Android的Activity 和 Package
  10. 加密钱包和借记卡提供商Swipe即将发布V2版本