GetAlpha:C#实现获取网页验证码图片,并识别出其中的字母

时间:2021-09-30 15:59:13

由于网页上的验证码图片都是通过程序产生的,因此,各个字母之间也都比较规则,进行识别其中的字符的话,也比较简单,只要将图片进行相减后,看看和那个字母的图片接近即可.

下面,我就那我们公司的外网邮箱:http://mail.lida-oe.com.cn的网页中的验证码为例子,我写了一个程序.

【网通】点击这里下载全部源程序    【电信、网通】点击这里下载源程序

【下载说明】
1、单击上面这个地址,打开下载页面。
2、点普通下载--等待30秒--点“下载”按钮--保存

整个程序的过程是这样的:

1 获取网页中的图片的地址,并下载到本地

2 对图像的像素中的A(透明度)值,来对图像进行二值化处理

3 对整个图片进行裁剪,仅裁剪出包含字符的区域

4 使用投影法对图像进行分割,从而保证每个分割区域仅包含一个字符

5 对分割出来的图片,再次进行裁剪,使得整个字符充满图片框,并大小一致

6 因此对分割出来的字符图片与图片库中的图片进行比较,相差最小的仅为字符.

我首先是搜集了多幅的验证码图片,以便能够得到所有的字符的图片. 然后,对这些搜集来的图片进行分割,从而得到包含26个字母的图片. 将这些图片作为图片库, 之后将从网页中获取的图片分割出来的字符图片,与此对比,从而得到识别结果.

截图如下:

GetAlpha:C#实现获取网页验证码图片,并识别出其中的字母

获取网页中验证码图片之后,如上图。

GetAlpha:C#实现获取网页验证码图片,并识别出其中的字母

将图片进行“二值化”之后的图片,如上图。

GetAlpha:C#实现获取网页验证码图片,并识别出其中的字母

之后,对图片进行剪裁,如上图。

GetAlpha:C#实现获取网页验证码图片,并识别出其中的字母

再使用投影法,分割出每个字符,如上图。

GetAlpha:C#实现获取网页验证码图片,并识别出其中的字母

将分割出来的字符进行剪裁,如上图。

GetAlpha:C#实现获取网页验证码图片,并识别出其中的字母

最终,通过与样本库的字符图片进行对比,识别出图片中的字母。

部分源程序:

主要源程序(由于做的比较急,并未对程序结构进行优化):

/*
* 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;
}
}

【更多阅读】

  1. [译]在C# .NET2.0实现单实例应用程序
  2. [原]ManageStartUpApps:C#操作注册表来读取和修改开机启动项
  3. [原]PjCleanSystemTrash:C#清除系统盘垃圾
  4. [原]ManageApps:C#读取Windows系统中的已经安装的程序并卸载软件
  5. [原]WMICodeCreator:C#产生WMI代码的工具
  6. [原]《The C Programming Language》电子书下载
  7. [原]Baidu:C#利用百度来搜索网页、图片、视频等等
  8. [原]WMICodeCreator:C#产生WMI代码的工具
  9. [原]PjConvertImageFormat:用FreeImage.NET写的一个35种图像格式转换程序
  10. [原]DownloadWebImages:下载某页面上的所有图片