验证码切分程序
2016-04-25 16:24
411 查看
// 整合切分每个字符test.cpp : Defines the entry point for the console application. #include "stdafx.h" #include <stdio.h> #include <string> #include <math.h> #include <windows.h> #include <iostream> #include <io.h> using namespace std; //stdio.h包含FILE类 //windows.h包含位图头类,POINT类 #define PI 3.1415926535 //角度到弧度转化 #define RADIAN(angle) ((angle)*PI/180.0) void KB(const string& srcFile,const string& desFile) { BITMAPFILEHEADER bmfHeader;//位图文件头 BITMAPINFOHEADER bmiHeader;//位图信息头 //int bitCount;//位深度 //int RGBQuadNum;//调色板项数 //int srcW;//宽 //int srcH;//高 //int lineSize;//原图像每一行去除偏移量的字节数 //int alignBytes;//偏移量,windows系统要求每个扫描行按四字节对齐 int imgBufSize;//原图像缓存大小 BYTE* srcBuf;//原图像缓存 BYTE* filBuf;//滤波图像缓存 BYTE* segBuf;//分割图像缓存 FILE *pFile; if ((pFile = fopen(srcFile.c_str(),"rb")) == NULL)//二进制只读 { printf("open bmp file error."); exit(-1); } //读取文件和Bitmap头信息 // fseek(pFile,0,SEEK_SET);//从文件头偏移0个字节 fread(&bmfHeader,sizeof(BITMAPFILEHEADER),1,pFile); fread(&bmiHeader,sizeof(BITMAPINFOHEADER),1,pFile); //先不支持小于16位的位图 int bitCount = bmiHeader.biBitCount; //if (bitCount < 16) //{ // printf("bitCount < 16 ."); // exit(-1); //} //************************************************************************ //调色板项数 int RGBQuadNum=(bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER)-sizeof(BITMAPINFOHEADER))/sizeof(RGBQUAD); //分配调色板空间 RGBQUAD* strPla = new RGBQUAD[RGBQuadNum]; // printf("biBitCount=%d\n",bitCount); /// printf("biClrUesd=%d\n",bmiHeader.biClrUsed); // printf("sizeof(RGBQUAD)=%d\n",sizeof(RGBQUAD)); // printf("bfOffBits=%d\n",bmfHeader.bfOffBits); // printf("调色板项数=%d\n",RGBQuadNum); if(RGBQuadNum>0) fread(strPla,sizeof(RGBQUAD),RGBQuadNum,pFile); //************************************************************************ int srcW = bmiHeader.biWidth; int srcH = bmiHeader.biHeight; //原图像每一行去除偏移量的字节数 int lineSize = bitCount * srcW / 8; //偏移量,windows系统要求每个扫描行按四字节对齐 int alignBytes = ((bmiHeader.biWidth * bitCount + 31) & ~31) / 8L - bmiHeader.biWidth * bitCount / 8L; //原图像缓存 imgBufSize = lineSize * srcH; srcBuf = new BYTE[imgBufSize]; int desWidth=srcW; int desHeight=srcH; int desBufSize=imgBufSize; int i,j; //读取文件中数据 for (i = 0; i < srcH; i++) { fread(&srcBuf[lineSize * i],lineSize,1,pFile); //if(i==0) // for(j=0;j<30;j++) // printf("%d\n",srcBuf[j]); fseek(pFile,alignBytes,SEEK_CUR); } filBuf = new BYTE[imgBufSize]; memcpy(&filBuf[0],&srcBuf[0],imgBufSize); BYTE *tempBuf = new BYTE[imgBufSize]; memcpy(&tempBuf[0],&srcBuf[0],imgBufSize); //将上下左右边框先变黑 int k; for(i=0;i<srcH;i++) { for(k=0;k<bitCount/8;k++) tempBuf[i*lineSize+k]=0;//左1 for(k=0;k<bitCount/8;k++) tempBuf[i*lineSize+(srcW-1)*bitCount/8+k]=0;//右1 for(k=0;k<bitCount/8;k++) tempBuf[i*lineSize+1*bitCount/8+k]=0;//左2 for(k=0;k<bitCount/8;k++) tempBuf[i*lineSize+(srcW-2)*bitCount/8+k]=0;//右2 } for(j=0;j<srcW;j++) { for(k=0;k<bitCount/8;k++) tempBuf[j*bitCount/8+k]=0;//下1 for(k=0;k<bitCount/8;k++) tempBuf[(i-1)*lineSize+j*bitCount/8+k]=0;//上1 for(k=0;k<bitCount/8;k++) tempBuf[lineSize+j*bitCount/8+k]=0;//下2 for(k=0;k<bitCount/8;k++) tempBuf[(i-2)*lineSize+j*bitCount/8+k]=0;//上2 } int BCount=0; //3*3中值滤波 for(i=1;i<srcH-1;i++) for(j=1;j<srcW-1;j++) { BCount=0;//黑色数量 if(tempBuf[(i-1) * lineSize + (j-1) * bitCount / 8]==0)BCount++; if(tempBuf[(i-1) * lineSize + j * bitCount / 8]==0)BCount++; if(tempBuf[(i-1) * lineSize + (j+1) * bitCount / 8]==0)BCount++; if(tempBuf[i * lineSize + (j-1) * bitCount / 8]==0)BCount++; if(tempBuf[i * lineSize + j * bitCount / 8]==0)BCount++; if(tempBuf[i * lineSize + (j+1) * bitCount / 8]==0)BCount++; if(tempBuf[(i+1) * lineSize + (j-1) * bitCount / 8]==0)BCount++; if(tempBuf[(i+1) * lineSize + j * bitCount / 8]==0)BCount++; if(tempBuf[(i+1) * lineSize + (j+1) * bitCount / 8]==0)BCount++; if(BCount>=5) for(k=0;k<bitCount/8;k++) filBuf[i * lineSize + j * bitCount / 8+k]=0; else for(k=0;k<bitCount/8;k++) filBuf[i * lineSize + j * bitCount / 8+k]=255; } for(i=0;i<srcH;i++) { for(k=0;k<bitCount/8;k++) filBuf[i*lineSize+k]=0;//左1 for(k=0;k<bitCount/8;k++) filBuf[i*lineSize+(srcW-1)*bitCount/8+k]=0;//右1 for(k=0;k<bitCount/8;k++) filBuf[i*lineSize+1*bitCount/8+k]=0;//左2 for(k=0;k<bitCount/8;k++) filBuf[i*lineSize+(srcW-2)*bitCount/8+k]=0;//右2 } for(j=0;j<srcW;j++) { for(k=0;k<bitCount/8;k++) filBuf[j*bitCount/8+k]=0;//下1 for(k=0;k<bitCount/8;k++) filBuf[(i-1)*lineSize+j*bitCount/8+k]=0;//上1 for(k=0;k<bitCount/8;k++) filBuf[lineSize+j*bitCount/8+k]=0;//下2 for(k=0;k<bitCount/8;k++) filBuf[(i-2)*lineSize+j*bitCount/8+k]=0;//上2 } memcpy(&tempBuf[0],&filBuf[0],imgBufSize); //形如“┘”的结构元素,3个像素,原点在右下角,先腐蚀再膨胀 for(i=1; i<srcH-1; i++) { for( j=1; j<srcW-1; j++) { if(tempBuf[i * lineSize + j * bitCount / 8]==255 && tempBuf[(i+1) * lineSize + j * bitCount / 8]==0) for(k=0;k<bitCount/8;k++) filBuf[i * lineSize + j * bitCount / 8+k]=0; if(tempBuf[i * lineSize + j * bitCount / 8]==255 && tempBuf[i * lineSize + (j-1) * bitCount / 8]==0) for(k=0;k<bitCount/8;k++) filBuf[i * lineSize + j * bitCount / 8+k]=0; } } memcpy(&tempBuf[0],&filBuf[0],imgBufSize); for(i=1; i<srcH-1; i++) { for( j=1; j<srcW-1; j++) { if(tempBuf[i * lineSize + j * bitCount / 8]==0 && tempBuf[(i+1) * lineSize + j * bitCount / 8]==255) for(k=0;k<bitCount/8;k++) filBuf[i * lineSize + j * bitCount / 8+k]=255; if(tempBuf[i * lineSize + j * bitCount / 8]==0 && tempBuf[i * lineSize + (j-1) * bitCount / 8]==255) for(k=0;k<bitCount/8;k++) filBuf[i * lineSize + j * bitCount / 8+k]=255; } } //////////////////////////////////////////////////////// /////////////////////////////////////////////////////// segBuf = new BYTE[imgBufSize]; memcpy(&segBuf[0],&filBuf[0],imgBufSize); //////////////////////////////////////////////////////////////////////////////////////////////////////// //60是从-30到30,296是64+116*2 //k,b空间,k指角度,从-30到30,b是截距,从-116到64+116,用投影的方法判断左右方向的角度 int b; int XWhiteNum[60][296]; //初始化k,b空间为0 for(k=0;k<60;k++) for(b=0;b<296;b++) XWhiteNum[k][b]=0; //对于每一条直线y=kx+b,统计直线上白色点的个数XWhiteNum for(k=-30;k<30;k++) //for(b=-116;b<(64+116);b++) for(i=0;i<srcH;i++) for(j=0;j<srcW;j++) { //if(filBuf[i * lineSize + j * bitCount / 8]==255 && (int)(j*tan(RADIAN(k))+b)==i) b=i-(int)(j*tan(RADIAN(k))); if(filBuf[i * lineSize + j * bitCount / 8]==255 &&(b>=-116&&b<180)) XWhiteNum[k+30][b+116]++; } int XProjNum[60]; for(k=0;k<60;k++) XProjNum[k]=0; for(k=0;k<60;k++) { for(b=0;b<296;b++) if(XWhiteNum[k][b]!=0) XProjNum[k]++; } int Xmink,m; m=XProjNum[0]; Xmink=0; for(k=0;k<60;k++) if(XProjNum[k]<m) { m=XProjNum[k]; Xmink=k; } //cout<<"XProjNum最小的角度是"<<Xmink-30<<endl; // for(b=0;b<296;b++) // cout<<XWhiteNum[Xmink][b]<<","; // cout<<"..."<<endl<<endl<<endl; int Xb1,Xb2; for(b=0;b<296;b++) { if((XWhiteNum[Xmink][b-1]+XWhiteNum[Xmink][b]+XWhiteNum[Xmink][b+1])<30&& (XWhiteNum[Xmink][b]+XWhiteNum[Xmink][b+1]+XWhiteNum[Xmink][b+2])>=30) Xb1=b; if((XWhiteNum[Xmink][b-2]+XWhiteNum[Xmink][b-1]+XWhiteNum[Xmink][b])>30&& (XWhiteNum[Xmink][b-1]+XWhiteNum[Xmink][b]+XWhiteNum[Xmink][b+1])<=30) Xb2=b; } //cout<<"Xb1="<<Xb1-116<<",Xb2="<<Xb2-116<<endl; //画线 for(i=0;i<srcH;i++) for(j=0;j<srcW;j++) if((int)(j*tan(RADIAN(Xmink-30))+Xb1-116)==i||(int)(j*tan(RADIAN(Xmink-30))+Xb2-116)==i) { segBuf[i * lineSize + j * bitCount / 8]=0; segBuf[i * lineSize + j * bitCount / 8+1]=0; segBuf[i * lineSize + j * bitCount / 8+2]=255; } ///////////////////////////////////////////////////////////////////////////////////////// //x=ky+b //60是从-30到30,274是200+37*2 int YWhiteNum[60][274]; for(k=0;k<60;k++) for(b=0;b<274;b++) YWhiteNum[k][b]=0; for(k=-30;k<30;k++) //for(b=-37;b<(200+37);b++) for(i=0;i<srcH;i++) for(j=0;j<srcW;j++) { //if(filBuf[i * lineSize + j * bitCount / 8]==255 && (int)(i*tan(RADIAN(k))+b)==j) b=j-(int)(i*tan(RADIAN(k))); if(filBuf[i * lineSize + j * bitCount / 8]==255 &&(b>=-37&&b<237)) YWhiteNum[k+30][b+37]++; } /* for(k=0;k<60;k++) { cout<<"k="<<k-30<<endl; for(b=0;b<274;b++) cout<<YWhiteNum[k][b]<<","; cout<<"..."<<endl<<endl<<endl; } */ int YProjNum[60]; for(k=0;k<60;k++) YProjNum[k]=0; for(k=0;k<60;k++) { for(b=0;b<274;b++) if(YWhiteNum[k][b]!=0) YProjNum[k]++; // cout<<"角度="<<90-(k-30)<<","<<"YProjNum="<<YProjNum[k]<<" "; } int Ymink; m=YProjNum[0]; Ymink=0; for(k=0;k<60;k++) if(YProjNum[k]<m) { m=YProjNum[k]; Ymink=k; } //cout<<"YProjNum最小的角度是"<<90-(Ymink-30)<<endl; // for(b=0;b<274;b++) // cout<<YWhiteNum[Ymink][b]<<","; // cout<<"..."<<endl<<endl<<endl; int Yb1,Yb2; for(b=0;b<296;b++) { if((YWhiteNum[Ymink][b-1]+YWhiteNum[Ymink][b]+YWhiteNum[Ymink][b+1])<10&& (YWhiteNum[Ymink][b]+YWhiteNum[Ymink][b+1]+YWhiteNum[Ymink][b+2])>=10) { Yb1=b; break; } } for(b=295;b>=0;b--) { if((YWhiteNum[Ymink][b-2]+YWhiteNum[Ymink][b-1]+YWhiteNum[Ymink][b])>10&& (YWhiteNum[Ymink][b-1]+YWhiteNum[Ymink][b]+YWhiteNum[Ymink][b+1])<=10) { Yb2=b; break; } } //画线 for(i=0;i<srcH;i++) for(j=0;j<srcW;j++) if((int)(i/tan(RADIAN(90-(Ymink-30)))+Yb1-37)==j||(int)(i/tan(RADIAN(90-(Ymink-30)))+Yb2-37)==j) { segBuf[i * lineSize + j * bitCount / 8]=0; segBuf[i * lineSize + j * bitCount / 8+1]=0; segBuf[i * lineSize + j * bitCount / 8+2]=255; } //Yb[9]是用来存放除最左和最右的两根上下方向的分割线之外的 中间的分割线 的 x轴截距,正确的是5根,这里允许判断过多,设9根的空间 int Yb[9]; for(i=0;i<9;i++) Yb[i]=0; //找中间一段过白点数为0的直线的截距,上限为r2,下限为r1,二者中间记为Yb[k] int r1=Yb1; int r2=Yb1; for(k=0;k<9&&i<Yb2-1;) { for(i=Yb1;i<Yb2;i++) { if(YWhiteNum[Ymink][i-1]!=0&&YWhiteNum[Ymink][i]==0) { r1=i; } if(YWhiteNum[Ymink][i]==0&&YWhiteNum[Ymink][i+1]!=0) { r2=i; } if(r2>r1) Yb[k]=(r1+r2)/2; if(i==r2+1) k++; } } //调整一下Yb[k]的结构,方便下面的计算, //因为Yb[k]中的0是随机出现的,也会有重复出现的值,或与Yb1,Yb2相等的值,将它们清0,并将0移到最后 for(i=1;i<9;i++) { if(Yb[i]==Yb[i-1])Yb[i]=0; } for(i=0;i<9;i++) { if(Yb[i]==Yb1)Yb[i]=0; } for(i=0;i<9;i++) { if(Yb[i]==Yb2)Yb[i]=0; } int temp[9]; for(i=0;i<9;i++) temp[i]=0; for(i=0,j=0;i<9;i++) { if(Yb[i]!=0) { temp[j]=Yb[i]; j++; } } for(i=0;i<9;i++) Yb[i]=temp[i]; //中间的线的数量,正确的话应为5根 int LineNum=0; for(i=0;i<9;i++) { //if(Yb[i]!=0&&Yb[i]!=Yb[i+1]&&Yb[i]!=Yb1&&Yb[i]!=Yb2) if(Yb[i]!=0) LineNum++; } //如果中间的线数量大于5根,选择其中于其它相邻线距离之和最近的删除 int DisSum[9]; int SumMax=0; for(i=0;i<9;i++) DisSum[i]=0; int iMin=-1; if(LineNum>5) { DisSum[0]=(Yb[0]-Yb1)+(Yb[1]-Yb[0]); DisSum[LineNum-1]=(Yb2-Yb[LineNum-1])+(Yb[LineNum-1]-Yb[LineNum-2]); for(i=1;i<LineNum-1;i++) DisSum[i]=(Yb[i]-Yb[i-1])+(Yb[i+1]-Yb[i]); int SumMin=DisSum[0]; for(i=0;i<9;i++) { if(DisSum[i]<SumMin&&DisSum[i]!=0) { SumMin=DisSum[i]; iMin=i; } } } ////////////////////////////////////////////////////////////////////////// int MaxD=0; int D=0; int d=0; //为补偿线截距分配空间 int Yb_remedy[3]; for(i=0;i<3;i++) Yb_remedy[i]=0; //如果中间的线小于5根,平均分割最大的块 if(LineNum<5) { for(i=0;i<LineNum;i++) { D=Yb[i+1]-Yb[i]; if(D>MaxD) { MaxD=D; k=i; } } //中间的线与最右边的线Yb2比较 if(Yb2-Yb[LineNum-1]>MaxD) { MaxD=Yb2-Yb[LineNum-1]; k=LineNum-1; } d=MaxD/(5-LineNum+1); for(i=0;i<5-LineNum;i++) Yb_remedy[i]=Yb[k]+(i+1)*d; } //画中间的线 for(i=0;i<srcH;i++) for(j=0;j<srcW;j++) for(k=0;k<9;k++) { //删除上面选出的多余的线 if(k==iMin)continue; if((int)(i/tan(RADIAN(90-(Ymink-30)))+Yb[k]-37)==j) { segBuf[i * lineSize + j * bitCount / 8]=0; segBuf[i * lineSize + j * bitCount / 8+1]=0; segBuf[i * lineSize + j * bitCount / 8+2]=255; } } //画补偿线 for(i=0;i<srcH;i++) for(j=0;j<srcW;j++) for(k=0;k<3;k++) { if((int)(i/tan(RADIAN(90-(Ymink-30)))+Yb_remedy[k]-37)==j) { segBuf[i * lineSize + j * bitCount / 8]=0; segBuf[i * lineSize + j * bitCount / 8+1]=0; segBuf[i * lineSize + j * bitCount / 8+2]=255; } } BYTE * desBuf = new BYTE[imgBufSize]; memcpy(&desBuf[0],&segBuf[0],imgBufSize); HFILE hfile = _lcreat(desFile.c_str(),0); //文件头信息 BITMAPFILEHEADER nbmfHeader; nbmfHeader.bfType = 0x4D42; nbmfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + desWidth * desHeight * bitCount / 8; nbmfHeader.bfReserved1 = 0; nbmfHeader.bfReserved2 = 0; nbmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); //Bitmap头信息 BITMAPINFOHEADER bmi; bmi.biSize=sizeof(BITMAPINFOHEADER); bmi.biWidth=desWidth; bmi.biHeight=desHeight; bmi.biPlanes=1; bmi.biBitCount=bitCount; bmi.biCompression=BI_RGB; bmi.biSizeImage=0; bmi.biXPelsPerMeter=0; bmi.biYPelsPerMeter=0; bmi.biClrUsed=0; bmi.biClrImportant=0; //写入文件头信息 _lwrite(hfile,(LPCSTR)&nbmfHeader,sizeof(BITMAPFILEHEADER)); //写入Bitmap头信息 _lwrite(hfile,(LPCSTR)&bmi,sizeof(BITMAPINFOHEADER)); //*********************************************************************************** // printf("sizeof(strPla)=%d\n",sizeof(strPla)); if(RGBQuadNum>0) _lwrite(hfile,(LPCSTR)strPla,sizeof(RGBQUAD)*RGBQuadNum); //************************************************************************************** //写入图像数据 _lwrite(hfile,(LPCSTR)desBuf,desBufSize); _lclose(hfile); } int main(int argc, char* argv[]) { FILE *pFile; string srcFile; string desFile; string srcDir="F:\\图像处理大作业\\OCR\\image\\"; string desDir="F:\\图像处理大作业\\OCR\\整合切分每个字符test\\result\\"; char * to_search="F:\\图像处理大作业\\OCR\\image\\*.bmp"; //欲查找的文件,支持通配符 long handle; //用于查找的句柄 struct _finddata_t fileinfo; //文件信息的结构体 handle=_findfirst(to_search,&fileinfo); //第一次查找 if(-1==handle) printf("打开文件出错\n"); srcFile=srcDir+fileinfo.name ; desFile=desDir+fileinfo.name ; cout<<"正在处理"<<fileinfo.name<<"..."<<endl; KB(srcFile ,desFile ); while(!_findnext(handle,&fileinfo)) //循环查找其他符合的文件,知道找不到其他的为止 { srcFile=srcDir+fileinfo.name ; desFile=desDir+fileinfo.name ; cout<<"正在处理"<<fileinfo.name<<"..."<<endl; KB(srcFile ,desFile ); //system("pause"); } _findclose(handle); //别忘了关闭句柄 printf("定位完成\n\n"); system("pause"); return 0; }
以前写的一个验证码识别的程序,这个程序大致实现了切分的功能
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- java自动生成验证码插件-kaptcha
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- 如何识别高级的验证码的技术总结第1/4页
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例