91 lines
5.2 KiB
Markdown
91 lines
5.2 KiB
Markdown
---
|
|
title: "JPEG算法解密(三)"
|
|
tags: 压缩 图像 程序 算法
|
|
---
|
|
# JPEG算法解密(三)
|
|
|
|
### 步骤四:数据量化
|
|
----
|
|
经过上一节介绍的离散余弦变换,图像数据虽然已经面目全非,但仍然是处于“可逆”的状态,也就是说我们还没有进入“有损”的那一步。这次我们来玩真的,看一下数据中的细节是如何被滤去的。先来考察一下要对付的问题是什么,经过颜色空间转换和离散余弦变换,每一个8X8的图像块都变成了三个8X8的浮点数矩阵,分别表示Y,Cr,Cb数据,比如以其中某个亮度数据矩阵举例,它的数据如下
|
|
$$
|
|
\small{G=\begin{bmatrix}
|
|
-415.38 & -30.19 & -61.20 & 27.24 & 56.12 & -20.10 & -2.39 & 0.46 \\
|
|
4.47 & -21.86 & -60.76 & 10.25 & 13.15 & -7.09 & -8.54 & 4.88 \\
|
|
-46.83 & 7.37 & 77.13 & -24.56 & -28.91 & 9.93 & 5.42 & -5.65 \\
|
|
-48.53 & 12.07 & 34.10 & -14.76 & -10.24 & 6.30 & 1.83 & 1.95 \\
|
|
12.12 & -6.55 & -13.20 & -3.95 & -1.87 & 1.75 & -2.79 & 3.14 \\
|
|
-7.73 & 2.91 & 2.38 & -5.94 & -2.38 & 0.94 & 4.30 & 1.85 \\
|
|
-1.03 & 0.18 & 0.42 & -2.42 & -0.88 & -3.02 & 4.12 & -0.66 \\
|
|
-0.17 & 0.14 & -1.07 & -4.19 & -1.17 & -0.10 & 0.50 & 1.68 \\
|
|
\end{bmatrix}
|
|
}
|
|
$$
|
|
我们的问题是,在可以损失一部分精度的情况下,如何用更少的空间存储这些浮点数?答案是使用量子化(Quantization),简称量化。“量子”这个概念来自于物理学,意思是说连续的能量可以看做是一个个单元体的组合,很简单,比如游戏中在处理角色面朝方向时,往往不是使用0到2π这样的32bit浮点数,而是把方向分成16个区间,用0到16这样的整数来表示,这样只用4个bit就足够了。JPEG提供的量子化算法如下:
|
|
$$
|
|
B_{i,j}=round\left(\frac{G_{i,j}}{Q_{i,j}}\right)\quad i,j=0,1,2,\cdots,7\tag{3.1}
|
|
$$
|
|
其中G是我们需要处理的图像矩阵,Q称作量化系数矩阵(Quantization matrices),JPEG算法提供了两张标准的量化系数矩阵,分别用于处理亮度数据Y和色差数据Cr以及Cb。
|
|
$$\begin{aligned}
|
|
Q_{luminance} &= \small{\begin{bmatrix}
|
|
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 \\
|
|
\end{bmatrix}
|
|
}\\
|
|
Q_{chrominance}&=\small{\begin{bmatrix}
|
|
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 \\
|
|
\end{bmatrix}}
|
|
\end{aligned}
|
|
$$
|
|
其中round函数是取整函数,但考虑到了四舍五入,也就是说
|
|
$$
|
|
round(r) =
|
|
\begin{cases}
|
|
& \cdots \\
|
|
2 & \text{when } 1.5 \leq r < 2.5 \\
|
|
1 & \text{when } 0.5 \leq r < 1.5 \\
|
|
0 & \text{when } -0.5 \leq r < 0.5 \\
|
|
-1 & \text{when } -1.5 \leq r < -0.5 \\
|
|
-2 & \text{when } -2.5 \leq r < -1.5 \\
|
|
& \cdots
|
|
\end{cases}\tag{3.2}
|
|
$$
|
|
比如上面数据,以左上角的-415.38为例,对应的量子化系数是16,那么
|
|
$$
|
|
round(-415.38/16)=round(-25.96125)=-26
|
|
$$
|
|
最终得到的量化后的结果为
|
|
$$
|
|
\small{
|
|
\begin{bmatrix}
|
|
-26 & -3 & -6 & 2 & 2 & -1 & 0 & 0 \\
|
|
0 & -2 & -4 & 1 & 1 & 0 & 0 & 0 \\
|
|
-3 & 1 & 5 & -1 & -1 & 0 & 0 & 0 \\
|
|
-3 & 1 & 2 & -1 & 0 & 0 & 0 & 0 \\
|
|
0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
|
|
0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
|
|
0 & 0 & 0 & 0 & 0 & 0 & 0 & 0
|
|
\end{bmatrix}
|
|
}
|
|
$$
|
|
可以看到,一大部分数据变成了0,这非常有利于后面的压缩存储。这两张神奇的量化表也是有讲究的,还记得我们在第一节中所讲的有损压缩的基本原理吗,有损压缩就是把数据中重要的数据和不重要的数据分开,然后分别处理。DCT系数矩阵中的不同位置的值代表了图像数据中不同频率的分量,这两张表中的数据时人们根据人眼对不不同频率的敏感程度的差别所积累下的经验制定的,一般来说人眼对于低频的分量必高频分量更加敏感,所以两张量化系数矩阵左上角的数值明显小于右下角区域。在实际的压缩过程中,还可以根据需要在这些系数的基础上再乘以一个系数,以使更多或更少的数据变成0,我们平时使用的图像处理软件在生成jpg文件时,在控制压缩质量的时候,就是控制的这个系数。
|
|
在进入下一节之前,矩阵的量化还有最后一步要做,就是把量化后的二维矩阵转变成一个一维数组,以方便后面的霍夫曼压缩,但在做这个顺序转换时,需要按照一个特定的取值顺序。
|
|
|
|

|
|
|
|
这么做的目的只有一个,就是尽可能把0放在一起,由于0大部分集中在右下角,所以才用这种由左上角到右下角的顺序,经过这种顺序变换,最终矩阵变成一个整数数组
|
|
-26,-3,0,-3,-2,-6,2,-4,1,-3,0,1,5,,1,2,-1,1,-1,2,0,0,0,0,0,-1,-1,0,0,0,0,…,0,0
|
|
后面的工作就是对这个数组进行再一次的哈夫曼压缩,已得到最终的压缩数据。
|
|
|