📄 bitmap.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 + -