QQ验证码识别源代码(C#/NET1.1)
using System;
namespace QQ
{
///
1<summary>
2/// yzm 的摘要说明。
3/// </summary>
public class yzm
{
public yzm(public System.Drawing.Bitmap pic)
{
this.bp = pic;
}
///
1<summary>
2/// 将一个int值存入到4个字节的字节数组(从高地址开始转换,最高地址的值以无符号整型参与"与运算")
3/// </summary>
///
1<param name="thevalue"/>
要处理的int值
///
1<param name="thebuff"/>
存放信息的字符数组
public static void getbytesfromint(int thevalue, byte[] thebuff)
{
long v1=0; long v2=0; long v3=0; long v4=0;
uint b1=(uint)4278190080; uint b2=(uint)16711680; uint b3=(uint)65280; uint b4=(uint)255;
v1=thevalue & b1;
v2=thevalue & b2;
v3=thevalue & b3;
v4=thevalue & b4;
thebuff[0]=(byte)(v1>>24);
thebuff[1]=(byte)(v2>>16);
thebuff[2]=(byte)(v3>>8);
thebuff[3]=(byte)v4;
}
///
1<summary>
2/// 将一个ushort值存入到2个字节的字节数组(从高地址开始转换,最高地址的值以无符号整型参与"与运算")
3/// </summary>
///
1<param name="thevalue"/>
要处理的ushort值
///
1<param name="thebuff"/>
存放信息的字符数组
public static void getbytesfromushort(ushort thevalue, byte[] thebuff)
{
ushort v1=0; ushort v2=0;
ushort b1=(ushort)65280; ushort b2=(ushort)255;
v1=(ushort)(thevalue & b1);
v2=(ushort)(thevalue & b2);
thebuff[0]=(byte)(v1>>8);
thebuff[1]=(byte)(v2);
}
///
1<summary>
2/// 将4个字节的字节数组转换成一个int值
3/// </summary>
///
1<param name="thebuff"/>
字符数组
///
1<returns></returns>
public static int getintfrombyte(byte[] thebuff)
{
int jieguo=0;
long mid=0;
long m1=0; long m2=0; long m3=0; long m4=0;
m1=(thebuff[0]<<24);
m2=(thebuff[1]<<16);
m3=(thebuff[2]<<8);
m4=thebuff[3];
mid=m1+m2+m3+m4;
jieguo=(int)mid;
return jieguo;
}
///
1<summary>
2/// 将2个字节的字节数组转换成一个ushort值
3/// </summary>
///
1<param name="thebuff"/>
字符数组
///
1<returns></returns>
public static ushort getushortfrombyte(byte[] thebuff)
{
int jieguo1=0;
jieguo1=(thebuff[0]<<8)+thebuff[1];
ushort jieguo=(ushort)jieguo1;
return jieguo;
}
///
1<summary>
2/// 将内存中的数据写入硬盘(保存特征库)
3/// </summary>
///
1<param name="thefile"/>
保存的位置
public static void writetofile(string thefile)
{
System.IO.FileStream fs = new System.IO.FileStream(thefile,System.IO.FileMode.OpenOrCreate,System.IO.FileAccess.ReadWrite);
byte[] buff0=new byte[4];
getbytesfromint(datanum,buff0);
fs.Write(buff0,0,4);
for(int ii=0;ii
1<datanum;ii++) <summary="" buff="new" byte[2];="" byte[]="" for(int="" fs.close();="" fs.write(buff,0,2);="" fs.writebyte(datachar[ii]);="" fs.writebyte(dataxy[ii,0]);="" fs.writebyte(dataxy[ii,1]);="" getbytesfromushort(datap[ii,jj],buff);="" jj="0;jj<20;jj++)" {="" }="">
2/// 从文件中读取信息,并保存在内存中相应的位置
3///
4/// <param name="thefile"/>特征库文件
5public static void readfromfile(string thefile)
6{
7int allnum=0;
8byte[] buff=new byte[4];
9System.IO.FileStream fs = new System.IO.FileStream(thefile,System.IO.FileMode.Open,System.IO.FileAccess.Read);
10fs.Read(buff,0,4);
11allnum=getintfrombyte(buff);
12byte[] buff0=new byte[2];
13for(int ii=0;ii<allnum;ii++) <summary="" datachar[ii]="buff0[0];" datanum="allnum;" datap[ii,jj]="getushortfrombyte(buff0);" dataxy[ii,0]="buff0[0];" dataxy[ii,1]="buff0[0];" for(int="" fs.close();="" fs.read(buff0,0,1);="" fs.read(buff0,0,2);="" jj="0;jj<20;jj++)" {="" }="">
14/// 验证码图片
15///
16public System.Drawing.Bitmap bp =new System.Drawing.Bitmap(49,20);
17/// <summary>
18/// 特征库的长度
19/// </summary>
20public static int datanum=0;
21/// <summary>
22/// 特征库数据
23/// </summary>
24public static ushort[,] datap=new ushort[100000,20];
25/// <summary>
26/// 长度与高度
27/// </summary>
28public static byte[,] dataxy=new byte[100000,2];
29/// <summary>
30/// 对应的字符
31/// </summary>
32public static byte[] datachar=new byte[100000];
33/// <summary>
34/// 等待处理的数据
35/// </summary>
36public ushort[] datapic=new ushort[20];
37/// <summary>
38/// 有效长度
39/// </summary>
40public byte xlpic=0;
41/// <summary>
42/// 有效宽度
43/// </summary>
44public byte ylpic=0;
45/// <summary>
46/// 检索特征库中存在的记录
47/// </summary>
48public string getchar()
49{
50//如果查找不到,就返回空串
51string jieguo="";
52for(int ii=0;ii<datanum;ii++) <summary="" char="" cj="(char)datachar[ii];" cj.tostring();="" continue;="" dataxy[ii,1]!="ylpic)" for(int="" if(datap[ii,jj]!="datapic[jj])" if(dataxy[ii,0]!="xlpic" if(notsamenum<4)="" int="" jieguo;="" jj="0;jj<20;jj++)" notsamenum="0;" notsamenum++;="" return="" {="" ||="" }="" 如果能够收集更多的特征库,识别率可以达到80%以上="" 当然也可以改进品配算法(如使用关键点品配),以用较少的特征库达到较高的识别率,但="" 统计一共有多少行的像素有差异,如果在4行以内就认为是存在该记录="" 这种方法比较原始,但比较适合多线程时的运行,因为程序只进行简单的逻辑比较="" 那样有比较大的机会造成识别错误并且多线程时占用较多cpu时间。="" (此时可能需要将特征库的容量提高到15w个或以上)="">
53/// 检查特征库中是否已经存在相关记录
54///
55bool ischardatain()
56{
57bool jieguo=false;
58for(int ii=0;ii<datanum;ii++) if(system.math.abs(dataxy[ii,0]-xlpic)="" int="" notsamenum="0;" {="" 如果能够收集更多的特征库,识别率可以达到80%以上="" 当然也可以改进品配算法(如使用关键点品配),以用较少的特征库达到较高的识别率,但="" 统计一共有多少行的像素有差异,如果在4行以内就认为是存在该记录="" 这种方法比较原始,但比较适合多线程时的运行,因为程序只进行简单的逻辑比较="" 那样有比较大的机会造成识别错误并且多线程时占用较多cpu时间。="" (此时可能需要将特征库的容量提高到15w个或以上)="">1 || System.Math.Abs(dataxy[ii,1]-ylpic)>1)
59{
60continue;
61}
62for(int jj=0;jj<20;jj++)
63{
64if(datap[ii,jj]!=datapic[jj])
65{
66notsamenum++;
67}
68}
69if(notsamenum<4)
70{
71string asdasd=((char)datachar[ii]).ToString();
72return true;
73}
74}
75return jieguo;
76}
77/// <summary>
78/// 添加到特征库中,并暂时将对应的字符置为空格以待人工识别
79/// </summary>
80void adddatawithnullchar()
81{
82if(this.ischardatain())
83{
84return;
85}
86for(int ii=0;ii<20;ii++)
87{
88datap[datanum,ii]=this.datapic[ii];
89}
90//暂时将对应的字符置为空格以待人工识别
91datachar[datanum]=32;
92dataxy[datanum,0]=this.xlpic;
93dataxy[datanum,1]=this.ylpic;
94datanum++;
95}
96/// <summary>
97/// 检查验证码图片是否能分成4个部分,如果可以就检查4个字符在特征库中是否已经存在,如果不存在,
98/// 就添加到特征库中,并暂时将对应的字符置为空格以待人工识别
99/// </summary>
100public void writetodata()
101{
102bool[,] picpixel=new bool[49,20];
103for(int ii=0;ii<49;ii++)
104{
105for(int jj=0;jj<20;jj++)
106{
107if(bp.GetPixel(ii,jj).GetBrightness()<0.999)
108{
109picpixel[ii,jj]=true;
110}
111}
112}
113int[] index=new int[8];
114int indexnum=0;
115bool black=false;
116for(int ii=0;ii<49;ii++)
117{
118bool haveblack=false;
119for(int jj=0;jj<20;jj++)
120{
121if(picpixel[ii,jj])
122{
123haveblack=true;
124break;
125}
126}
127if(haveblack && black==false)
128{
129index[indexnum]=ii;
130indexnum++;
131black=true;
132}
133if(!haveblack && black)
134{
135index[indexnum]=ii;
136indexnum++;
137black=false;
138}
139}
140if(indexnum<7)
141{
142return;
143}
144if(indexnum==7)
145{
146index[7]=49;
147}
148//****
149for(int ii=0;ii<4;ii++)
150{
151int x1=index[ii*2];
152int x2=index[ii*2+1];
153int y1=0,y2=19;
154bool mb=false;
155for(int jj=0;jj<20;jj++)
156{
157for(int kk=x1;kk<x2;kk++) break;="" for(int="" if(mb)="" if(picpixel[kk,jj])="" jj="19;jj" mb="false;" y1="jj;" {="" }="">=0;jj--)
158{
159for(int kk=x1;kk<x2;kk++) **以上是获取有效区域的范围="" break;="" for(int="" if(mb)="" if(picpixel[kk,jj])="" if(xlpic="" jj="0;jj<20;jj++)" mb="true;" this.datapic[jj]="0;" this.xlpic="(byte)(x2-x1);" y2="jj;" {="" }="" 如果字符宽度超过16个像素就不予处理="">16)
160{
161continue;
162}
163this.ylpic=(byte)(y2-y1+1);
164int ys=-1;
165ushort[] addin=new ushort[]{1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
166for(int jj=y1;jj<=y2;jj++)
167{
168ys++;
169int xs=-1;
170for(int kk=x1;kk<x2;kk++) ****="" <summary="" if(picpixel[kk,jj])="" this.adddatawithnullchar();="" this.datapic[ys]="(ushort)(this.datapic[ys]+addin[xs]);" xs++;="" {="" }="">
171/// 识别图片
172///
173/// <returns>返回识别结果(如果返回的字符串长度小于4就说明识别失败)</returns>
174public string ocrpic()
175{
176string jieguo="";
177bool[,] picpixel=new bool[49,20];
178for(int ii=0;ii<49;ii++)
179{
180for(int jj=0;jj<20;jj++)
181{
182if(bp.GetPixel(ii,jj).GetBrightness()<0.999)
183{
184picpixel[ii,jj]=true;
185}
186}
187}
188int[] index=new int[8];
189int indexnum=0;
190bool black=false;
191for(int ii=0;ii<49;ii++)
192{
193bool haveblack=false;
194for(int jj=0;jj<20;jj++)
195{
196if(picpixel[ii,jj])
197{
198haveblack=true;
199break;
200}
201}
202if(haveblack && black==false)
203{
204index[indexnum]=ii;
205indexnum++;
206black=true;
207}
208if(!haveblack && black)
209{
210index[indexnum]=ii;
211indexnum++;
212black=false;
213}
214}
215if(indexnum<7)
216{
217return jieguo;
218}
219if(indexnum==7)
220{
221index[7]=49;
222}
223//****
224for(int ii=0;ii<4;ii++)
225{
226int x1=index[ii*2];
227int x2=index[ii*2+1];
228int y1=0,y2=19;
229bool mb=false;
230for(int jj=0;jj<20;jj++)
231{
232for(int kk=x1;kk<x2;kk++) break;="" for(int="" if(mb)="" if(picpixel[kk,jj])="" jj="19;jj" mb="false;" y1="jj;" {="" }="">=0;jj--)
233{
234for(int kk=x1;kk<x2;kk++) **以上是获取有效区域的范围="" break;="" for(int="" if(mb)="" if(picpixel[kk,jj])="" if(xlpic="" jj="0;jj<20;jj++)" mb="true;" this.datapic[jj]="0;" this.xlpic="(byte)(x2-x1);" y2="jj;" {="" }="" 如果字符宽度超过16个像素就不予处理="">16)
235{
236continue;
237}
238this.ylpic=(byte)(y2-y1+1);
239int ys=-1;
240ushort[] addin=new ushort[]{1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
241for(int jj=y1;jj<=y2;jj++)
242{
243ys++;
244int xs=-1;
245for(int kk=x1;kk<x2;kk++)
246{
247xs++;
248if(picpixel[kk,jj])
249{
250this.datapic[ys]=(ushort)(this.datapic[ys]+addin[xs]);
251}
252}
253}
254jieguo=jieguo+this.getchar();
255}
256return jieguo;
257}
258}
259}
260---
261
262---</x2;kk++)></x2;kk++)></x2;kk++)></x2;kk++)></x2;kk++)></datanum;ii++)></datanum;ii++)></allnum;ii++)></datanum;ii++)>