文章标题

来源:互联网 发布:2016光棍节淘宝交易额 编辑:程序博客网 时间:2024/06/10 20:25

LBG矢量量化算法

LBG算法是由Linde,Buzo,Gray三人在1980年提出的。它其实相当于Lord-Max方法的多维推广,但它并不需要知道输入矢量的概率分布,LBG算法通过训练矢量集和一定的迭代算法来逼近最优的再生码本。是最著名的矢量量化编码。

LBG算法实现步骤

1.随意选取n个图像块作为码矢量
2.由这n个码矢量对所有的图像块进行划分,即分成n个集合,使每个集合中的图像块,都是与各码矢量距离中,与对应的码矢量的距离最小的
3.由这n个集合的重心,得到n个新的码矢量
4.如果这些个码矢量与原来的码矢量变化不大(收敛),就完成码书的训练,否则重新进行2、3步

LBG算法的局限性

1.最优量化器是对于训练向量集而言,对于实际的未经训练的向量集是否最优还很难说,这要依赖于训练向量的代表性到底真实到何种程度。
2.由于优化分割的过程没有依据数据结构方面的规则或者限制,而是自由进行,这就使得对码本进行有效组织时遇到极大的困难。
3.在有些时候根本无法找到真正有代表性的训练向量集。

C源代码

#include <iostream>#include <stdlib.h>#include "Bitmap.h"using namespace std;int main(int argc, char *argv[]){cout<<512/4<<endl;cout<<517-517%4<<endl;srand((unsigned)time(NULL));//为了得到随机数CBitmap bitmap;int nFlag=0;char szInfile[100];//文件名string strChoice;cout<<"输入所要处理的文件名>";cin.getline(szInfile,100);nFlag=bitmap.Init(szInfile);//nFlag等于0才是满足条件的文件//必须是BMP文件//必须是256色的8位位图if(nFlag==0){bitmap.LBG();}return 0;}//在1~s内生成一个随机数int get_rand(int s){int i;i=rand()%s+1;return i;}#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 memoryexit(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 memoryexit(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 memoryexit(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++){//intint f1=floor((double)i/wordSize);int m1=i%wordSize;if(m1==0){m1=wordSize;f1--;}//intint 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)//求最小的值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个码字距离最小,将这个码字的索引计数加1d1+=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 codebkofstream codeBookfile("LBGcodeBook.txt",ios::out);//|ios::binary);if(!codeBookfile){cout<<"处理失败!\n";return;}for(i=1;i<=bookSize;i++)//save codebkcodeBookfile.write((char *)&codebk[i][1],ss);codeBookfile.close();///////////////////save codebkdouble d1=0.0;// char codeNumber[512*512/16+1];//intunsigned char * codeNumber;//intif((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;}/////////////////////////////////存储codeNumberofstream codeNOFile("LBGcodeNumber.txt",ios::out);//|ios::binary);if(!codeNOFile){cout<<"处理失败!\n";return;}for(i=1;i<nn+1;i++)//save codeNumbercodeNOFile.write((char *)&codeNumber[i],sizeof(char));//intcodeNOFile.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赋值回datafor(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_sigoutfile.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";}
原创粉丝点击