JPEG 编码原理概述

本文简要概述 JPEG 基本系统的编码流程。

编码需要经过 DCT、量化、Z 序列化、系数编码(DC 差分脉冲调制编码、DC 系数中间格式计算、AC 差分脉冲调制编码、AC 系数中间格式计算)、熵编码五个步骤,最后按指定格式进行封装,成为一张 JPEG 图片。

图片被分割为若干 8×8 块后,每个块进行离散余弦变换(DCT),其目的是将图像块按频率分解,得到其频谱。

类似傅里叶变换,DCT 的目的是将图像分解为不同频率的基本分量的线性组合。

事实上,DCT 是 DFT 抹去虚(奇)部的特殊形式。由于实偶函数的 DFT 仍然是实偶函数,我们将时域函数倍增延拓成偶函数,于是频域也成为实偶函数。当然在存储时可以折半以消除冗余。

为何要求 DCT?对每一个图像块,如果一定要舍弃,我们会尽可能多保留其低频分量,而降低高频分量的分辨率。同时,高频分量通常也的确是较少的,而直流分量,虽然数值大,但相邻块的直流分量差别较小。

因此我们对低频分量取较低的量化系数,而对高频分量取较高的量化系数。

所谓量化,就是将浮点(实现上可能只是以更高精度的整数表示形式存在)值 x 转化为阶跃的整数值 y 表示的过程,而 y=round(x/q) 中的 q 就是量化系数。

随后我们进行 Z 序列化,将二维矩阵按 Z 形拍扁成向量。

考虑到相邻块 DC 分量差异小,我们首先将 DC 分量与上一个块做差。这个过程称为差分脉冲调制编码。

如今,向量中存在大量的 0,而绝对值小的数字出现的概率也远大于绝对值大者。

我们采用行程编码(RLE),将序列切成形如 0,0,…,0,x 的若干段,每段由 y(≥0) 个 0 和一个 x(>0) 组成,记作 (y,len(x),x),其中 len(x) 是 x 在反码二进制表示下的长度。这种三元组表示形式称为中间格式。

(注:这里图上将 DC 分量也一把揉进去了,严格来说是分开的,RLE 只考虑 AC 分量)

现在考虑 (y,l,x) 三元组的编码。我们用一个字节的高 4 位和低 4 位分别存放 y,l 两个 uint4,并对这个字节进行哈夫曼编码。至于 x,一个小多大少的家伙,还被记录了长度,就直接写进二进制流里好了。

需要指出,这里我们略去了一些特殊情况。比如连续 0 的个数超过 15 该如何处理,AC 分量末尾的若干个 0 该如何处理。这些细节处理或许结合代码阅读,理解会更加深刻。

原文地址:https://www.cnblogs.com/mollnn/p/15111954.html