图像编码霍夫曼编码.docx
《图像编码霍夫曼编码.docx》由会员分享,可在线阅读,更多相关《图像编码霍夫曼编码.docx(11页珍藏版)》请在冰豆网上搜索。
图像编码霍夫曼编码
编号:
题目名称图像编码——霍夫曼编码
学生姓名学号
学院信息科学与工程学院
专业年级2009级通信一班
指导教师职称教师
填写时间2012年10月27日
摘 要
进入21世纪,人类已步入信息社会,新信息技术革命使人类被日益增多的多媒体信息所包围,这也正好迎合了人类对要示提高视觉信息的需求。
多媒体信息主要有三种形式:
文本、声音和图像。
从信息传输的开展史〔电报、、、收音机、电视机直至现在的网络〕可以看出,人们逐渐将信息传输的重点从声音转向图像,然而图像是三种信息形式中数据量最大的,这给图像的传输和存储带来了极大的困难。
对于巨大的数字图像数据量,如果不经过压缩,不仅超出了计算机的存储和处理能力,而且在现有的通信信道的传输速率下,是无法完成大量多媒体信息实时传输的,数字图像高速传输和存贮所需要的巨大容量已成为推广数字图像通信和最大障碍。
因此,为了存储、处理和传输这些数据,必须进展压缩。
图像压缩之所以能够进展压缩是因为原始图像数据是高度相关的,存在很大的数据冗余。
数字图像包含的冗余信息一般有以下几种:
空间冗余、时间冗余、信息熵冗余、统计冗余、结构冗余、视觉冗余以与知识冗余等。
图像压缩算法就是要在保证图像一定的重建质量的同时,尽可能多的去除这些冗余信息,以达到对图像压缩的目的。
关键词:
图像处理,图像压缩,压缩算法,图像编码,霍夫曼编码
对数字图像进展压缩通常利用两个根本原理:
一是数字图像的相关性。
在图像的同一行相邻象素之间,相邻象素之间,活动图像的相邻帧的对应象素之间往往存在很强的相关性,去除或减少这些相关性,也即去除或减少图像信息中的冗余度也就实现了对数字图像的压缩。
帧内象素的相关称做空域相关性。
相邻帧间对应象素之间的相关性称做时域相关性。
二是人的视觉心理特征。
人的视觉对于边缘急剧变化不敏感(视觉掩盖效应),对颜色分辨力弱,利用这些特征可以在相应局部适当降低编码精度而使人从视觉上并不感觉到图像质量的下降,从而达到对数字图像压缩的目的。
图像数据压缩的目的是在满足一定图像质量的条件下,用尽可能少的比特数来表示原始图像,以提高图像传输的效率和减少图像存储的容量,在信息论中称为信源编码。
图像压缩是通过删除图像数据中冗余的或者不必要的局部来减小图像数据量的技术,压缩过程就是编码过程,解压缩过程就是解码过程。
压缩技术分为无损压缩和有损压缩两大类,前者在解码时可以准确地恢复原图像,没有任何损失;后者在解码时只能近似原图像,不能无失真地恢复原图像。
假设有一个无记忆的信源,它产生的消息为{ai},1≤i≤N,其出现的概率是的,记为P(ai)。
如此其信息量定义为:
由此可见一个消息出现的可能性越小,其信息量就越多,其出现对信息的贡献量越大,反之亦然。
信源的平均信息量称为“熵〞〔entropy〕,可以表示为:
对上式取以2为底的对数时,单位为比特〔bits〕:
根据香农〔Shannon〕无噪声编码定理,对于熵为H的信号源,对其进展无失真编码所可能达到的最低比特数为,这里为一任意小的正数,因此可能达到的
最大压缩比:
其中B是原始图像的平均比特率。
在图像压缩中,压缩比是一个重要的衡量指标。
可以定义压缩比为:
Huffman编码在无损压缩的编码方法中,它是一种有效的编码方法。
它是霍夫曼博士在1952年根据可变长最优编码定理提出的。
依据信源数据中各信号出现的频率分配不同长度的编码。
其根本思想是在编码过程中,对出现频率越高的值,分配越短的编码长度,相应地对出现频率越低的值如此分配较长的编码长度,
它是一种无损编码方法。
采用霍夫曼编码方法的实质是针对统计结果对字符本身重新编码,而不是对重复字符或重复子串编码,得到的单位像素的比特数最接近图像的实际熵值。
例如,在英文中,e的出现概率很高,而z的出现概率如此最低。
当利用哈夫曼编码对一篇英文进展压缩时,e极有可能用一个位(bit)来表示,而z如此可能花去25个位〔不是26〕。
用普通的表示方法时,每个英文字母均占用一个字节〔byte〕,即8个位。
二者相比,e使用了一般编码的1/8的长度,z如此使用了3倍多。
倘假如我们能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。
例如:
假设信源符号为【a、b、c、d、e、f、g】,其出现的概率相应的为【0.25、0.025、0.025、0.05、0.35、0.25、0.05】,一共7个字符,对其进展huffman编码,算法如下:
首先按照每个字符出现的频率大小从左到右排列:
0.35、0.25、0.25、0.05、0.05、0.025、0.025;选出最小的两个值作为叶子节点构成一棵二叉树,值较大的叶子节点在左,两个叶子节点对应的频率之和作为根节点。
把原排列中最小的两个节点删除,新的根节点插入排列保持大小从左到右的排列顺序不变;重复执行2〕,直到最后得到值为1的根节点。
得到一棵huffman树,如如下图所示:
在得到的huffman树上左分支标记1,右分支标记0,所有的字符根据其频率标记到对应的叶子节点上,从根节点到叶子节点路径上遇到的0、1字符串即为对应叶子节点所在字符的编码。
a、b、c、d、e、f、g七个字符的huffman编码分别是:
10、0001、0000、0011、11、01、0010,可以看到,符号只能出现在树叶上,任何一个字符的路径都不会是另一字符路径的前缀路径。
设计目标是实现Huffman压缩的编码器。
编码器的工作过程呢个如下;首先读入待压缩的源文件,为保证与源文件信息完全一致,对文件的读写操作都用二进制文件的方式进展。
与这只偶那个方式对应的是ASCII方式读写。
然后建立并分析字母表,对读入内存的源文件我们以字节为单元进展分析,将类型表示,其用C++内建的CHAR,最多将有256中可能的字符。
我们对每种字符的出现频度进展统计,以频度作为建立Huffman树的权值。
频度表建好之后,就可以根据前述算法建立Huffman树,对出现的每种字符进展Huffman编码。
此入时,再次读入源文件,逐字节编码,将得到的编码流写入到磁盘文件。
编码的核心是Huffman树,它也是连接编码的纽带。
考虑到Huffman树节点的设计。
编码时从叶节点逐步构建中间节点,到整颗树。
树的节点应该应该包括的信息有:
节点表示的字符,子字节的位置,字符出现的频度,父节点的位置等,这些都是构造Huffman所需要的。
而解码时,我们只需要能够根据位序列从树的根节点循次遍历到叶节点,叶节点保存其表示的字符,这就足够了。
4.设计程序
;clear
loadwoman;%读入图像数据
%X=imread('girl.bmp','bmp');
data=uint8(X);
[zipped,info]=huffencode(data);%调用Huffman编码程序进展压缩
unzipped=huffdecode(zipped,info,data);
%调用Huffman编码程序进展解码
%显示原始图像和经编码后的图像,显示压缩比,并计算均方根误差得erms=0,表示是Huffman是无失真编码
subplot(121);imshow(data);
subplot(122);imshow(unzipped);
%erms=pare(data(:
),unzipped(:
))
whosdataunzippedzipped
%huffencode函数对输入矩阵vector进展Huffman编码,返回%编码后的向量〔压缩后数据〕与相关信息
function[zipped,info]=huffencode(vector)
%输入和输出都是unit8格式
%info返回解码需要的机构信息
if~isa(vector,'uint8')
error('inputargumentmustbeauint8vector');
end
[m,n]=size(vector);
vector=vector(:
)';
f=frequency(vector);%计算各符号出现的概率
symbols=find(f~=0);
f=f(symbols);
[f,sortindex]=sort(f);
%将符号按照出现的概率大小排序
symbols=symbols(sortindex);
len=length(symbols);
symbols_index=num2cell(1:
len);
codeword_tmp=cell(len,1);
whilelength(f)>1%生产Huffman树,得到码字编码表
index1=symbols_index{1};
index2=symbols_index{2};
codeword_tmp(index1)=addnode(codeword_tmp(index1),uint8(0));
codeword_tmp(index2)=addnode(codeword_tmp(index2),uint8
(1));
f=[sum(f(1:
2))f(3:
end)];
symbols_index=[{[index1,index2]}symbols_index(3:
end)];
[f,sortindex]=sort(f);
symbols_index=symbols_index(sortindex);
end
codeword=cell(256,1);
codeword(symbols)=codeword_tmp;
len=0;
forindex=1:
length(vector)%得到整个图像所有比特数
len=len+length(codeword{double(vector(index))+1});
end
string=repmat(uint8(0),1,len);
pointer=1;
forindex=1:
length(vector)%对输入图像进展编码
code=codeword{double(vector(index))+1};
len=length(code);
string(pointer+(0:
len-1))=code;
pointer=pointer+len;
end
len=length(string);
pad=8-mod(len,8);
%非8整数倍时,最后补pad个0
ifpad>0
string=[stringuint8(zeros(1,pad))];
end
codeword=codeword(symbols);
codelen=zeros(size(codeword));
weights=2.^(0:
23);
maxcodelen=0;
forindex=1:
length(codeword)
len=length(codeword{index});
iflen>maxcodelen
maxcodelen=len;
end
iflen>0
code=sum(weights(codeword{index}==1));
code=bitset(code,len+1);
codeword{index}=code;
codelen(index)=len;
end
end
codeword=[codeword{:
}];
%计算压缩后的向量
cols=length(string)/8;
string=reshape(string,8,cols);
weights=2.^(0:
7);
zipped=uint8(weights*double(string));
%码表存储到一个稀疏矩阵
huffcodes=sparse(1,1);
forindex=1:
nnz(codeword)
huffcodes(codeword(index),1)=symbols(index);
end
%填写解码时所需的结构信息
info.pad=pad;
info.huffcodes=huffcodes;
info.ratio=cols./length(vector);
info.length=length(vector);
info.maxcodelen=maxcodelen;
info.rows=m;
info.cols=n;
%huffdecode函数对输入矩阵vector进展Huffman编码,
%返回解压后的图像数据
functionvector=huffdecode(zipped,info,image)
if~isa(zipped,'uint8')
error('inputargumentmustbeauint8vector');
end
%产生0,1序列,每位占一个字节
len=length(zipped);
string=repmat(uint8(0),1,len.*8);
bitindex=1:
8;
forindex=1:
len
string(bitindex+8.*(index-1))=uint8(bitget(zipped(index),bitindex));
end
string=logical(string(:
)');
len=length(string);
%开始解码
weights=2.^(0:
51);
vector=repmat(uint8(0),1,info.length);
vectorindex=1;
codeindex=1;
code=0;
forindex=1:
len
code=bitset(code,codeindex,string(index));
codeindex=codeindex+1;
byte=decode(bitset(code,codeindex),info);
ifbyte>0
vector(vectorindex)=byte-1;
codeindex=1;
code=0;
vectorindex=vectorindex+1;
end
end
%vector=reshape(vector,info.rows,info.cols);
%函数addnode添加节点
functioncodeword_new=addnode(codeword_old,item)
codeword_new=cell(size(codeword_old));
forindex=1:
length(codeword_old)
codeword_new{index}=[itemcodeword_old{index}];
end
%函数frequency计算各符号出现的概率
functionf=frequency(vector)
if~isa(vector,'uint8')
error('inputargumentmustbeauint8vector');
end
f=repmat(0,1,256);
len=length(vector);
forindex=0:
255
f(index+1)=sum(vector==uint8(index));
end
f=f./len;
%函数decode返回码字对应的符号
functionbyte=decode(code,info)
byte=info.huffcodes(code)
5.实验结果
(1)对图像woman进展编码
NameSizeBytesClassAttributes
data256x25665536uint8
unzipped1x6553765537uint8
zipped1x4122641226uint8
(2)对图像cameraman.tif进展编码
NameSizeBytesClassAttributes
data256x25665536uint8
unzipped1x6553765537uint8
zipped1x5771257712uint8
NameSizeBytesClassAttributes
data409x541x3663807uint8
unzipped1x663808663808uint8
zipped1x578031578031uint8
图像压缩编码的目的是以尽量少的比特数表征图像,同时保持复原图像你的质量,使他符合预定应用场合的要求。
压缩数据量,提高有效性是图像压缩编码的首要目的,通常把图像压缩编码简称为图像编码。
图像编码是一种信源编码,其信源是各种类型的图像信息。
通过本次设计,我学到很多。
数据压缩有两种根本类型:
无损压缩和有损压缩。
使用无损压缩算法压缩的文件buhui8丢失任何信息,它与源文件具有可逆性,即经过压缩算法可以恢复原来的数据。
通常我们对“离散〞的数据采用这种算法:
文本文件,字处理文件,应用程序等。
有损压缩技术在压缩时会丢失一些信息,压缩后不能完全恢复出所有信息。
而实际上,对于音频,图像和视频数据,我们人类可以感知的信息阀值是有限的,有选择的丢弃局部频率成分会产生更好的压缩比。