I = [2 3 2;
4 5 7;
9 6 7]; % 测试数据模拟图像
[m,n] = size(I);
[sym,prob] = SymbolsAndProbabilityStatistics(I); % 计算符号和概率
% 算术编码
dict = arithmeticdict(sym,prob); % 初始编码区间
sig = I(:); % 编码向量
enco = arithmeticenco(sig,dict); % 编码
fprintf('算术编码为:%16.15f\n',enco);
dsing = arithmeticdeco((enco(1)+enco(2))/2,dict,m,n); % 解码(取上下区间的平均值)
ide = col2im(dsing,[m,n],[m,n],'distinct'); % 把向量重新转换成图像块
figure;
subplot(121),imshow(I,[]),title('原图');
subplot(122),imshow(ide,[]),title('解压图像');
其中函数如下
% 得到图像的符号和概率
function [sym,prob] = SymbolsAndProbabilityStatistics(I)
[m,n] = size(I);
sym = zeros(1); % 符号数组
prob = zeros(1); % 概率
% 匹配概率
p = zeros(1,256);
for i = 1:m
for j = 1:n
p(I(i,j)+1) = p(I(i,j)+1)+1;
end
end
% 删除未出现的编码
num = 1; % 计数
for k = 1:256
if (p(k)~=0)
sym(num) = k-1;
prob(num) = p(k);
num = num+1;
end
end
prob = prob./(m*n); % 概率
end
% 将符号和区间组成表,区间由概率取得
function dict = arithmeticdict(sym,prob)
plast = 0;
dict = cell(length(sym),2); % 编码表
for i = 1:length(sym)
dict{i,1} = sym(i);
dict{i,2} = [plast plast+prob(i)];
plast = plast+prob(i);
end
end
% 编码
function enco = arithmeticenco(sig,dict)
hight = 1;
low = 0;
for i = 1:length(sig)
for j = 1:length(dict)
if (sig(i) == dict{j,1})
range = hight-low;
hight = low+range*dict{j,2}(2);
low = low+range*dict{j,2}(1);
end
end
end
enco = [low hight];
end
% 解码
function dsing = arithmeticdeco(enco,dict,m,n)
dsing = (-1);
for p = 1:(m*n)
for i = 1:length(dict)
if (enco >= dict{i,2}(1) && enco < dict{i,2}(2))
dsing = [dsing, dict{i,1}];
range = dict{i,2}(2)-dict{i,2}(1);
enco = (enco-dict{i,2}(1))/range;
break;
end
end
end
dsing(dsing==-1) = [];
dsing = dsing';
end
得到的输出如下,第一个行是区间下限,第二行是区间上限
算术编码为:0.096786589931747
算术编码为:0.096786631230544
查看dict
能得到每个符号对应的区间
2 ------------------------ [0,0.222222222222222]
3 ------------------------ [0.222222222222222,0.333333333333333]
4 ------------------------ [0.333333333333333,0.444444444444444]
5 ------------------------ [0.444444444444444,0.555555555555556]
6 ------------------------ [0.555555555555556,0.666666666666667]
7 ------------------------ [0.666666666666667,0.888888888888889]
9 ------------------------ [0.888888888888889,1]
注意
当数据较大,如测试时传入一张200*200的图像,编码的结果就出现了问题,解码后的图像无法识别。原因是数据的精度有限,造成溢出。可使用符号计算或有更高精度的advanpix工具包等其他办法。问题如下
算术编码为:0.816069123170177
算术编码为:0.816069123170177