⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bitmap.cpp

📁 lbg算法代码
💻 CPP
字号:
#include "Bitmap.h"

int CBitmap::Init(char *szInfile)
{
    int nFlag=0; 
    
	infile.open(szInfile,ios::in|ios::binary);
	//不能打开文件 
	if(!infile)
	{
		cout<<"不能成功打开文件"<<szInfile<<endl;
		nFlag=1;
		return nFlag;
	}
	
	infile.read((char *)&strHead,sizeof(strHead));
	//文件不是位图文件 
	if(strHead.bfType!=0x4d42)
	{
		cout<<"该图不是位图\n";
		nFlag=1;
		return nFlag;
	}
	//文件是位图文件,显示相关信息 
	else 
	{
		int filesize; 
		int* p = (int*)strHead.bfSize;  
		filesize=*p;
		cout<<"文件大小:"<<'\t'<<filesize<<'\n'
			<<"点阵偏移量:"<<'\t'<<strHead.bfOffBits<<endl;
		
		cout<<"\n矩阵大小:"<<filesize-sizeof(RGBQUAD)-sizeof(strHead)-sizeof(strInfo)<<endl;
	}

	infile.read((char *)&strInfo,sizeof(strInfo));
	//使用的不是256色的位图 
	if(strInfo.biBitCount!=8)
	{
		cout<<"使用的颜色数:"<<strInfo.biClrUsed<<"像素点阵大小:"<<strInfo.biSizeImage
			<<"像素位深:"<<strInfo.biBitCount<<endl;
		cout<<"非256色\n";
		nFlag=1;
		return nFlag;
	}
	
	cout<<endl;
	cout<<"使用的颜色数:"<<'\t'<<strInfo.biClrUsed<<'\n'
		<<"像素点阵大小:"<<'\t'<<strInfo.biSizeImage<<'\n'
		<<"像素位深:"<<'\t'<<strInfo.biBitCount<<'\n'
	    <<"图像大小\n宽"<<'\t'<<strInfo.biWidth<<'\n'
		<<"高"<<'\t'<<strInfo.biHeight<<endl;

    //读入调色板信息 
	for(int i=0;i<256;i++)
		infile.read((char *)&straPla[i],sizeof(RGBQUAD));
	//infile.close();
	return nFlag;
}

