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