您的位置:首页 > 编程语言 > C语言/C++

验证码切分程序

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;

}


以前写的一个验证码识别的程序,这个程序大致实现了切分的功能



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息