宝峰科技

 找回密码
 注册

QQ登录

只需一步,快速开始

智能终端设备维修查询系统注册会员邮箱认证须知!
查看: 3573|回复: 0

[推荐] 简单验证码识别程序

[复制链接]
  • TA的每日心情
    开心
    2024-12-9 18:45
  • 签到天数: 124 天

    [LV.7]常住居民III

    admin 发表于 2010-9-28 22:10:26 | 显示全部楼层 |阅读模式

    欢迎您注册加入!这里有您将更精采!

    您需要 登录 才可以下载或查看,没有账号?注册

    x
    简单验证码是指验证码图片里的字符,固定不变,或者变化很小的验证码,比如:字符上会有一些干扰点干扰线等情况,或者只有少数几种字体变化和字体大小变化。

        这里给出源代码都是非常简单的源代码,学过《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[W][H]={0};
    int YZM_red[W][H]={0};
    int YZM_green[W][H]={0};
    int YZM_blue[W][H]={0};
    int rec[W]={0};
    int lf[N],rt[N],up[N],dw[N];
    char result[N];

    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[x][y]=fgetc(fp);YZM_green[x][y]=fgetc(fp);YZM_red[x][y]=fgetc(fp);}
        //依次读取每个像素的RGB值
    }
    fclose(fp);//关闭文件



        好的,通过以上几个语句就可以把图片信息读取到程序的数组里了,然后对其进行二值化,去干扰等工作。
        二值化就是把刚才读取的RGB信息,转换成01数据,0表示空白背景,1表示字符。


    for(x=0;x<W;x++)for(y=0;y<H;y++)
    {
        if(YZM_red[x][y]*0.3+YZM_green[x][y]*0.6+YZM_blue[x][y]*0.1<200)YZM[x][y]=1;else YZM[x][y]=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[x][y]==1 && YZM[x-1][y-1]==0 && YZM[x][y-1]==0 && YZM[x+1][y-1]==0 && YZM[x-1][y]==0 && YZM[x+1][y]==0 && YZM[x-1][y+1]==0 && YZM[x][y+1]==0 && YZM[x+1][y+1]==0)YZM[x][y]=0;
         //如果一个点的值是1,而且它的周围8个点的值都是0,那么这个点就是干扰点
    } 经过这些预处理工作就可以得到一个二进制数组数据了。我们以一组普通的验证码图片为例,



    for(y=0;y<H;y++) { for(x=0;x<W;x++) printf(" %c",YZM[x][y]+'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[x][y];
        if(s>0)rec[x]=1;else rec[x]=0;//rec记录数组的断连情况
    }
    for(i=0,x=1;x<W-1;x++)if(rec[x-1]==0 && rec[x]==1 && rec[x+1]==1){i++;lf[i]=x;}//计算每个字符的左边界
    for(i=0,x=1;x<W-1;x++)if(rec[x-1]==1 && rec[x]==1 && rec[x+1]==0){i++;rt[i]=x;}//计算每个字符的右边界
    for(i=1;i<=N;i++)for(x=0;x<W;x++)for(y=0;y<H;y++) if(x>=lf[i] && x<=rt[i] && YZM[x][y]==1)YZM[x][y]=i;
    for(y=H-1;y>=0;y--)for(x=0;x<W;x++)for(i=1;i<=N;i++)if(YZM[x][y]==i)up[i]=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[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==0 &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==0 && YZM[lf[i]+2][up[i]+1]==i &&
            YZM[lf[i]+0][up[i]+2]==0 && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==i &&
            YZM[lf[i]+0][up[i]+3]==i && YZM[lf[i]+1][up[i]+3]==i && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==i && YZM[lf[i]+1][up[i]+4]==i && YZM[lf[i]+2][up[i]+4]==0 )result[i-1]='0';
        if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==i &&
            YZM[lf[i]+0][up[i]+2]==i && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==i &&
            YZM[lf[i]+0][up[i]+3]==0 && YZM[lf[i]+1][up[i]+3]==0 && YZM[lf[i]+2][up[i]+3]==i &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==0 && YZM[lf[i]+2][up[i]+4]==i )result[i-1]='1';
        if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==i &&
            YZM[lf[i]+0][up[i]+2]==i && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==0 && YZM[lf[i]+1][up[i]+3]==0 && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==0 && YZM[lf[i]+2][up[i]+4]==0 )result[i-1]='2';
        if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==i && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==i && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==0 &&
            YZM[lf[i]+0][up[i]+2]==0 && YZM[lf[i]+1][up[i]+2]==0 && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==0 && YZM[lf[i]+1][up[i]+3]==0 && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==0 && YZM[lf[i]+2][up[i]+4]==0 )result[i-1]='3';
        if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==0 &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==0 && YZM[lf[i]+2][up[i]+1]==0 &&
            YZM[lf[i]+0][up[i]+2]==0 && YZM[lf[i]+1][up[i]+2]==0 && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==0 && YZM[lf[i]+1][up[i]+3]==0 && YZM[lf[i]+2][up[i]+3]==i &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==i && YZM[lf[i]+2][up[i]+4]==i )result[i-1]='4';
        if( YZM[lf[i]+0][up[i]+0]==i && YZM[lf[i]+1][up[i]+0]==i && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==i && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==0 &&
            YZM[lf[i]+0][up[i]+2]==i && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==i && YZM[lf[i]+1][up[i]+3]==i && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==i && YZM[lf[i]+1][up[i]+4]==i && YZM[lf[i]+2][up[i]+4]==i )result[i-1]='5';
        if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==i &&
            YZM[lf[i]+0][up[i]+2]==i && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==i && YZM[lf[i]+1][up[i]+3]==i && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==i && YZM[lf[i]+1][up[i]+4]==i && YZM[lf[i]+2][up[i]+4]==0 )result[i-1]='6';
        if( YZM[lf[i]+0][up[i]+0]==i && YZM[lf[i]+1][up[i]+0]==i && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==0 && YZM[lf[i]+2][up[i]+1]==0 &&
            YZM[lf[i]+0][up[i]+2]==0 && YZM[lf[i]+1][up[i]+2]==0 && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==0 && YZM[lf[i]+1][up[i]+3]==0 && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==0 && YZM[lf[i]+2][up[i]+4]==0 )result[i-1]='7';
        if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==i &&
            YZM[lf[i]+0][up[i]+2]==i && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==0 && YZM[lf[i]+1][up[i]+3]==i && YZM[lf[i]+2][up[i]+3]==i &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==0 && YZM[lf[i]+2][up[i]+4]==i )result[i-1]='8';
        if( YZM[lf[i]+0][up[i]+0]==0 && YZM[lf[i]+1][up[i]+0]==0 && YZM[lf[i]+2][up[i]+0]==i &&
            YZM[lf[i]+0][up[i]+1]==0 && YZM[lf[i]+1][up[i]+1]==i && YZM[lf[i]+2][up[i]+1]==i &&
            YZM[lf[i]+0][up[i]+2]==i && YZM[lf[i]+1][up[i]+2]==i && YZM[lf[i]+2][up[i]+2]==0 &&
            YZM[lf[i]+0][up[i]+3]==i && YZM[lf[i]+1][up[i]+3]==i && YZM[lf[i]+2][up[i]+3]==0 &&
            YZM[lf[i]+0][up[i]+4]==0 && YZM[lf[i]+1][up[i]+4]==i && YZM[lf[i]+2][up[i]+4]==i )result[i-1]='9';
    }
    printf("%s",result);//输出识别结果
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    免责声明

    本站中所有被研究的素材与信息全部来源于互联网,版权争议与本站无关。本站所发布的任何软件编程开发或软件的逆向分析文章、逆向分析视频、补丁、注册机和注册信息,仅限用于学习和研究软件安全的目的。全体用户必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。学习编程开发技术或逆向分析技术是为了更好的完善软件可能存在的不安全因素,提升软件安全意识。所以您如果喜欢某程序,请购买注册正版软件,获得正版优质服务!不得将上述内容私自传播、销售或者用于商业用途!否则,一切后果请用户自负!

    QQ|Archiver|手机版|小黑屋|联系我们|宝峰科技 ( 滇公网安备 53050202000040号 | 滇ICP备09007156号-2 )

    Copyright © 2001-2023 Discuz! Team. GMT+8, 2024-12-22 23:11 , File On Powered by Discuz! X3.49

    快速回复 返回顶部 返回列表