由于网页上的验证码图片都是通过程序产生的,因此,各个字母之间也都比较规则,进行识别其中的字符的话,也比较简单,只要将图片进行相减后,看看和那个字母的图片接近即可.
下面,我就那我们公司的外网邮箱:http://mail.lida-oe.com.cn的网页中的验证码为例子,我写了一个程序.
【网通】点击这里下载全部源程序 【电信、网通】点击这里下载源程序
【下载说明】
1、单击上面这个地址,打开下载页面。
2、点普通下载--等待30秒--点“下载”按钮--保存
整个程序的过程是这样的:
1 获取网页中的图片的地址,并下载到本地
2 对图像的像素中的A(透明度)值,来对图像进行二值化处理
3 对整个图片进行裁剪,仅裁剪出包含字符的区域
4 使用投影法对图像进行分割,从而保证每个分割区域仅包含一个字符
5 对分割出来的图片,再次进行裁剪,使得整个字符充满图片框,并大小一致
6 因此对分割出来的字符图片与图片库中的图片进行比较,相差最小的仅为字符.
我首先是搜集了多幅的验证码图片,以便能够得到所有的字符的图片. 然后,对这些搜集来的图片进行分割,从而得到包含26个字母的图片. 将这些图片作为图片库, 之后将从网页中获取的图片分割出来的字符图片,与此对比,从而得到识别结果.
截图如下:
获取网页中验证码图片之后,如上图。
将图片进行“二值化”之后的图片,如上图。
之后,对图片进行剪裁,如上图。
再使用投影法,分割出每个字符,如上图。
将分割出来的字符进行剪裁,如上图。
最终,通过与样本库的字符图片进行对比,识别出图片中的字母。
部分源程序:
主要源程序(由于做的比较急,并未对程序结构进行优化):
/*
* Created by SharpDevelop.
* User: Administrator
* Date: 2012-6-11
* Time: 11:46
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Windows.Forms;
namespace GetAlpha
{
/// <summary>
/// Description of MainForm.
/// </summary>
public partial class MainForm : Form
{
private Bitmap bitmap=null;
private string fileName=string.Empty;
private List<Bitmap> alphaBmp=new List<Bitmap>();
public MainForm()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
//
// TODO: Add constructor code after the InitializeComponent() call.
//
this.toolStripStatusLabel1.Text="";
this.toolStripStatusLabel2.Text="";
}
void Button1Click(object sender, EventArgs e)
{
OpenFileDialog ofd=new OpenFileDialog();
ofd.Filter="All Image Files|*.bmp;*.png;*.jpg;*.gif";
ofd.RestoreDirectory=false;
if(ofd.ShowDialog()==DialogResult.OK)
{
pictureBox1.Image=Image.FromFile(ofd.FileName);
if(this.bitmap!=null)
{
this.bitmap.Dispose();
this.bitmap=null;
}
this.bitmap=new Bitmap(Image.FromFile(ofd.FileName),pictureBox1.Width,pictureBox1.Height);
this.Text="GetAlpha("+System.IO.Path.GetFileName(ofd.FileName)+")";
this.fileName=System.IO.Path.GetFileNameWithoutExtension(ofd.FileName);
}
}
void PictureBox1MouseHover(object sender, EventArgs e)
{
}
void PictureBox1MouseClick(object sender, MouseEventArgs e)
{
if(this.bitmap==null) return;
this.toolStripStatusLabel1.Text=e.Location.ToString();
Color mouse_clr=bitmap.GetPixel(e.X,e.Y);
this.toolStripStatusLabel2.Text=mouse_clr.ToString();
}
void Button2Click(object sender, EventArgs e)
{
int bmp_width=this.bitmap.Width;
int bmp_height=this.bitmap.Height;
for(int i=0;i<bmp_height;i++)
{
for(int j=0;j<bmp_width;j++)
{
Color clr=this.bitmap.GetPixel(j,i);
if(clr.R!=0 && clr.G!=0 && clr.B!=0)
{
int a=(clr.A>120)?255:0;
Color tmp=Color.FromArgb(a,255,255,255);
this.bitmap.SetPixel(j,i,tmp);
}
}
}
pictureBox1.Image=this.bitmap;
}
void Button3Click(object sender, EventArgs e)
{
int bmp_width=this.bitmap.Width;
int bmp_height=this.bitmap.Height;
List<Point> pt1_list=new List<Point>();
List<Point> pt2_list=new List<Point>();
//统计每行的第一个和最后一个白色像素点
bool isFirstPixelInLine=false;
for(int i=0;i<bmp_height;i++)
{
isFirstPixelInLine=false;
Point pt1=new Point(0,0);
Point pt2=new Point(0,0);
for(int j=0;j<bmp_width;j++)
{
Color clr=this.bitmap.GetPixel(j,i);
if(clr.R==255 && clr.G==255 && clr.B==255)
{
if(isFirstPixelInLine==false)
{
isFirstPixelInLine=true;
pt1.X=j;
pt1.Y=i;
}
else
{
pt2.X=j;
pt2.Y=i;
}
}
}
pt1_list.Add(pt1);
pt2_list.Add(pt2);
}
//找出裁剪区域的左上角和右下角点的坐标
Point ptt1=new Point(this.bitmap.Width,this.bitmap.Height);
Point ptt2=new Point(0,0);
for(int i=0;i<pt1_list.Count;i++)
{
if(pt1_list[i].X!=0 && pt1_list[i].Y!=0)
{
if(pt1_list[i].X<ptt1.X) ptt1.X=pt1_list[i].X;
if(pt1_list[i].Y<ptt1.Y) ptt1.Y=pt1_list[i].Y;
if(pt2_list[i].X>ptt2.X) ptt2.X=pt2_list[i].X;
if(pt2_list[i].Y>ptt2.Y) ptt2.Y=pt2_list[i].Y;
}
}
//画出红色竖线以分割图片
// for(int i=0;i<pt1_list.Count;i++)
// {
// Debug.WriteLine("pt1="+pt1_list[i].ToString());
// this.bitmap.SetPixel(pt1_list[i].X,pt1_list[i].Y,Color.FromArgb(255,255,0,0));
// Debug.WriteLine("pt2="+pt2_list[i].ToString());
// this.bitmap.SetPixel(pt2_list[i].X,pt2_list[i].Y,Color.FromArgb(255,255,0,0));
// }
//
// this.bitmap.SetPixel(ptt1.X,ptt1.Y,Color.FromArgb(255,0,255,0));
// this.bitmap.SetPixel(ptt2.X,ptt2.Y,Color.FromArgb(255,0,255,0));
//裁剪图片
int new_width=ptt2.X-ptt1.X;
int new_height=ptt2.Y-ptt1.Y;
Bitmap temp=new Bitmap(new_width,new_height,PixelFormat.Format32bppArgb);
for(int i=ptt1.Y,h=0;i<ptt2.Y;i++,h++)
{
for(int j=ptt1.X,w=0;j<ptt2.X;j++,w++)
{
Color clr=this.bitmap.GetPixel(j,i);
temp.SetPixel(w,h,Color.FromArgb(clr.A,clr.R,clr.G,clr.B));
}
}
this.bitmap.Dispose();
this.bitmap=new Bitmap(temp,pictureBox1.Width,pictureBox1.Height);
pictureBox1.Image=this.bitmap;
}
void MainFormSizeChanged(object sender, EventArgs e)
{
}
void MainFormResize(object sender, EventArgs e)
{
if(this.WindowState==FormWindowState.Maximized || this.WindowState==FormWindowState.Normal)
{
if(this.bitmap!=null)
{
this.bitmap.Dispose();
this.bitmap=new Bitmap(this.pictureBox1.Image,this.pictureBox1.Width,this.pictureBox1.Height);
}
}
}
void Button4Click(object sender, EventArgs e)
{
SaveFileDialog sfd=new SaveFileDialog();
sfd.Filter="JPG File|*.jpg|GIF File|*.gif";
if(sfd.ShowDialog()==DialogResult.OK)
{
this.pictureBox1.Image.Save(sfd.FileName);
}
}
void Button5Click(object sender, EventArgs e)
{
int bmpWidth=this.bitmap.Width;
int bmpHeight=this.bitmap.Height;
int[] whitePoints=new int[bmpWidth];
//统计在水平方向上的非0像素的个数
for(int j=0;j<bmpWidth;j++)
{
whitePoints[j]=0;
for(int i=0;i<bmpHeight;i++)
{
Color clr=this.bitmap.GetPixel(j,i);
if(clr.A==255&&clr.R==255&&clr.G==255&&clr.B==255)
{
whitePoints[j]++;
}
}
Trace.WriteLine(j.ToString()+","+whitePoints[j].ToString());
}
//找出0的转变点
List<int> splitPoints=new List<int>();
for(int j=0;j<bmpWidth-1;j++)
{
if(whitePoints[j]==0)
{
if(whitePoints[j+1]!=0)
{
Trace.Write((j+1).ToString()+",");
splitPoints.Add(j+1);
}
}
else
{
if(whitePoints[j+1]==0)
{
Trace.Write((j+1).ToString()+",");
splitPoints.Add(j+1);
}
}
}
//画出红色竖线
// for(int j=0;j<splitPoints.Count;j++)
// {
// for(int i=0;i<bmpHeight;i++)
// {
// this.bitmap.SetPixel(splitPoints[j],i,Color.FromArgb(255,255,0,0));
// }
// }
//
// this.pictureBox1.Image=this.bitmap;
//分割各个字符到下面的图片框中
for(int k=0;k<4;k++)
{
Bitmap tmp=new Bitmap(splitPoints[2*k+1]-splitPoints[2*k],bmpHeight,PixelFormat.Format32bppArgb);
for(int j=0,h=0;j<bmpHeight;j++,h++)
{
for(int i=splitPoints[2*k],w=0;i<splitPoints[2*k+1];i++,w++)
{
Color clr=this.bitmap.GetPixel(i,j);
tmp.SetPixel(w,h,Color.FromArgb(clr.A,clr.R,clr.G,clr.B));
}
}
if(k==0) this.pictureBox2.Image=tmp;
if(k==1) this.pictureBox3.Image=tmp;
if(k==2) this.pictureBox4.Image=tmp;
if(k==3) this.pictureBox5.Image=tmp;
}
}
【更多阅读】
- [译]在C# .NET2.0实现单实例应用程序
- [原]ManageStartUpApps:C#操作注册表来读取和修改开机启动项
- [原]PjCleanSystemTrash:C#清除系统盘垃圾
- [原]ManageApps:C#读取Windows系统中的已经安装的程序并卸载软件
- [原]WMICodeCreator:C#产生WMI代码的工具
- [原]《The C Programming Language》电子书下载
- [原]Baidu:C#利用百度来搜索网页、图片、视频等等
- [原]WMICodeCreator:C#产生WMI代码的工具
- [原]PjConvertImageFormat:用FreeImage.NET写的一个35种图像格式转换程序
- [原]DownloadWebImages:下载某页面上的所有图片