验证码切分程序

// 整合切分每个字符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;


}  

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值