天天看點

(matlab圖像處理)算術編碼

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
           
(matlab圖像處理)算術編碼

檢視

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
           
(matlab圖像處理)算術編碼