1. 程式人生 > >基於matlab的LZW影象壓縮編碼

基於matlab的LZW影象壓縮編碼

LZW壓縮
LZW壓縮(LZW compression)是一種由Abraham Lempel、Jacob Ziv和Terry Welch發明的基於表查尋演算法把檔案壓縮成小檔案的無失真壓縮方法。LZW壓縮使用的兩個常用檔案格式是用於網站的GIF圖象格式和TIFF圖象格式。LZW壓縮是還適合壓縮文字檔案。
一個特殊的LZW壓縮演算法使用指定的長度的位的序列(例如,12位)並且在一個表(有時叫做“字典”或“譯碼本”)裡為這個特殊的位模式產生一個條目創造一個詞條,並把這個模式的本身和短程式碼結合起來。隨著輸入的讀取,任何已經讀取的模式將取代這些短的程式碼,有效的把輸入壓縮成一個更小的檔案。
LZW通俗理解:

http://blog.csdn.net/krossford/article/details/49157531
這個博主LZW的工作思路是錯誤的,下面的編碼思路是正確的,比如abcabcabc編碼後位元組是6個,分別是a,b,c,ab,ca,bc,並不是博主上面說的3個位元組。

主程式:

為什麼要把int型轉換成double型?
1 、有些函式支援double型,而不支援uint8的資料型別,所以要轉換
2 、精度問題了,因為uint8進行資料處理的時候,容易造成資料溢位或精度不夠。
為了節省儲存空間,matlab為影象提供了特殊的資料型別uint8(8位無符號整數),以此方式儲存的影象稱作8點陣圖像。
如果現在想imshow顯示影象結果,就需要再轉換成uint8格式。

clear;clc
I = rgb2gray(imread('DSC_0528.jpg'));
[m,n] = size(I);
x = double(I(:)'); % 轉化格式型別
% LZW編碼
[S,sz]=LZW(x);
% LZW解碼
A =  [];
for i = 1:length(sz)
    A = [A S{sz(i)}];
end

A = [A zeros(1,m*n-length(A))];
II = uint8(reshape(A,m,n));
[M,N]=size(II);
b=length(S);
sum=M*N;
H=0;  %初始化資訊熵
for i=0:255;
    [r,c]=find(II==i);  %統計每個灰度值的畫素點總數
    num(i+1)=length(r);
    p(i+1)=num(i+1)/sum;  %統計每個灰度值的概率
    if p(i+1)~=0
        H=H-p(i+1)*log2(p(i+1));  %計算資訊熵
    end
end

%計算平均碼字長度
pjmc=b/sum
%計算編碼效率
bmxl=H/pjmc
%計算壓縮比
ysb=sum*8/b
disp('資訊熵');disp(H);disp('平均碼字長度');disp(pjmc);
disp('編碼效率');disp(bmxl);disp('壓縮比');disp(ysb);
subplot(121);imshow(I);
subplot(122);imshow(II);

定義LZW編碼函式:

1、unique()函式:去掉矩陣中重複的元素
2、細胞陣列:細胞結構可以把不同型別的資料納入到一個變數中。普通陣列中的每個元素都必須具有相同的資料型別,而細胞則沒有此要求。

function [S,sz]=LZW(x)
% LZW詞典編碼
% x為輸入序列  S為詞典  sz為輸出
n = length(x); % 序列長度
S = unique(x); % 初始化詞典
x = num2cell(x); % 轉化為細胞陣列
S = num2cell(S); % 轉化為細胞陣列
sz = []; % 初始化輸出序列
temp = []; % 當前序列
% 開始編碼
for i = 1:n
    temp = [temp x{i}]; % 取一個元素放入序列中
    for j = 1:length(S)
        if isequal(S{j},temp) %判斷S{j},temp兩個陣列是否相等
            flag = 1;
            break;
        else
            flag = 0;
        end
    end
    if flag == 1 % 如果當前序列在詞典中
        continue;
    else % 如果當前序列不在詞典中
        S = [S temp]; % 將當前序列加入詞典
        for j = 1:length(S)
            if isequal(S{j},temp(1:end-1))
                T = j;
                break;
            end
        end
        sz = [sz T];
        temp = temp(end); % 重置temp
    end
end
for j = 1:length(S)
    if isequal(S{j},temp(end))
        T = j;
        break;
    end
end
sz = [sz T]; % 最後一位加入輸出