基于霍夫曼图像压缩重建
部分参考来源:
https://blog.csdn.net/qq_59747472/article/details/121890265
为了节省空间,在对数据进行编码时,可以对那些经常出现的数据指定较少的位数表示, 而那些不常出现的数据指定较多的位数表示,从而降低冗余,这样从总的效果看就节省了存储空间。基于哈夫曼编码图像压缩的基本原理是频繁使用的数据用较短的代码代替,较少使用的数据用较长的代码代替,每个数据的代码各不相同,这是一种典型的无损编码方式。
部分函数
Mat2Huff.m
function [zvec, zi] = Mat2Huff(vec)
if ~isa(vec,'uint8')
fprintf('\n请确认输入uint8类型数据向量!\n');
return;
end
vec = vec(:)';
f = Frequency(vec);
syminfos = find(f~=0);
f = f(syminfos);
[f, sind] = sort(f);
syminfos = syminfos(sind);
len = length(syminfos);
syminfos_ind = num2cell(1:len);
cw_temp = cell(len,1);
while length(f)>1
ind1 = syminfos_ind{1};
ind2 = syminfos_ind{2};
cw_temp(ind1) = AddNode(cw_temp(ind1),uint8(0));
cw_temp(ind2) = AddNode(cw_temp(ind2),uint8(1));
f = [sum(f(1:2)) f(3:end)];
syminfos_ind = [{[ind1 ind2]} syminfos_ind(3:end)];
[f,sind] = sort(f);
syminfos_ind = syminfos_ind(sind);
end
cw = cell(256,1);
cw(syminfos) = cw_temp;
len = 0;
for i = 1 : length(vec),
len = len+length(cw{double(vec(i))+1});
end
str_temp = repmat(uint8(0),1,len);
pt = 1;
for index=1:length(vec)
cd = cw{double(vec(index))+1};
len = length(cd);
str_temp(pt+(0:len-1)) = cd;
pt = pt+len;
end
len = length(str_temp);
pad = 8-mod(len,8);
if pad > 0
str_temp = [str_temp uint8(zeros(1,pad))];
end
cw = cw(syminfos);
cl = zeros(size(cw));
ws = 2.^(0:51);
mcl = 0;
for index = 1:length(cw)
len = length(cw{index});
if len>mcl
mcl = len;
end
if len>0
cd = sum(ws(cw{index}==1));
cd = bitset(cd,len+1);
cw{index} = cd;
cl(index) = len;
end
end
cw = [cw{:}];
cols = length(str_temp)/8;
str_temp = reshape(str_temp,8,cols);
ws = 2.^(0:7);
zvec = uint8(ws*double(str_temp));
huffcodes = sparse(1,1);
for index = 1:numel(cw)
huffcodes(cw(index),1) = syminfos(index);
end
zi.pad = pad;
zi.huffcodes = huffcodes;
zi.ratio = cols./length(vec);
zi.length = length(vec);
zi.maxcodelen = mcl;
直方图对比函数代码
HisteqContrast.m
function HisteqContrast(Img1, Img2)
figure('Name', '直方图对比', 'NumberTitle', 'Off', ...
'Units', 'Normalized', 'Position', [0.1 0.1 0.5 0.5]);
subplot(2, 2, 1); imshow(mat2gray(Img1)); title('原图像', 'FontWeight', 'Bold');
subplot(2, 2, 2); imshow(mat2gray(Img2)); title('处理后的图像', 'FontWeight', 'Bold');
if ndims(Img1) == 3
Q = rgb2gray(Img1);
else
Q = mat2gray(Img1);
end
if ndims(Img2) == 3
W = rgb2gray(Img2);
else
W = mat2gray(Img2);
end
subplot(2, 2, 3); imhist(Q, 64); title('原灰度直方图', 'FontWeight', 'Bold');
subplot(2, 2, 4); imhist(W, 64); title('处理后的灰度直方图', 'FontWeight', 'Bold');
这些代码都是二进制码,且码字长度是不均匀的、平均码率可以接近信息源熵值的一种编码。编码过程是先对图像数据扫描一遍, 计算出各种像素出现的概率,按概率的大小建立最优二叉树(二叉树的叶子节点刚好表示的图像中的某种像素)并给二叉树的每个分支赋特定权值(0或1), 然后通过遍历二叉树读取从根节点到叶子节点的路径权值字符串,即给每种像素指定了不同长度的唯一编码, 由此得到一张该图像所有像素的哈夫曼编码表。编码后的图像数据记录的是每个像素的码字,而码字与实际像素值的对应关系记录在码表中,码表是附在图像文件中的。
得到后续的直方图对比,效果如图
算法流程
系统GUI初始界面
保存截图函数:
function SnapImage()
imagesPath = '.\\snap_images';
if ~exist(imagesPath, 'dir')
mkdir(imagesPath);
end
[FileName,PathName,FilterIndex] = uiputfile({'*.jpg;*.tif;*.png;*.gif','All Image Files';...
'*.*','All Files' },'保存截图',...
'.\\snap_images\\temp.jpg');
if isequal(FileName, 0) || isequal(PathName, 0)
return;
end
fileStr = fullfile(PathName, FileName);
f = getframe(gcf);
f = frame2im(f);
imwrite(f, fileStr);
msgbox('抓图文件保存成功!', '提示信息');
保存图像函数:
function SaveImage(Img)
imagesPath = '.\\results';
if ~exist(imagesPath, 'dir')
mkdir(imagesPath);
end
[FileName,PathName,FilterIndex] = uiputfile({'*.jpg;*.tif;*.png;*.gif','All Image Files';...
'*.*','All Files' },'保存截图',...
'.\\results\\result.jpg');
if isequal(FileName, 0) || isequal(PathName, 0)
return;
end
fileStr = fullfile(PathName, FileName);
imwrite(mat2gray(Img), fileStr);
结果展示:
本文源代码下载地址–>传送门