//LBG算法函数 
void CBitmap::LBG()
{
	int i;
	unsigned char  **data;                  //输入文件要存放的二维数组 
	unsigned char  **codebk;                //码书
	int  m_sig=strInfo.biHeight;            //图像高度 
	int  n_sig=strInfo.biWidth;             //图像宽度 
	int  wordSize = 4;                      //码字的长度 
	int  bookSize = 64;                     //码书长度
	
	cout<<"Word Size:\t";                   //请求用户输入码字长度 
	cin>>wordSize;
	cout<<"Book Size:\t";                   //请求用户输入码书长度 
	cin>>bookSize;
	
	int  hnum = m_sig/wordSize;
	int  wnum = n_sig/wordSize;
	int  ss = wordSize*wordSize;            //码字,是一个小矩形 
	int  nn = hnum*wnum;                    //整个图象被分成的子图个数 
	unsigned char **re_sig;                 //存放中间过程的图像 
	
    //unsigned char re_re_sig[512+1][512+1];// 使用data替换
	cout<<"\n正在 LBG ... ... \n请稍等... ...\n";
	
	//原始位图输入分配空间,每一行 
	if((data = (unsigned char **) malloc((m_sig+1) * sizeof(unsigned char*)))==NULL)
	{
          fprintf(stderr,"内存不足!\n");//no more memory
          exit(1);
    }
    
    //每一列
	for(i=0;i<=m_sig;i++)
		if((data[i] = (unsigned char *) malloc((n_sig+1) * sizeof(unsigned char)))==NULL)// 维数
		{
            fprintf(stderr,"内存不足!\n");
            exit(1);
        }

	//分配码书空间,码书是一个二维数组 
	if((codebk = (unsigned char **) malloc((bookSize+1) * sizeof(unsigned char*)))==NULL)
	{
          fprintf(stderr,"内存不足!\n");//no more memory
          exit(1);
    }

    //为码书中的每一个码字分配空间
	for(i=0;i<=bookSize;i++)
		if((codebk[i] = (unsigned char *) malloc((ss+1) * sizeof(unsigned char)))==NULL)// 维数
		{
            fprintf(stderr,"内存不足!\n");
            exit(1);
        }
	
    //中间处理过程的存储 
	if((re_sig = (unsigned char **) malloc((nn+1) * sizeof(unsigned char*)))==NULL)
	{
          fprintf(stderr,"内存不足!\n");//no more memory
          exit(1);
    }

    //每个子图中,为每一个码字分配空间
	for(i=0;i<=nn;i++)
		if((re_sig[i] = (unsigned char *) malloc((ss+1) * sizeof(unsigned char)))==NULL)// 维数
		{
            fprintf(stderr,"内存不足!\n");
            exit(1);
        }
		
	infile.seekg(strHead.bfOffBits,ios::beg);//读入,从点阵偏移量以后开始

	//一行一行读取,每读取一行存放到一个data[i][]数组里
	for(i=1;i<=m_sig;i++)
	    infile.read((char *)&data[i][1],n_sig*sizeof(char));
	infile.close();			

	//切割图片
	//将原图像的每一行按码字的长度分割,然后存到re_sig的前四列
	//以此类推,第二行是接下来的四列
	for(i=1;i<=m_sig;i++)
		for(int j=1;j<=n_sig;j++)
		{
			//int 
            int f1=floor((double)i/wordSize);
			int m1=i%wordSize;
			if(m1==0)
			{
				m1=wordSize;
				f1--;
			}
			//int 
            int f2=floor((double)j/wordSize);
			int m2=j%wordSize;
			if(m2==0)
			{
				m2=wordSize;
				f2--;
			}
			re_sig[hnum*f1+f2+1][wordSize*(m1-1)+m2]=data[i][j];
		}

	////////////////////////以下开始求取码书
    ////////////////////////使用随机编码法求取初始码书,计算量低
     
	//给码书赋值,
	for(i=1;i<=bookSize;i++)
		for(int j=1;j<=ss;j++)
		{
			int r=get_rand(nn);
			codebk[i][j]=re_sig[r][j];  //每次从所有的子图中随机取一个值 
		}

	/**
	*LBG训练法
	*d0 d1 用于存放各训练矢量与其码书中最相近的码字的距离平方之和
	*sea 用于存放迭代精度
	**/
	double d0=0.0;//每个输入向量与codebk[1]的距离
	for(i=1;i<=nn;i++)
		for(int ti=1;ti<=ss;ti++)
			d0=d0+pow((double)((int)re_sig[i][ti]-(int)codebk[1][ti]),2);
	while(1)
	{
        //int vectorNumber[64+1];
        
        //vectorNumber存储的是码书中的某一个码字的计数
        //表示这个向量和训练向量距离最近的次数 
		int *vectorNumber;
        //分配空间 
		if((vectorNumber = (int *) malloc((bookSize+1) * sizeof(int)))==NULL)
		{
		    fprintf(stderr,"内存不足!\n");
            exit(1);			
		}
        //int codeNumber[512*512/16+1];
        
        //某一个向量会和某一个码字距离最近,codeNumber存储 
        //的是这个码字的索引,每一个训练向量都有一个对应的
        //码字索引 
		int *codeNumber;
		//分配空间 
		if((codeNumber = (int *) malloc((nn+1) * sizeof(int)))==NULL)
		{
		    fprintf(stderr,"内存不足!\n");
            exit(1);			
		}
		
		//d1存储的是第i个训练向量和码字的最短距离 
		double d1 = 0.0;
		for(i=1;i<=bookSize;i++)
			vectorNumber[i]=0;//初始化为零

		//对于所有的输入向量
		for(i=1;i<=nn;i++)
		{
			codeNumber[i]=1;
			double min =0.0;			
			for(int ti=1;ti<=ss;ti++)
				min=min+pow((double)((int)re_sig[i][ti]-(int)codebk[1][ti]),2);    //第i个训练向量对codebk[1]的距离
//			if(min<0)
//				system("pause");

			//求最小的值
			for(int j=1;j<=bookSize;j++)
			{
				double d=0.0;
				for(int pp=1;pp<=ss;pp++)
				{					
					d = d+pow((double)((int)re_sig[i][pp]-(int)codebk[j][pp]),2);
					if (d>=min)
						break;
				}
				
				//第i个训练向量对第j个码字的距离小于对第1个码字的距离
				//更新最小距离和第i个码字序号
				if(d<min)
				{	
					min=d;
					codeNumber[i]=j;    //将第i个训练向量的Number记为和它距离最小的码字的序号
				}
			}

			//经过上面的for循环,就能够得到第i个训练向量对于第j个码字的距离最小
			//与 i距离最小的索引
			int temp=codeNumber[i];
			vectorNumber[temp]=vectorNumber[temp]+1;   //对第j个码字距离最小,将这个码字的索引计数加1
			d1+=min;//d1存放最小的距离
		}

		//求迭代精度
		double sea=(d0-d1)/d1;
		//如果达到了指定的精度,跳出while循环
		if(sea<=0.0001)
			break;

        //如果没有达到指定的精度,还要继续迭代 
		d0=d1;
		for(int j=1;j<=bookSize;j++)
		{
			//某一个码字的标记不是0,就是上面求得的最小距离的码字
			if(vectorNumber[j]!=0)
			{
//				int dd[16+1];//dd[ss]
				int *dd;
				if((dd = (int *) malloc((ss+1) * sizeof(int)))==NULL)
				{
					fprintf(stderr,"内存不足!\n");
					exit(1);
				}
				for(int l=1;l<=nn;l++)
				{	
					if(codeNumber[l]==j)//某一个训练向量对j距离最小,可能不只一个
					{	
					    //将这一个训练向量提出来,加到dd上
					    //最后所有满足对j距离最小的向量都
                        //被加到了码字j上    
						for(int k=1;k<=ss;k++)
							dd[k]=dd[k]+re_sig[l][k];
					}
				}

				//更新码书
				for(int k=1;k<=ss;k++)
					codebk[j][k]=dd[k]/vectorNumber[j];
			}

			//如果是0,表示这个码字没有和任何一个向量之间距离最小,继续随机抽取
			else
			{	
				int l=floor((double)get_rand(nn));
				for(int tt=1;tt<=ss;tt++)
					codebk[j][tt]=re_sig[l][tt];
			}
		}
		free(vectorNumber);
		vectorNumber=NULL;
		free(codeNumber);
		codeNumber=NULL;
	}

	////////////////////////得到码书

	///////////////////save codebk
	ofstream codeBookfile("LBGcodeBook.txt",ios::out);//|ios::binary);
	if(!codeBookfile)
	{
		cout<<"处理失败!\n";
		return;
	}	
	for(i=1;i<=bookSize;i++)//save codebk
		codeBookfile.write((char *)&codebk[i][1],ss);
	codeBookfile.close();

	///////////////////save codebk


	double d1=0.0;
//	char codeNumber[512*512/16+1];//int

	unsigned char * codeNumber;//int
	
	if((codeNumber = (unsigned char *) malloc((nn+1) * sizeof(unsigned char)))==NULL)// 维数
	{
        fprintf(stderr,"内存不足!\n");
        exit(1);
    }
	
	//求取第i个输入向量和第几个码字的距离最近
	//并将这个最近的码字的索引记录在codeNumber数组中
	//这时码书已经得到,此时求得的最近码字
    //就是最后要代替每一个子图的码字 
	for(i=1;i<=nn;i++)
	{
		codeNumber[i]=1;
		double min=0.0;
		for(int ti=1;ti<=ss;ti++)
			min=min+pow((double)((int)re_sig[i][ti]-(int)codebk[1][ti]),2);   //第i个向量和codebk[1]的距离

		//第i个向量和其余的码字距离比较
		for(int j=2;j<=bookSize;j++)
		{
			double d=0.0;
			for(int l=1;l<=ss;l++)
			{
				d =d+pow((double)((int)re_sig[i][l]-(int)codebk[j][l]),2);
				if (d>=min)
					break;
			}
			if(d<min)
			{
				min=d;
				codeNumber[i]=j;
			}
		}
		d1=d1+min;
	}

	/////////////////////////////////存储codeNumber
	ofstream codeNOFile("LBGcodeNumber.txt",ios::out);//|ios::binary);
	if(!codeNOFile)
	{
		cout<<"处理失败!\n";
		return;
	}	
	for(i=1;i<nn+1;i++)//save codeNumber
		codeNOFile.write((char *)&codeNumber[i],sizeof(char));//int
	codeNOFile.close();
	/////////////////////////////////存储codeNumber
	
	/////////////////////////////////重建图像
	for(i=1;i<=nn;i++)
		for(int j=1;j<=ss;j++)
		{
			int temp=codeNumber[i];
			re_sig[i][j]=codebk[temp][j];        //按距离最接近的标准将码字赋值给re_sig
		}
	

	for(i=0;i<=bookSize;i++)//训练向量数目
		free(codebk[i]);// 维数
	free(codebk);
	codebk=NULL;
	
	free(codeNumber);
	codeNumber=NULL;

	ofstream outfile("LBG.bmp",ios::out|ios::binary);
	if(!outfile)
	{
		cout<<"处理失败!\n";
		return;
	}

	//将位图文件头复制到新建文件
	outfile.write((char *)&strHead,sizeof(strHead));
	outfile.write((char *)&strInfo,sizeof(strInfo));

	//将调色板复制到新建文件
	for(i=0;i<256;i++)
		outfile.write((char *)&straPla[i],sizeof(RGBQUAD));
	
	//重建图像的关键部分,将修改后的re_sig赋值回data
	for(int ni=1;ni<=nn;ni++)
		for(int nj=1;nj<=ss;nj++)
		{
			int f1=floor((double)ni/hnum);
			int f2=ni%hnum;
			if (f2==0)
			{
				f2=hnum;
				f1--;
			}
			int m1=floor((double)nj/wordSize)+1;
			int m2=nj%wordSize;
			if(m2==0)
			{
				m2=wordSize;
				m1--;
			}
			data[wordSize*f1+m1][wordSize*(f2-1)+m2]=re_sig[ni][nj];
		}
		for(i=1;i<=m_sig;i++)//save re_re_sig
				outfile.write((char *)data[i]+1,n_sig*sizeof(char));

	/////////////////////////////////重建图像			

	for(i=0;i<=m_sig;i++)//训练向量数目
		free(data[i]);
	free(data);
	for(i=0;i<=nn;i++)//训练向量数目
		free(re_sig[i]);
	free(re_sig);

	cout<<"\nLBG 结束!\n";	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -