C语言 — 简单验证码识别程序
C语言 — 简单验证码识别程序简单验证码是指验证码图片里的字符,固定不变,或者变化很小的验证码,比如:字符上会有一些干扰点干扰线等情况,或者只有少数几种字体变化和字体大小变化。
这里给出源代码都是非常简单的源代码,学过《C程序设计》的都可以看懂,不会超出书本范围,而且不使用指针,这样VB,Delphi,JAVA 等语言都可以照此写出相应的源代码。
验证码识别可以分为三个大的步骤:预处理,分割,识别。预处理又可细分为读取图片,二值化,去干扰点,去干扰线等等步骤。
读取图片很简单就是把要识别的验证码图片读取到我们的程序里,网络上常见的验证码图片格式有BMP,JPG,GIF,PNG,其中BMP的图片格式种类很多,但都不复杂,24位BMP格式最简单,除去54字节的文件头,只需要顺序读取BMP文件的字节信息就可以了,256色的也就是8位的BMP格式也很常见,256色BMP图片在文件头后多一个索引表,后面也是顺序存储图片信息的。JPG,GIF,PNG的格式都复杂一点,不过网上都有这些公司或组织发布的source code。
下面以24位BMP格式的源代码进行说明:
#define W 40 //定义验证码图片的宽度
#define H 20 //定义验证码图片的宽度
#define N 4 //定义字符位数,一般是4位
#define BMP_filename "c:\\test.bmp"
int x,y,i,s,temp;
int YZM={0};
int YZM_red={0};
int YZM_green={0};
int YZM_blue={0};
int rec={0};
int lf,rt,up,dw;
char result;
FILE *fp=fopen(BMP_filename,"rb");//以二进制只读方式打开BMP文件
for(i=0;i<54;i++)temp=fgetc(fp);//跳过54个字节的文件头数据
for(y=H-1;y>=0;y--)//BMP图片数据是倒序存储的,据说是为了下载显示方便,呵呵
{
for(x=0;x<W;x++){YZM_blue=fgetc(fp);YZM_green=fgetc(fp);YZM_red=fgetc(fp);}
//依次读取每个像素的RGB值
}
fclose(fp);//关闭文件
好的,通过以上几个语句就可以把图片信息读取到程序的数组里了,然后对其进行二值化,去干扰等工作。
二值化就是把刚才读取的RGB信息,转换成01数据,0表示空白背景,1表示字符。
for(x=0;x<W;x++)for(y=0;y<H;y++)
{
if(YZM_red*0.3+YZM_green*0.6+YZM_blue*0.1<200)YZM=1;else YZM=0;
//red*0.3+green*0.6+blue*0.1 是计算亮度的公式
}
//如果图片里有干扰点,可以用下面的语句去除。
for(x=1;x<W-1;x++)for(y=1;y<H-1;y++)
{
if(YZM==1 && YZM==0 && YZM==0 && YZM==0 && YZM==0 && YZM==0 && YZM==0 && YZM==0 && YZM==0)YZM=0;
//如果一个点的值是1,而且它的周围8个点的值都是0,那么这个点就是干扰点
} 经过这些预处理工作就可以得到一个二进制数组数据了。我们以一组普通的验证码图片为例,
for(y=0;y<H;y++) { for(x=0;x<W;x++) printf(" %c",YZM+'0'); printf("\n"); }
我们可以用上面的输出语句进行输出,输出语句在最终的程序中可以删除或者注释掉。
输出结果如下:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 1 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 1 1 1 1 1 1 1 0 0 0 0
0 0 1 1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 0 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0
0 0 1 1 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0
0 0 1 1 0 1 1 1 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0 0 0 0
0 0 1 1 1 0 0 1 1 0 0 0 0 0 1 1 0 0 0 0 1 1 0 1 1 1 0 0 0 1 1 1 0 0 1 1 0 0 0 0
0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 1 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0
0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0
0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 1 1 0 0 0 0 1 1 0 0 0
0 0 0 1 1 0 0 1 1 0 0 0 0 0 1 1 0 0 0 0 0 1 1 0 0 1 1 0 0 0 1 1 0 0 1 1 0 0 0 0
0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
for(x=0;x<W;x++)
{ s=0;
for(y=0;y<H;y++)s=s+YZM;
if(s>0)rec=1;else rec=0;//rec记录数组的断连情况
}
for(i=0,x=1;x<W-1;x++)if(rec==0 && rec==1 && rec==1){i++;lf=x;}//计算每个字符的左边界
for(i=0,x=1;x<W-1;x++)if(rec==1 && rec==1 && rec==0){i++;rt=x;}//计算每个字符的右边界
for(i=1;i<=N;i++)for(x=0;x<W;x++)for(y=0;y<H;y++) if(x>=lf && x<=rt && YZM==1)YZM=i;
for(y=H-1;y>=0;y--)for(x=0;x<W;x++)for(i=1;i<=N;i++)if(YZM==i)up=y;//计算每个字符的上边界
经过上面的分割语句,我们就完成了分割工作,我们可以用输出语句进行输出,输出结果如下:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 1 1 1 0 0 0 0 0 2 2 0 0 0 0 0 0 3 3 3 3 0 0 0 4 4 4 4 4 4 4 0 0 0 0
0 0 1 1 0 0 0 0 0 0 0 0 0 2 2 2 0 0 0 0 0 3 3 0 0 3 3 0 0 4 4 0 0 0 0 0 0 0 0 0
0 0 1 1 0 0 0 0 0 0 0 0 2 2 2 2 0 0 0 0 3 3 0 0 0 0 3 0 0 4 4 0 0 0 0 0 0 0 0 0
0 0 1 1 0 1 1 1 0 0 0 0 0 0 2 2 0 0 0 0 3 3 0 0 0 0 0 0 0 4 4 0 4 4 4 0 0 0 0 0
0 0 1 1 1 0 0 1 1 0 0 0 0 0 2 2 0 0 0 0 3 3 0 3 3 3 0 0 0 4 4 4 0 0 4 4 0 0 0 0
0 0 0 0 0 0 0 0 1 1 0 0 0 0 2 2 0 0 0 0 3 3 3 0 0 3 3 0 0 0 0 0 0 0 0 4 4 0 0 0
0 0 0 0 0 0 0 0 1 1 0 0 0 0 2 2 0 0 0 0 3 3 0 0 0 0 3 3 0 0 0 0 0 0 0 4 4 0 0 0
0 0 1 1 0 0 0 0 1 1 0 0 0 0 2 2 0 0 0 0 3 3 0 0 0 0 3 3 0 4 4 0 0 0 0 4 4 0 0 0
0 0 0 1 1 0 0 1 1 0 0 0 0 0 2 2 0 0 0 0 0 3 3 0 0 3 3 0 0 0 4 4 0 0 4 4 0 0 0 0
0 0 0 0 1 1 1 1 0 0 0 0 2 2 2 2 2 2 0 0 0 0 3 3 3 3 0 0 0 0 0 4 4 4 4 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
最后我们就可以进行识别工作,识别的方法有很多,可以进行逐点的精确识别,也可以进行模糊识别等等,甚至也可以不进行去干扰和分割工作直接进行识别(主要用于粘连的验证码),这都要根据具体情况来具体分析用什么方法最有效,简单验证码的识别则没有那么复杂,用很多方法都可以识别,这里使用的是从每个字符的左上边界开始,精确判断5行3列15个点来进行识别。
for(i=1;i<=N;i++)
{
if( YZM==0 && YZM==0 && YZM==0 &&
YZM==0 && YZM==0 && YZM==i &&
YZM==0 && YZM==i && YZM==i &&
YZM==i && YZM==i && YZM==0 &&
YZM==i && YZM==i && YZM==0 )result='0';
if( YZM==0 && YZM==0 && YZM==i &&
YZM==0 && YZM==i && YZM==i &&
YZM==i && YZM==i && YZM==i &&
YZM==0 && YZM==0 && YZM==i &&
YZM==0 && YZM==0 && YZM==i )result='1';
if( YZM==0 && YZM==0 && YZM==i &&
YZM==0 && YZM==i && YZM==i &&
YZM==i && YZM==i && YZM==0 &&
YZM==0 && YZM==0 && YZM==0 &&
YZM==0 && YZM==0 && YZM==0 )result='2';
if( YZM==0 && YZM==i && YZM==i &&
YZM==i && YZM==i && YZM==0 &&
YZM==0 && YZM==0 && YZM==0 &&
YZM==0 && YZM==0 && YZM==0 &&
YZM==0 && YZM==0 && YZM==0 )result='3';
if( YZM==0 && YZM==0 && YZM==0 &&
YZM==0 && YZM==0 && YZM==0 &&
YZM==0 && YZM==0 && YZM==0 &&
YZM==0 && YZM==0 && YZM==i &&
YZM==0 && YZM==i && YZM==i )result='4';
if( YZM==i && YZM==i && YZM==i &&
YZM==i && YZM==i && YZM==0 &&
YZM==i && YZM==i && YZM==0 &&
YZM==i && YZM==i && YZM==0 &&
YZM==i && YZM==i && YZM==i )result='5';
if( YZM==0 && YZM==0 && YZM==i &&
YZM==0 && YZM==i && YZM==i &&
YZM==i && YZM==i && YZM==0 &&
YZM==i && YZM==i && YZM==0 &&
YZM==i && YZM==i && YZM==0 )result='6';
if( YZM==i && YZM==i && YZM==i &&
YZM==0 && YZM==0 && YZM==0 &&
YZM==0 && YZM==0 && YZM==0 &&
YZM==0 && YZM==0 && YZM==0 &&
YZM==0 && YZM==0 && YZM==0 )result='7';
if( YZM==0 && YZM==0 && YZM==i &&
YZM==0 && YZM==i && YZM==i &&
YZM==i && YZM==i && YZM==0 &&
YZM==0 && YZM==i && YZM==i &&
YZM==0 && YZM==0 && YZM==i )result='8';
if( YZM==0 && YZM==0 && YZM==i &&
YZM==0 && YZM==i && YZM==i &&
YZM==i && YZM==i && YZM==0 &&
YZM==i && YZM==i && YZM==0 &&
YZM==0 && YZM==i && YZM==i )result='9';
}
printf("%s",result);//输出识别结果
我擦!我要沙发! 无回帖,不论坛,这才是人道。 着玩意还是很有用处的。。。
页:
[1]