多媒体技术与应用实验之Huffman编解码matlab实现
主函数:
clc;
clear;
close all ;
X=imread( 'lena.bmp' ); %图像灰度化
data=uint8(X);
[zipped,info]=huffencode(data); %调用 Huffman 编码程序进行压缩
unzipped=huffdecode(zipped,info); %调用 Huffman 编码程序进行解码
subplot(121);imshow(data);title( ' 原始图像 ' );
subplot(122);imshow(unzipped);title( 'Huffman 编码并解码后图像 ' );
disp( ' 平均码长 ' );L=info.avalen
disp( ' 压缩比 ' );CR=info.ratio
disp( ' 信息熵 ' );H=info.h
disp( ' 编码效率 ' );CE=info.ce
disp( ' 编码 ' );huffcode = info.huffcodes
编码函数:
function [zipped,info]=huffencode(vector)
[m,n]=size(vector); %求输入矩阵的行列数
vector=vector(:)'; %将矩阵按列转换成一列后转至,成为一个行向量 ( 其中存放灰度值 )
f=frequency(vector); %0-255灰度概率,值为概率
symbols=find(f~=0); %概率不为零的灰度值,1-215 值为灰度值
f=f(symbols); %筛选后概率向量,0-255 去0概率
[f,sortindex]=sort(f); %排序升序,sortindex筛选后的序号
fs=f;
symbols=symbols(sortindex); %灰度值按概率排序
len=length(symbols); %读取位置向量的长度
symbols_index=num2cell(1:len); %生成异质矩阵
codeword_tmp=cell(len,1); %异质变量 存放码字
while length(f)>1 % Huffman 树,得二进制码表
index1=symbols_index{1};
index2=symbols_index{2};
codeword_tmp(index1)=addnode(codeword_tmp(index1),uint8(0)); %添加节点且该分支按 0 标记
codeword_tmp(index2)=addnode(codeword_tmp(index2),uint8(1)); %添加节点且该分支按 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;
for i=1:length(symbols) %得到各符号码长矩阵
wordlen(i)=length(codeword_tmp{i});
end
avawordlen=fs*wordlen'; %计算平均码长
Hlog=log2(fs)';
H=-(fs*Hlog); %计算信息熵
for index=1:length(vector) %得到整个图像各点灰度值转化为二进制码字后的总比特数
len=len+length(codeword{double(vector(index))+1});
end
string=repmat(uint8(0),1,len); %创建元素数与总比特数一致的行向量
pointer=1; %定义指针变量
for index=1:length(vector) % 对输入图像进行编码
code=codeword{double(vector(index))+1}; %对应符号的二进制码字给
len=length(code); %读取码字长度
string(pointer+(0:len-1))=code; %将二进制码字存入行向量中
pointer=pointer+len; %指针移移位
end
% 将二进制编码按照每 8 位生成一个新字符。
len=length(string);
zp=8-mod(len,8);
if zp>0
string=[string uint8(zeros(1,zp))]; %不足 8 位的在后补零
end
codeword=codeword(symbols); %码字按符号概率放入列向量中
codelen=zeros(size(codeword)); %创建与列向量元素数相同的列向量
%将二进制转化为十进制
weights=2.^(0:23);
for index=1:length(codeword)
len=length(codeword{index}); %读二进制码字长度
if len>0
code=sum(weights(codeword{index}==1)); %计算二进制码字对应的十进制数
code=bitset(code,len+1); %将码字最高位的上一位置 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);
for index=1:nnz(codeword)
huffcodes(codeword(index),1)=symbols(index);
end
%返回编码参数
% info.zeropad=zp; %添加的比特数
info.huffcodes=huffcodes; %码字表
info.length=length(vector); %灰度化图像矩阵长度
info.rows=m; %灰度图像行数
info.cols=n; %灰度图像列数
info.avalen=avawordlen; %平均码长
info.ratio=8/avawordlen; %压缩比
info.h=H; %信息熵
info.ce=H/avawordlen; %编码效率
end
解码函数:
%huffdecode 函数对输入矩阵 vector 进行 Huffman 编码,返回解压后的图像数据
function vector=huffdecode(zipped,info)
len=length(zipped); %读取压缩矩阵长度
string=repmat(uint8(0),1,len*8); %创建全为 0的行向量
bitindex=(1:8);
for index=1:len %还原成01串
string(bitindex+8.*(index-1))=uint8(bitget(zipped(index),bitindex)); % 读取压缩矩阵中的值并转化为 8位二进制按顺序放入 string 矩阵中
end
len=length(string);
%开始解码
vector=repmat(uint8(0),1,info.length); %创建与灰度化图像行向量等长的行向量
vectorindex=1;
codeindex=1;
code=0;
for index=1:len-1
code=bitset(code,codeindex,string(index)); %按位读编码码字
codeindex=codeindex+1; %移位
byte=decode(bitset(code,codeindex),info); %进行码字匹配,读取相对应符号
if byte>0 %若读取到对应符号则进行下面操作,无符号继续按位读取码字
vector(vectorindex)=byte-1; %将符号表示的灰度值放入容器矩阵中
codeindex=1; %重置
code=0; %重置
vectorindex=vectorindex+1; %容器指针移位
end
end
vector=reshape(vector,info.rows,info.cols); %将构成的灰度矩阵按原图矩阵行列 数重构,解码完成
end
检测频率概率:
%函数 frequency 计算各符号出现的概率
function f=frequency(vector)
f=zeros(1,256); %设置一个 256 个元素都为 0 的行向量
len=length(vector); %读取输入矩阵元素个数
for index=0:1:255
f(index+1)=sum(vector==index); %统计输入图像矩阵中 0 至 255 各值出现的个数, 存入一个行向量中
end
f=f./len; %求各符号值出现的概率
end
decode:
%函数 decode 返回码字对应的符号
function byte=decode(code,info)
byte=info.huffcodes(code);
end
addnode:
%函数 addnode 添加节点确定符号码字
function codeword_new=addnode(codeword_old,item)
codeword_new=cell(size(codeword_old)); %前一步码字维数作为新细胞型变量的维数, 用于存放码字
for index=1:length(codeword_old) %确定符号对应码字
codeword_new{index}=[item codeword_old{index}];
end
end