请注意:本文代码参考用MATLAB实现JPEG压缩过程 原作者为新浪博客:dzh_漫漫修行路
本文是一个代码的搬移,其他知识为学习和补充,如有侵权,请联系作者删除。
JPEG原理流程
1.色彩空间转换及相应预处理
在进行JPEG 压缩之前,我们先将图像由rgb 颜色空间转换成YCbCr 空间。然后,我们对图像进行扩展,以保证图像的行列都是8 的倍数。
2.色度抽样
在YCbCr 模型中,Cb 通道和Cr 通道中所包含的信息量远远少于Y 通道中包含的信息量,同时,人眼对色彩的敏感程度有限,因此,JPEG 的压缩算法主要对Cb 和Cr 通道中的数据进行缩减取样,取样的比例可以是4:4:4(无缩减取样)、4:2:2(在水平方向2 的倍数中取样)和4:2:0(在水平方向和垂直方向的2 的倍数中取样),其中,以4:2:0 最为常见。
3.图像分块并进行DCT 变换
将颜色空间转换后的图像进行8*8 的分块,然后对每一块进行DCT 变换。注意,在dct 变换之前,先将每个像素值减去128(直流电平下移)。
4.对三个通道分别量化
所谓量化就是用像素值÷量化表对应值所得的结果(四舍五入)。由于量化表左上角的值较小,右上角的值较大,这样就起到了保持低频分量,抑制高频分量的目的。JPEG使用的颜色是YCrCb 格式。我们提到过,Y 分量代表了亮度信息,CrCb 分量代表了色差信息。相比而言,Y 分量更重要一些。我们可以对Y 采用细量化,对CrCb 采用粗量化,可进一步提高压缩比。所以上面所说的量化表通常有两张,一张是针对Y 的;一张是针对CrCb 的。通过量化可以达到通低频减高频的效果。
5.反量化和反DCT
这个过程就是量化和DCT 的逆过程。
6.恢复出YCBCR 图像并去掉扩展的行和列
这一步骤后便可得到压缩后又恢复的图像。
下面给出三个.m文件,如原作者之言,运行JPEGEncodeDecode.m的确能够运行
亮度量化表
%亮度量化表
Y_Table=[16 11 10 16 24 40 51 61
12 12 14 19 26 58 60 55
14 13 16 24 40 57 69 56
14 17 22 29 51 87 80 62
18 22 37 56 68 109 103 77
24 35 55 64 81 104 113 92
49 64 78 87 103 121 120 101
72 92 95 98 112 100 103 99];
色差量化表
%色差量化表
CbCr_Table=[17, 18, 24, 47, 99, 99, 99, 99;
18, 21, 26, 66, 99, 99, 99, 99;
24, 26, 56, 99, 99, 99, 99, 99;
47, 66, 99 ,99, 99, 99, 99, 99;
99, 99, 99, 99, 99, 99, 99, 99;
99, 99, 99, 99, 99, 99, 99, 99;
99, 99, 99, 99, 99, 99, 99, 99;
99, 99, 99, 99, 99, 99, 99, 99];
请注意:本文代码参考用MATLAB实现JPEG压缩过程 原作者为新浪博客:dzh_漫漫修行路
本文是一个代码的搬移,其他知识为学习和补充,如有侵权,请联系作者删除。
JPEGEncodeDecode.m文件
function JPEGEncodeDecode
img=imread('lena.jpg');
subplot(121);imshow(img);title('原图'); %显示原图
img_ycbcr = rgb2ycbcr(img); % rgb->yuv转换
[row,col,~]=size(img_ycbcr); % 取出行列数,~表示3个通道算1列
%对图像进行扩展
row_expand=ceil(row/16)*16; %行数上取整再乘16,及扩展成16的倍数
if mod(row,16)~=0 %行数不是16的倍数,用最后一行进行扩展
for i=row:row_expand
img_ycbcr(i,:,:)=img_ycbcr(row,:,:);
end
end
col_expand=ceil(col/16)*16; %列数上取整
if mod(col,16)~=0 %列数不是16的倍数,用最后一列进行扩展
for j=col:col_expand
img_ycbcr(:,j,:)=img_ycbcr(:,col,:);
end
end
%对Y,Cb,Cr分量进行4:2:0采样
Y=img_ycbcr(:,:,1); %Y分量
Cb=zeros(row_expand/2,col_expand/2); %Cb分量
Cr=zeros(row_expand/2,col_expand/2); %Cr分量
for i=1:row_expand/2
for j=1:2:col_expand/2-1 %奇数列
Cb(i,j)=double(img_ycbcr(i*2-1,j*2-1,2));
Cr(i,j)=double(img_ycbcr(i*2-1,j*2+1,3));
end
end
for i=1:row_expand/2
for j=2:2:col_expand/2 %偶数列
Cb(i,j)=double(img_ycbcr(i*2-1,j*2-2,2));
Cr(i,j)=double(img_ycbcr(i*2-1,j*2,3));
end
end
%分别对三种颜色分量进行编码
Y_Table=[16 11 10 16 24 40 51 61
12 12 14 19 26 58 60 55
14 13 16 24 40 57 69 56
14 17 22 29 51 87 80 62
18 22 37 56 68 109 103 77
24 35 55 64 81 104 113 92
49 64 78 87 103 121 120 101
72 92 95 98 112 100 103 99];%亮度量化表
CbCr_Table=[17, 18, 24, 47, 99, 99, 99, 99;
18, 21, 26, 66, 99, 99, 99, 99;
24, 26, 56, 99, 99, 99, 99, 99;
47, 66, 99 ,99, 99, 99, 99, 99;
99, 99, 99, 99, 99, 99, 99, 99;
99, 99, 99, 99, 99, 99, 99, 99;
99, 99, 99, 99, 99, 99, 99, 99;
99, 99, 99, 99, 99, 99, 99, 99];%色差量化表
Qua_Factor=0.5;%量化因子,最小为0.01,最大为255,建议在0.5和3之间,越小质量越好文件越大
%对三个通道分别DCT和量化
Y_dct_q=Dct_Quantize(Y,Qua_Factor,Y_Table);
Cb_dct_q=Dct_Quantize(Cb,Qua_Factor,CbCr_Table);
Cr_dct_q=Dct_Quantize(Cr,Qua_Factor,CbCr_Table);
%对三个通道分别反量化和反DCT
Y_in_q_dct=Inverse_Quantize_Dct(Y_dct_q,Qua_Factor,Y_Table);
Cb_in_q_dct=Inverse_Quantize_Dct(Cb_dct_q,Qua_Factor,CbCr_Table);
Cr_in_q_dct=Inverse_Quantize_Dct(Cr_dct_q,Qua_Factor,CbCr_Table);
%恢复出YCBCR图像
YCbCr_in(:,:,1)=Y_in_q_dct;
for i=1:row_expand/2
for j=1:col_expand/2
YCbCr_in(2*i-1,2*j-1,2)=Cb_in_q_dct(i,j);
YCbCr_in(2*i-1,2*j,2)=Cb_in_q_dct(i,j);
YCbCr_in(2*i,2*j-1,2)=Cb_in_q_dct(i,j);
YCbCr_in(2*i,2*j,2)=Cb_in_q_dct(i,j);
YCbCr_in(2*i-1,2*j-1,3)=Cr_in_q_dct(i,j);
YCbCr_in(2*i-1,2*j,3)=Cr_in_q_dct(i,j);
YCbCr_in(2*i,2*j-1,3)=Cr_in_q_dct(i,j);
YCbCr_in(2*i,2*j,3)=Cr_in_q_dct(i,j);
end
end
I_in=ycbcr2rgb(YCbCr_in);
I_in(row+1:row_expand,:,:)=[];%去掉扩展的行
I_in(:,col+1:col_expand,:)=[];%去掉扩展的列
subplot(122);imshow(I_in);title('重构后的图片');
end
Dct_Quantize.m文件
function [Matrix]=Dct_Quantize(I,Qua_Factor,Qua_Table)
%Dct量化
%I:
%Qua_Factor:
%Qua_Table
I=double(I)-128; %层次移动128个灰度级
%t2变换:把ImageSub分成8*8像素块,分别进行dct2变换,得变换系数矩阵Coef
I=blkproc(I,[8 8],'dct2(x)');
Qua_Matrix=Qua_Factor.*Qua_Table; %量化矩阵
I=blkproc(I,[8 8],'round(x./P1)',Qua_Matrix); %量化,四舍五入
Matrix=I; %得到量化后的矩阵
end
Inverse_Quantize_Dct.m文件
function [ Matrix ] = Inverse_Quantize_Dct( I,Qua_Factor,Qua_Table )
%UNTITLED3 Summary of this function goes here
% Detailed explanation goes here
Qua_Matrix=Qua_Factor.*Qua_Table; %反量化矩阵
I=blkproc(I,[8 8],'x.*P1',Qua_Matrix);%反量化,四舍五入
[row,column]=size(I);
I=blkproc(I,[8 8],'idct2(x)'); %T反变换
I=uint8(I+128);
for i=1:row
for j=1:column
if I(i,j)>255
I(i,j)=255;
elseif I(i,j)<0
I(i,j)=0;
end
end
end
Matrix=I; %反量化和反Dct后的矩阵
end
其中一个函数解释
函数blkproc会显示不推荐使用,但是运行时并不会报错
B = blkproc(A,[M N],FUN) processes the image A by applying the function
FUN to each distinct M-by-N block of A, padding A with zeros if
necessary. FUN is a FUNCTION_HANDLE that accepts an M-by-N matrix, X,
and returns a matrix, vector, or scalar Y: