注:

1、该博客已经停止维护了,相关文件也早已丢失了,各位非常抱歉!

2、本实验不生成、不存储具体编码,只计算编码长度、PSNR 和压缩比等,即计算 JPEG 性能。

3、本文只提供代码。如果需要完整的实现过程,压缩包下载地址

https://download.csdn.net/download/weixin_41730407/10371917

4、该程序还使用 imwrite 实现了相同放大倍数下 JPEG2000 的压缩,并与 JPEG 压缩指标进行了对比。

实验环境:Matlab R2017b

实验准备:lenaXING.mat含:

codelength.mat:霍夫曼编码码长矩阵(AC、DC 亮度编码表),个人整理;

JPEG图像压缩 matlab实现 - 图1

lena512.mat from https://www.ece.rice.edu/~wakin/images/

lighttable.mat:JPEG 标准亮度量化表;

zigzag.mat:快速 Z 型排序行向量。

JPEG图像压缩 matlab实现 - 图2

为了简化步骤,我们省略了第一步,而直接对源图像进行处理。

1、图像分割

以 8x8 为最小单元分割,可分割成 4096 个方块,从上往下存。得到 32768x8 的矩阵。

2、DCT变换

对这 4096 个方阵分别进行DCT变换,得到 4096 个变换方阵,从上往下存。仍是 32768x8 的矩阵。

3、量化

对这 4096 个方阵分别根据JPEG亮度标准量化表进行量化,从上往下存。仍是 32768x8 的矩阵。

由于四舍五入,许多高频分量已经被舍弃,减小了视觉冗余。

4、系数编码和熵编码

进一步地,我们要对图像进行系数编码和熵编码。

先用一个例子说明以下过程:

JPEG图像压缩 matlab实现 - 图3

a. 对每一个方阵采用ZIG-ZAG排序,以增加图像中的连 0 个数。得到 4096x64 的矩阵。

b. 对第一列的DC分量进行DPCM编码。第一个记为 0,后面的都只记录与前者的差值。

c. 然后,我们根据VLI编码表,对这些数值进行分组。

JPEG图像压缩 matlab实现 - 图4

d. 我们将组号记录下来。例如:(2,3) 意思是:DPCM编码为 3,且位于第二组(如表所示)。

DC组号(实际上就是编码长度)记录在 4096x1 的矩阵里

e. 根据组号和DC值,计算出VLI和霍夫曼编码码长和。

JPEG图像压缩 matlab实现 - 图5

f. 我们对其余 63 列AC分量进行RLC编码。

首先,我们要得到这些AC分量的中间格式。假设 - 30 前面有 1 个 0,并且属于VLI编码表中的第五组,则其中间格式为: (1,5),-30。

注意,若连 0 超过 15,则记作 (15,0)。

g. 根据中间格式,计算总编码长度。

JPEG图像压缩 matlab实现 - 图6

(这个表是我根据 AC 亮度霍夫曼表整理的,可能有错误。如果需要使用该表,请务必校正)

JPEG图像压缩 matlab实现 - 图7

JPEG图像压缩 matlab实现 - 图8

压缩倍数约为 16.8。

