使用Huffman编码在MATLAB中进行灰度图像压缩

4
我正在尝试使用MATLAB中的Huffman编码压缩灰度图像,并尝试了以下代码。我已经使用了一个大小为512x512的灰度图像,格式为tif。我的问题是,压缩后的图像大小(压缩码字的长度)比未压缩的图像还要大。压缩比小于1。
clc;
clear all;
A1 = imread('fig1.tif');
[M N]=size(A1);
A = A1(:);
count = [0:1:255]; % Distinct data symbols appearing in sig
total=sum(count);
for i=1:1:size((count)');                  
    p(i)=count(i)/total;
end

[dict,avglen]=huffmandict(count,p) % build the Huffman dictionary
comp= huffmanenco(A,dict);         %encode your original image with the dictionary you just built
compression_ratio= (512*512*8)/length(comp)   %computing the compression ratio

%% DECODING
Im = huffmandeco(comp,dict); % Decode the code
I11=uint8(Im);

decomp=reshape(I11,M,N);
imshow(decomp);
1个回答

4

你的代码中存在一些小错误。我假设你想计算每个像素遇到的概率,即标准化直方图。但是你的计算方法有问题。具体而言:

count = [0:1:255]; % Distinct data symbols appearing in sig
total=sum(count);
for i=1:1:size((count)');                  
    p(i)=count(i)/total;
end

total 正在对 [0,255] 进行求和,这是不正确的。您应该计算图像的概率分布。您应该使用 imhist 来完成这个操作。因此,您应该改为执行以下操作:

count = 0:255;
p = imhist(A1) / numel(A1);

这将正确计算您图像的概率分布。请记住,在进行哈夫曼编码时,您需要指定遇到像素的概率。假设每个像素被选择的可能性相等,这可以通过计算图像的直方图,然后通过图像中的像素总数进行归一化来捕获。尝试一下,看看是否能得到更好的结果。
但是,如果您拥有频繁出现的符号,哈夫曼才能给您带来良好的压缩比率。您是否查看了直方图或图像中像素的分布?
如果分布很大,并且每个bin中的条目很少,则哈夫曼不会为您提供任何压缩节省。实际上,它可能会导致结果更大。请记住,TIFF压缩标准仅将Huffman用作算法的一部分。还有一些预处理和后处理工作可进一步降低大小。
例如,假设我有一个由[0,1,2,... 255; 0,1,2,...,255; 0,1,2,...,255]组成的图像;我有3行[0,255],但实际上它可以是任意行数。这意味着遇到每个符号的概率是等概率的,或者是1/255,这意味着对于每个符号,我们需要8位/每个符号...这基本上就是原始像素值!
哈夫曼的关键在于一组比特一起生成一个符号。经常出现的符号被分配一个较小的比特序列。由于我所说的这张图片具有等概率的强度,因此您只会为每个强度生成一个符号,而不是一组。因此,除了传输字典外,您实际上每次只发送一个字符,这与发送原始字节流一样。
如果要通过原始哈夫曼压缩图像,则像素的分布必须倾斜。例如,如果您的图像中大多数强度都很暗或很亮。如果您的图像具有良好的对比度或者像素强度的分布在整个图像中是平坦的,则哈夫曼不会为您提供任何压缩节省。

我尝试运行代码,但当我按照问题中给出的方式运行时,即:count = [0:1:255]; % Distinct data symbols appearing in sig total=sum(count); for i=1:1:size((count)');
p(i)=count(i)/total; end代码永远不会结束。 当我像答案提供的那样运行时,我会收到一个错误:Error using huffmandict (line 171) Source symbols repeatError in Huffman (line 10) [dict,avglen]=huffmandict(count,p)唯一的区别是:我获取了一张RGB图像并将其转换为灰度图像。你能帮我吗?
- faith
@faith 当您引用原始问题时,count计算不正确。我在我的答案中特别指出了这一点,并建议OP使用imhist代替。如果您没有imhist,因为它是图像处理工具箱的一部分,请使用accumarrayp = accumarray(double(A(:)) + 1, 1, [256 1]) / numel(A);A是输入图像。 - rayryeng
感谢您的快速回复。我已经按照您的建议尝试运行了。我也有imhist。然而,我遇到了“源符号重复”的错误。 - faith
@faith,你的 count 变量出了问题。有重复项。请仔细检查是否正确生成了从0到255的向量,步长为1。 - rayryeng
我觉得我漏掉了什么。你建议将count变量生成为count=imhist(A1)而不是count=[0:1:255]。那么我应该在哪里使用向量[0:255] - faith
1
@faith 我错了。count 应该保持不变。是 p 不正确,我已经在我的帖子中进行了更正。请查看编辑。祝你好运。 - rayryeng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接