一种基于MATLAB的JPEG图像压缩具体实现方法

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

一种基于MATLAB的JPEG图像压缩具体实现方法说明:该方法主要是对FPGA硬件实现编码的一个验证,MATLAB处理时尽量选择了简单化和接近硬件实现需要。

JPEG编码解码流程:BMP图像输入、8*8分块、DCT变换、量化、Zig_Zag 扫描、获取DC/AC系数中间格式、Huffman熵编码、DC/AC系数Huffman熵解码,反zig_zag扫描、反量化、反DCT变换、8*8组合、解码图像显示。

下面根据具体代码解释实现过程。

1.BMP图像输入

A=imread('messi_b.bmp'); %读取BMP图像矩阵

R=int16(A(:,:,1))-128; %读取RGB矩阵,由于DCT时输入为正负输入,G=int16(A(:,:,2))-128;%使得数据分布范围-127——127

B=int16(A(:,:,3))-128;

通过imread函数获取BMP图像的R、G、B三原色矩阵,因为下一步做DCT 转换,二DCT函数要求输入为正负值,所以减去128,使得像素点分布范围变为-127~127,函数默认矩阵A的元素为无符号型(uint8),所以如果直接相减差值为负时会截取为0,所以先用int16将像素点的值转为带符号整数。网上很多都提到了第一步的YUV转换,但是由于MATLAB在实验时YUV转换后色差失真比较严重,这里没有进行YUV转换。个人理解为YUV转换后经过非R/G/B原理显示器显示效果可能会比较好,或者如果图像有色差可以选择YUV调整。为了方便,读入的图像像素为400*296,是8*8的50*37倍,所以代码里没有进行8*8的整数倍调整。

2. 8*8分块

R_8_8=R(1:8,1:8);%取出一个8*8块

这里以R色压缩解码为例,后边解释均为R色编码解码过程,最后附全部代码。R_8_8为:

3.DCT变换

R_DCT=dct2(R_8_8);

使用MATLAB函数dct2进行DCT变换,也可使用DCT变换矩阵相乘的方法,即R_DCT=A* R_8_8*A T,其中A为DCT变换矩阵。R_DCT为:

4.量化

R_dct_s=round(R_DCT./S);

使用JPEG标准亮度量化表S量化并取整,S为:

R_dct_s为:

其中第一个数-14为DC系数,剩余63个数为AC系数,左上角低频,右下角高频,可以看出量化后已经将多数高频量丢弃,从而实现数据压缩。

5.Zig_Zag扫描

Rdcts_c=reshape(R_dct_s',1,64);

Rdcts_c_z=Rdcts_c(zig);

利用reshape函数将量化后的矩阵转为[1,64]行向量,利用zig向量按位取值,进行Zig_Zag扫描。其中Rdcts_c为:

11~64位均为0;

zig为:

zig=[0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6, 7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,4 6,53,60,61,54,47,55,62,63];

Zig_Zag扫描后的向量Rdcts_c_z为:

11~64位均为0;

可以看出通过zig向量按位取值准确实现了对量化后DC,AC系数的Zig_Zag 扫描。

6.获取DC/AC系数的中间格式

r_dc_diff=Rdcts_c_z(1)-r_dc;

用当前DC系数减去上一个8*8子块的DC系数得到两DC系数的差值作为DC 系数中间值,因为图像相邻像素具有很大的相关性,这样做可以减小DC编码长度,进一步压缩代码,在解码的时候通过该差值依次获得各8*8子块DC系数。

r_dc=Rdcts_c_z(1);

解码之后用该代码将当前DC系数赋给r_dc作为下一次编码时求差值的参考值。

for i=2:1:64;

if Rdcts_c_z(i)==0&&r_n<15&&i~=64

r_n=r_n+1;

elseif Rdcts_c_z(i)==0&&r_n<15&&i==64

r_ac_cnt=r_ac_cnt+1;

r_AC(1,2*r_ac_cnt-1)=r_n;

r_AC(1,2*r_ac_cnt)=Rdcts_c_z(i);

r_n=0;

elseif Rdcts_c_z(i)~=0&&r_n<15

r_ac_cnt=r_ac_cnt+1;

r_AC(1,2*r_ac_cnt-1)=r_n;

r_AC(1,2*r_ac_cnt)=Rdcts_c_z(i);

r_n=0;

elseif Rdcts_c_z(i)~=0&&r_n==15

r_ac_cnt=r_ac_cnt+1;

r_AC(1,2*r_ac_cnt-1)=r_n;

r_AC(1,2*r_ac_cnt)=Rdcts_c_z(i);

r_n=0;

elseif Rdcts_c_z(i)==0&&r_n==15

r_ac_cnt=r_ac_cnt+1;

r_AC(1,2*r_ac_cnt-1)=r_n;

r_AC(1,2*r_ac_cnt)=Rdcts_c_z(i);

r_n=0;

end

end

该for循环用来获取AC系数的中间格式,因为第一个数为DC系数,所以循环从2开始。因为63个AC系数中有很多值为0,所以采用行程编码可以很大的减小编码长度。行程编码是指记录两个非0数之间0的个数,以及非零数的数值,非零数个数和数值为一组中间格式,这里为了计数方便,连续16个0出现时,用(15,0)表示,继续获取下一个AC系数中间格式,也就是说行程编码压缩的最大长度设为16bit,例如数列:1、0、0、-1、0、0、0、0、0、3、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、2;对该列数通过形成编码获取中间格式即为:(0,1)、(2,-1)、(5,3)、(15,0)、(5,2)。第一个数为0的个数,第二个数为数值,特殊情况(15,0)指16个0。

通过该for循环获取AC系数中间格式并保存在向量Rdcts_c_z中,奇数表示0的个数,偶数表示AC系数数值。

表示前两个数

相关文档
最新文档