峰值信噪比为 35.8。

  1. function LenaJPEG
  2. clear;close all;clc;
  3. %% Image Segmentation
  4. % lena512: 512*512
  5. % Block: 32768*8
  6. load('lenaXING.mat','lena512');
  7. Block=[];
  8. for numi=1:64 %逐行取方阵
  9. m=(numi-1)*8+1; %每块行的开头
  10. for numj=1:64 %逐列取方阵
  11. n=(numj-1)*8+1; %每块列的开头
  12. Block=[Block; lena512(m:m+7,n:n+7)];
  13. end
  14. end
  15. %% DCT
  16. % Block: 32768*8
  17. % FBlock: 32768*8
  18. for num=1:4096
  19. start=(num-1)*8+1;
  20. FBlock(start:start+7,:)=dct2(Block(start:start+7,:));
  21. end
  22. %% Quantization
  23. % FBlock: 32768*8
  24. % QBlock: 32768*8
  25. load('lenaXING.mat','lighttable');
  26. for num=1:4096
  27. start=(num-1)*8+1;
  28. QBlock(start:start+7,:)=round(FBlock(start:start+7,:)./lighttable);
  29. end
  30. %% Inverse Quantization
  31. % QBlock: 32768*8
  32. % reFBlock: 32768*8
  33. for num=1:4096
  34. start=(num-1)*8+1;
  35. reFBlock(start:start+7,:)=QBlock(start:start+7,:).*lighttable;
  36. end
  37. %% IDCT
  38. for num=1:4096
  39. start=(num-1)*8+1;
  40. Block(start:start+7,:)=idct2(reFBlock(start:start+7,:));
  41. end
  42. %% Image Reconstrucion
  43. relena512=[];
  44. for numi=1:64
  45. m=(numi-1)*512+1;
  46. % 分成64512*8阵列,每个阵列有648*8方阵
  47. A=[];
  48. for numj=1:64
  49. n=(numj-1)*8;
  50. A=[A Block(m+n:m+n+7,:)];
  51. end
  52. relena512=[relena512; A];
  53. end
  54. %% JPEG & JPEG2000 Figure
  55. figure();
  56. subplot(1,2,1);
  57. imshow(lena512./256);
  58. xlabel('Origin');
  59. subplot(1,2,2);
  60. imshow(relena512./256);
  61. xlabel('JPEG');
  62. suptitle('Origin vs. JPEG by XING');
  63. figure();
  64. subplot(1,2,1);
  65. imshow(relena512./256);
  66. xlabel('JPEG');
  67. subplot(1,2,2);
  68. lena2k = imread('lena512.bmp');
  69. imwrite(lena2k,'lena_16.8.j2k','CompressionRatio',16.8);
  70. imshow('lena_16.8.j2k')
  71. xlabel('JPEG2000');
  72. suptitle('JPEG vs. JPEG2000 by XING');
  73. %% PSNR
  74. delta=lena512-relena512;
  75. delta=delta.^2;
  76. MSE=sum(delta(:))/512/512;
  77. PSNR=10*log10(255^2/MSE);
  78. disp(['PSNR_JPEG: ',num2str(PSNR)]);
  79. lena16_8=imread('lena_16.8.j2k');
  80. delta=lena2k-lena16_8;
  81. delta=delta.^2;
  82. MSE=sum(delta(:))/512/512;
  83. PSNR=10*log10(255^2/MSE);
  84. disp(['PSNR_JPEG2000: ',num2str(PSNR)]);
  85. %% CODE
  86. % 以下只计算编码长度,不实际存储编码。
  87. %% ZIG-ZAG
  88. % QBlock: 32768*8
  89. % QLine: 4096*64
  90. QLine=[];
  91. load('lenaXING.mat','zigzag');
  92. zigzag = zigzag + 1; % 下标加1,从0开始
  93. for num=1:4096
  94. start=(num-1)*8+1;
  95. A=reshape(QBlock(start:start+7,:),1,64);% 变成行向量
  96. QLine=[QLine;A(zigzag)];
  97. end
  98. %% DPCM for DC
  99. % QLine: 4096*64
  100. % VLIDC: 4096*1
  101. % 对第一列进行DPCM编码,第一个值记为DC,并赋0
  102. DC=QLine(1,1);%保留备用
  103. sumcode=0;%计算编码长度
  104. QLine(1,1)=0;
  105. for num=4096:-1:2
  106. QLine(num,1)=QLine(num,1)-QLine(num-1,1);
  107. end
  108. VLIDC=ones(4096,1);% VLI分组
  109. for num=1:4096
  110. temp=abs(QLine(num,1));%用绝对值判断组别
  111. if temp==0
  112. VLIDC(num)=0;
  113. else
  114. for k=1:7%经测试,第一列最大值为80,前7组够用
  115. if (temp>=2^(k-1)) && (temp<2^k)
  116. VLIDC(num)=k;
  117. break;
  118. end
  119. end
  120. end
  121. end
  122. for num=1:4096
  123. %先根据DC亮度huffman表计算sumcode
  124. if (VLIDC(num)<=5) && (VLIDC(num)>=0)
  125. sumcode=sumcode+3;
  126. elseif VLIDC(num)==6
  127. sumcode=sumcode+4;
  128. else
  129. sumcode=sumcode+5;
  130. end
  131. %再根据VLI表计算sumcode
  132. sumcode=sumcode+VLIDC(num);
  133. end
  134. %DC计算结果为24096,比8*4096=32768小得多。
  135. %% RLC for AC
  136. % QLine: 4096*64
  137. % 经测试,后63列最大值为58VLI6组够用。
  138. eob=max(QLine(:))+1; %设一个超大值作为每一行结束符
  139. for numn=1:4096 %放eob
  140. for numm=64:-1:2
  141. if QLine(numn,numm)~=0
  142. QLine(numn,numm+1)=eob;
  143. break;
  144. end
  145. if (numm==2)%没找到
  146. QLine(numn,2)=eob;
  147. end
  148. end
  149. end
  150. test=QLine';
  151. [col,~]=find(test==eob);%我们只要eob列位置
  152. validAC=col-1; %每一行保留的AC数据量,含EOB
  153. maxcz=0;
  154. for numn=1:4096 %逐行计算并加至sumcode
  155. cz=[];%记录前0数
  156. VLIAC=[];%记录组号
  157. count=0;%记录连0数
  158. for numm=2:1+validAC(numn)
  159. if QLine(numn,numm)==eob
  160. cz=[cz 0];
  161. VLIAC=[VLIAC 0];
  162. elseif QLine(numn,numm)==0
  163. count=count+1;
  164. else %遇到非0值
  165. if count>15 %遇到连0大于15的
  166. cz=[cz 15];
  167. count=0;
  168. VLIAC=[VLIAC 0];
  169. continue;
  170. end
  171. cz=[cz count];
  172. count=0;
  173. temp=abs(QLine(numn,numm));%用绝对值判断组别
  174. for k=1:6%经测试,后63列最大值为58,前6组够用
  175. if (temp>=2^(k-1)) && (temp<2^k)
  176. VLIAC=[VLIAC k];
  177. break;
  178. end
  179. end
  180. end
  181. end%该行cz和VLIAC已定,开始计算
  182. sumcode=sumcode+4;%EOB对应1010,就是4bit
  183. czlen=length(cz)-1; %czlen不包括EOB
  184. load('lenaXING.mat','codelength');
  185. for k=1:czlen
  186. if VLIAC(k)==0
  187. sumcode=sumcode+11;
  188. else
  189. sumcode=sumcode+codelength(cz(k)+1,VLIAC(k));
  190. end
  191. end
  192. end
  193. %sumcode计算结果为124555。
  194. %% Compression Rate
  195. OB=512*512*8;
  196. CR=OB/sumcode;
  197. PD=sumcode/512/512;
  198. disp(['Original Bit: ',num2str(OB),' bit']);
  199. disp(['Compressed Bit: ',num2str(sumcode),' bit']);
  200. disp(['Compression Ratios: ',num2str(CR)]);
  201. disp(['Pixel Depth: ',num2str(PD),' bpp']);
  202. disp(' ——Calculated by XING');
  203. end