Huffman编码及解码.docx
《Huffman编码及解码.docx》由会员分享,可在线阅读,更多相关《Huffman编码及解码.docx(20页珍藏版)》请在冰豆网上搜索。
Huffman编码及解码
Huffman编码图像解码
*********************/
//读入编码图像
boolreadHuffman(char*Name)
{
inti,j;
charNameStr[100];
//读取Huffman编码信息和编码树
strcpy(NameStr,Name);
strcat(NameStr,".bpt");
FILE*fin=fopen(NameStr,"r");
if(fin==0){
printf("未找到指定文件!
\n");
return0;
}
fscanf(fin,"%d%d%d",&NodeStart,&NodeNum,&InfLen);
//printf("%d%d%d\n",NodeStart,NodeNum,InfLen);
for(i=0;ifscanf(fin,"%d%d%d",&node[i].color,&node[i].lson,&node[i].rson);
//printf("%d%d%d\n",node[i].color,node[i].lson,node[i].rson);
}
//二进制读方式打开指定的图像文件
strcpy(NameStr,Name);
strcat(NameStr,".bhd");
FILE*fp=fopen(NameStr,"rb");
if(fp==0){
printf("未找到指定文件!
\n");
return0;
}
//跳过位图文件头结构BITMAPFILEHEADER
fseek(fp,sizeof(BITMAPFILEHEADER),0);
//定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中
BITMAPINFOHEADERhead;
fread(&head,sizeof(BITMAPINFOHEADER),1,fp);
//获取图像宽、高、每像素所占位数等信息
bmpWidth=head.biWidth;
bmpHeight=head.biHeight;
biBitCount=head.biBitCount;
//定义变量,计算图像每行像素所占的字节数(必须是4的倍数)
intlineByte=(bmpWidth*biBitCount/8+3)/4*4;
//灰度图像有颜色表,且颜色表表项为256
if(biBitCount==8){
//申请颜色表所需要的空间,读颜色表进内存
pColorTable=newRGBQUAD[256];
fread(pColorTable,sizeof(RGBQUAD),256,fp);
}
//申请位图数据所需要的空间,读位图数据进内存
pBmpBuf=newunsignedchar[lineByte*bmpHeight];
fread(pBmpBuf,1,InfLen/8,fp);
//关闭文件
fclose(fp);
return1;
}
voidHuffmanDecode()
{
//获取编码信息
inti,j,tmp;
intlineByte=(bmpWidth*biBitCount/8+3)/4*4;
for(i=0;i{
j=i*8+7;
tmp=*(pBmpBuf+i);
while(tmp>0)
{
ImgInf[j]=tmp%2;
tmp/=2;
j--;
}
}
/*for(i=0;iprintf("%d",ImgInf[i]);
printf("\n");*/
//解码
intp=NodeStart;//遍历指针位置
j=0;
i=0;
do
{
if(node[p].color>=0)
{
*(pBmpBuf+j)=node[p].color;
//printf("%d",*(pBmpBuf+j));
j++;
p=NodeStart;
}
if(ImgInf[i]==1)
p=node[p].lson;
elseif(ImgInf[i]==0)
p=node[p].rson;
i++;
}while(i<=InfLen);
//printf("\nj:
%d\n",j);
}
/*********************
Huffman编码
*********************/
//Huffman编码初始化
voidHuffmanCodeInit()
{
inti;
for(i=0;i<256;i++)//灰度值记录清零
Num[i]=0;
//初始化哈夫曼树
for(i=0;i<600;i++)
{
node[i].color=-1;
node[i].lson=node[i].rson=-1;
node[i].num=-1;
node[i].mark=0;
}
NodeNum=0;
}
//深搜遍历Huffman树获取编码值
charCodeTmp[300];
voiddfs(intpos,intlen)
{
//遍历左儿子
if(node[pos].lson!
=-1)
{
CodeTmp[len]='1';
dfs(node[pos].lson,len+1);
}
else
{
if(node[pos].color!
=-1)
{
CodeLen[node[pos].color]=len;
CodeTmp[len]='\0';
strcpy(CodeStr[node[pos].color],CodeTmp);
}
}
//遍历右儿子
if(node[pos].lson!
=-1)
{
CodeTmp[len]='0';
dfs(node[pos].rson,len+1);
}
else{
if(node[pos].color!
=-1)
{
CodeLen[node[pos].color]=len;
CodeTmp[len]='\0';
strcpy(CodeStr[node[pos].color],CodeTmp);
}
}
}
//寻找值最小的节点
intMinNode()
{
inti,j=-1;
for(i=0;iif(!
node[i].mark)
if(j==-1||node[i].numj=i;
if(j!
=-1)
{
NodeStart=j;
node[j].mark=1;
}
returnj;
}
//编码主函数
voidHuffmanCode()
{
inti,j,k,a,b;
for(i=0;i<256;i++)
{//创建初始节点
Feq[i]=(float)Num[i]/(float)(bmpHeight*bmpWidth);//计算灰度值频率
if(Num[i]>0)
{
node[NodeNum].color=i;
node[NodeNum].num=Num[i];
node[NodeNum].lson=node[NodeNum].rson=-1;//叶子节点无左右儿子
NodeNum++;
}
}
while
(1)
{//找到两个值最小的节点,合并成为新的节点
a=MinNode();
if(a==-1)
break;
b=MinNode();
if(b==-1)
break;
//构建新节点
node[NodeNum].color=-1;
node[NodeNum].num=node[a].num+node[b].num;
node[NodeNum].lson=a;
node[NodeNum].rson=b;
NodeNum++;
//node[a].mark=node[b].mark=1;
}
//根据建好的Huffman树编码(深搜实现)
dfs(NodeStart,0);
//屏幕输出编码
intsum=0;
printf("Huffman编码信息如下:
\n");
for(i=0;i<256;i++)
if(Num[i]>0)
{
sum+=CodeLen[i]*Num[i];
printf("灰度值:
%3d频率:
%f码长:
%2d编码:
%s\n",i,Feq[i],CodeLen[i],CodeStr[i]);
}
//printf("原始总码长:
%d\n",bmpWidth*bmpHeight*8);
//printf("Huffman编码总码长:
%d\n",sum);
//printf("压缩比:
%.3f:
1\n",(float)(bmpWidth*bmpHeight*8)/(float)sum);
//记录图像信息
InfLen=0;
intlineByte=(bmpWidth*biBitCount/8+3)/4*4;
for(i=0;ifor(j=0;j{
lpBuf=(unsignedchar*)pBmpBuf+lineByte*i+j;
for(k=0;k{
ImgInf[InfLen++]=(int)(CodeStr[*(lpBuf)][k]-'0');
}
}
//再编码数据
j=0;
for(i=0;i{
*(pBmpBuf+j)=Change2to10(i);
i+=8;
j++;
}
}
/******************************
主函数
******************************/
intmain(intargc,char**argv)
{
intord;//命令
charc;
inti,j;
clock_tstart,finish;
inttotal_time;
//CStringstr;
while
(1)
{
printf("本程序提供以下功能\n\n\t1.256色灰度BMP图像Huffman编码\n\t2.Huffman编码BMP文件解码\n\t3.退出\n\n请选择需要执行的命令:
");
scanf("%d%c",&ord,&c);
if(ord==1)
{
printf("\n---256色灰度BMP图像Huffman编码---\n");
printf("\n请输入要编码图像名称:
");
scanf("%s",str);
//读入指定BMP文件进内存
charreadPath[100];
strcpy(readPath,str);
strcat(readPath,".bmp");
if(readBmp(readPath))
{
//输出图像的信息
//printf("\n图像信息:
\nwidth=%d,height=%d,biBitCount=%d\n",bmpWidth,bmpHeight,biBitCount);
intlineByte=(bmpWidth*biBitCount/8+3)/4*4;
if(biBitCount==8)
{
//编码初始化
HuffmanCodeInit();
//计算每个灰度值出现的次数
for(i=0;ifor(j=0;j{
lpBuf=(unsignedchar*)pBmpBuf+lineByte*i+j;
Num[*(lpBuf)]+=1;
}
//调用编码
start=clock();
HuffmanCode();
finish=clock();
total_time=(finish-start);
printf("识别一张耗时:
%d毫秒",total_time);
//将图像数据存盘
charwritePath[100];
//保存编码后的bmp
strcpy(writePath,str);
strcat(writePath,"_Huffman.bhd");
saveBmp(writePath,pBmpBuf,bmpWidth,bmpHeight,biBitCount,pColorTable);
//保存Huffman编码信息和编码树
strcpy(writePath,str);
strcat(writePath,"_Huffman.bpt");
saveInfo(writePath,lineByte);
printf("\n编码完成!
编码信息保存在%s_Huffman文件中\n\n",str);
}
else
{
printf("本程序只支持256色BMP编码!
\n");
}
//清除缓冲区,pBmpBuf和pColorTable是全局变量,在文件读入时申请的空间
delete[]pBmpBuf;
if(biBitCount==8)
delete[]pColorTable;
}
printf("\n-----------------------------------------------\n\n\n");
}
elseif(ord==2)
{
printf("\n---Huffman编码BMP文件解码---\n");
printf("\n请输入要解码文件名称:
");
scanf("%s",str);
//编码解码初始化
HuffmanCodeInit();
if(readHuffman(str))
{//读取文件
HuffmanDecode();//Huffman解码
//将图像数据存盘
charwritePath[100];
//保存解码后的bmp
strcpy(writePath,str);
strcat(writePath,"_Decode.bmp");
InfLen=bmpWidth*bmpHeight*8;
saveBmp(writePath,pBmpBuf,bmpWidth,bmpHeight,biBitCount,pColorTable);
system(writePath);
printf("\n解码完成!
保存为%s_Decode.bmp\n\n",str);
}
printf("\n-----------------------------------------------\n\n\n");
}
elseif(ord==3)
break;
}
return0;/*ANSICrequiresmaintoreturnint.*/
}
/*********************
编码:
#include
#include
#include
#include"Windows.h"
#include"math.h"
#include
//几个全局变量,存放读入图像的位图数据、宽、高、颜色表及每像素所占位数(比特)
//此处定义全局变量主要为了后面的图像数据访问及图像存储作准备
unsignedchar*pBmpBuf;//读入图像数据的指针
intbmpWidth;//图像的宽
intbmpHeight;//图像的高
intimgSpace;//图像所需空间
RGBQUAD*pColorTable;//颜色表指针
intbiBitCount;//图像类型
charstr[100];//文件名称
intNum[300];//各灰度值出现的次数
floatFeq[300];//各灰度值出现的频率
unsignedchar*lpBuf;//指向图像像素的指针
unsignedchar*m_pDib;//存放打开文件的DIB
intNodeNum;//Huffman树总节点个数
intNodeStart;//Huffman树起始节点
structNode{//Huffman树节点
intcolor;//记录叶子节点的灰度值(非叶子节点为-1)
intlson,rson;//节点的左右儿子(若没有则为-1)
intnum;//节点的数值(编码依据)
intmark;//记录节点是否被用过(用过为1,没用过为0)
}node[600];
charCodeStr[300][300];//记录编码值
intCodeLen[300];//编码长度
boolImgInf[8000000];//图像信息
intInfLen;//图像信息长度
/***********************************************************************
*函数名称:
*readBmp()
*
*函数参数:
*char*bmpName-文件名字及路径
*
*返回值:
*0为失败,1为成功
*
*说明:
给定一个图像文件名及其路径,读图像的位图数据、宽、高、颜色表及每像素
*位数等数据进内存,存放在相应的全局变量中
***********************************************************************/
boolreadBmp(char*bmpName)
{
//二进制读方式打开指定的图像文件
//FILE*fp=fopen("E:
\ProgramFiles\program\Huffman\1.bmp","rb");
FILE*fp=fopen(bmpName,"rb");
if(fp==0)
{
printf("未找到指定文件!
\n");
return0;
}
//跳过位图文件头结构BITMAPFILEHEADER
fseek(fp,sizeof(BITMAPFILEHEADER),0);
//定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中
BITMAPINFOHEADERhead;
fread(&head,sizeof(BITMAPINFOHEADER),1,fp);
//获取图像宽、高、每像素所占位数等信息
bmpWidth=head.biWidth;
bmpHeight=head.biHeight;
biBitCount=head.biBitCount;
//定义变量,计算图像每行像素所占的字节数(必须是4的倍数)
intlineByte=(bmpWidth*biBitCount/8+3)/4*4;
//灰度图像有颜色表,且颜色表表项为256
if(biBitCount==8)
{
//申请颜色表所需要的空间,读颜色表进内存
pColorTable=newRGBQUAD[256];
fread(pColorTable,sizeof(RGBQUAD),256,fp);
}
//申请位图数据所需要的空间,读位图数据进内存
pBmpBuf=newunsignedchar[lineByte*bmpHeight];
fread(pBmpBuf,1,lineByte*bmpHeight,fp);
//关闭文件
fclose(fp);
return1;
}
/***********************************************************************
保存信息
***********************************************************************/
//二进制转十进制
intChange2to10(intpos){
inti,j,two=1;
j=0;
for(i=pos+7;i>=pos;i--){
j+=two*ImgInf[i];
two*=2;
}
returnj;
}
//保存Huffman编码树
intsaveInfo(char*writeP