Matlab-數字圖像編碼實驗-有損壓縮/壓縮算法實驗
代碼鏈接:https://download.csdn.net/download/qq_43571150/12033274
查閱JPEG編碼的有關資料,對圖像進行JPEG壓縮
算法步驟必須包括如下幾個部分:
- 圖像分塊
- 離散餘弦變換
- 量化
- ac和dc係數的Z字形編排
問題1:質量因子分別選爲20,60,80,對比顯示原圖與不同質量因子下解碼後的圖像;
問題2:記錄圖像大小、壓縮比、均方根誤差;對結果進行分析。
JPEG標準亮度量化表👇
結果👇
Matlab代碼👇
function JPEG;
close all;clear all;clc;
J=imread('05.jpg');
imwrite(J,'05 質量因子80.jpg','quality',80);
x=imread('05 質量因子80.jpg');
R=rgb2gray(x);
I=double(R);
imwrite(R,'05 灰度圖.jpg');
圖像分割
以8x8爲最小單元分割,可分割成4096個方塊,從上往下,得到32768x8的矩陣
%% 圖像分割 以8x8爲最小單元分割,可分割成4096個方塊,從上往下,得到32768x8的矩陣
% lena512: 512*512
% Block: 32768*8
Block=[];
for numi=1:64 %逐行取方陣
m=(numi-1)*8+1; %每塊行的開頭
for numj=1:64 %逐列取方陣
n=(numj-1)*8+1; %每塊列的開頭
Block=[Block; I(m:m+7,n:n+7)];
end
end
離散餘弦變換(DCT變換)
對4096個方陣分別進行DCT變換,得到4096個變換方陣,從上往下存,32768x8的矩陣
%% 離散餘弦變換 DCT變換 對4096個方陣分別進行DCT變換,得到4096個變換方陣,從上往下存,32768x8的矩陣
% Block: 32768*8
% FBlock: 32768*8
for num=1:4096
start=(num-1)*8+1;
FBlock(start:start+7,:)=dct2(Block(start:start+7,:));
end
量化
對4096個方陣分別根據JPEG亮度標準量化表進行量化,從上往下
%% 量化 對4096個方陣分別根據JPEG亮度標準量化表進行量化,從上往下存,32768x8的矩陣,部分高頻分量被捨棄,減小了視覺冗餘
% FBlock: 32768*8
% QBlock: 32768*8
load('JPEG512.mat','lighttable');%JPEG標準亮度量化表
for num=1:4096
start=(num-1)*8+1;
QBlock(start:start+7,:)=round(FBlock(start:start+7,:)./lighttable);
end
反向量化
%% 反向量化
% QBlock: 32768*8
% reFBlock: 32768*8
for num=1:4096
start=(num-1)*8+1;
reFBlock(start:start+7,:)=QBlock(start:start+7,:).*lighttable;
end
反離散餘弦變換(IDCT)
for num=1:4096
start=(num-1)*8+1;
Block(start:start+7,:)=idct2(reFBlock(start:start+7,:));
end
圖像重構
%% 圖像重構
reI=[];
for numi=1:64
m=(numi-1)*512+1;
% 分成64個512*8陣列,每個陣列有64個8*8方陣
A=[];
for numj=1:64
n=(numj-1)*8;
A=[A Block(m+n:m+n+7,:)];
end
reI=[reI; A];
end
JPEG Figure
subplot(1,2,1);imshow(I./256);title('input');
subplot(1,2,2);imshow(reI./256);title('JPEG壓縮');
imwrite(reI./256,'05 質量因子80.jpg');
CODE
%% 鋸齒形 ZIG-ZAG 對每一個方陣採用ZIG-ZAG排序,以增加圖像中的連0個數,得到4096x64的矩陣
% QBlock: 32768*8
% QLine: 4096*64
QLine=[];
load('JPEG512.mat','zigzag');%快速Z型排序行向量
zigzag = zigzag + 1; % 下標加1,從0開始
for num=1:4096
start=(num-1)*8+1;
A=reshape(QBlock(start:start+7,:),1,64);% 變成行向量
QLine=[QLine;A(zigzag)];
end
%% 對第一列的DC分量進行DPCM編碼 第一個記爲0,後面的都只記錄與前者的差值
% QLine: 4096*64
% VLIDC: 4096*1
% 對第一列進行DPCM編碼,第一個值記爲DC,並賦0
DC=QLine(1,1);%保留備用
sumcode=0;%計算編碼長度
QLine(1,1)=0;
for num=4096:-1:2
QLine(num,1)=QLine(num,1)-QLine(num-1,1);
end
VLIDC=ones(4096,1);% VLI分組
for num=1:4096
temp=abs(QLine(num,1));%用絕對值判斷組別
if temp==0
VLIDC(num)=0;
else
for k=1:7%經測試,第一列最大值爲80,前7組夠用
if (temp>=2^(k-1)) && (temp<2^k)
VLIDC(num)=k;
break;
end
end
end
end
for num=1:4096
%先根據DC亮度huffman表計算sumcode
if (VLIDC(num)<=5) && (VLIDC(num)>=0)
sumcode=sumcode+3;
elseif VLIDC(num)==6
sumcode=sumcode+4;
else
sumcode=sumcode+5;
end
%再根據VLI表計算sumcode
sumcode=sumcode+VLIDC(num);
end
%% 對其餘63列AC分量進行RLC編碼
% QLine: 4096*64
% 經測試,後63列最大值爲58,VLI前6組夠用。
eob=max(QLine(:))+1; %設一個超大值作爲每一行結束符
for numn=1:4096 %放eob
for numm=64:-1:2
if QLine(numn,numm)~=0
QLine(numn,numm+1)=eob;
break;
end
if (numm==2)%沒找到
QLine(numn,2)=eob;
end
end
end
test=QLine';
[col,~]=find(test==eob);%我們只要eob列位置
validAC=col-1; %每一行保留的AC數據量,含EOB
maxcz=0;
for numn=1:4096 %逐行計算並加至sumcode
cz=[];%記錄前0數
VLIAC=[];%記錄組號
count=0;%記錄連0數
for numm=2:1+validAC(numn)
if QLine(numn,numm)==eob
cz=[cz 0];
VLIAC=[VLIAC 0];
elseif QLine(numn,numm)==0
count=count+1;
else %遇到非0值
if count>15 %遇到連0大於15的
cz=[cz 15];
count=0;
VLIAC=[VLIAC 0];
continue;
end
cz=[cz count];
count=0;
temp=abs(QLine(numn,numm));%用絕對值判斷組別
for k=1:6%經測試,後63列最大值爲58,前6組夠用
if (temp>=2^(k-1)) && (temp<2^k)
VLIAC=[VLIAC k];
break;
end
end
end
end%該行cz和VLIAC已定,開始計算
sumcode=sumcode+4;%EOB對應1010,就是4bit
czlen=length(cz)-1; %czlen不包括EOB
load('JPEG512.mat','codelength');%霍夫曼編碼碼長矩陣(AC、DC亮度編碼表)
for k=1:czlen
if VLIAC(k)==0
sumcode=sumcode+11;
else
sumcode=sumcode+codelength(cz(k)+1,VLIAC(k));
end
end
end
壓縮率
%% 壓縮率
OB=512*512*8;
CR=OB/sumcode;
D=I-reI;
MSE = sum(D(:).*D(:))/prod(size(I));
disp(['原圖 Bit: ',num2str(OB),' bit']);
disp(['壓縮圖像 Bit: ',num2str(sumcode),' bit']);
disp(['壓縮比: ',num2str(CR)]);
disp(['均方根誤差: ',num2str(MSE)]);
end