首发于造轮者说
花一天写了个JPEG解码器,来整理一下JPEG格式的原理

花一天写了个JPEG解码器,来整理一下JPEG格式的原理

昨天花了一天的时间试着写了一下JPEG解码器,虽然遇到了一些麻烦,不过最后还是成功地解出了图像的数据。总共400行代码左右。

(解码的核心也就这50行左右,因为只是验证一下以前了解的信息,所以看起来还是有点乱,而且没有做各种错误处理,所以不要太在意啦┑( ̄Д  ̄)┍)

下面是JPEG的编码过程的整理(因为编码和解码是完全对称的所以就只说编码,解码可以自行脑补)(仔细看的话都能在上面那段代码中找到对应哦):


(图片自制) RGB转YCbCr:因为人眼对亮度比较敏感,而对于色度不那么敏感,所以,我们就先将RGB的数据转换到YCbCr色彩空间,便于下面的处理。


降采样:转到YCbCr色彩空间后,就可以将 Cb 和 Cr 这两个通道进行降采样,这里一般是将 2*2 个像素变为 1*1 个像素,虽然分辨率下降到了四分之一,但对于人眼来说差别是不大的。(这一步是有损的)

分块:顾名思义,将图像分为若干个 8*8 的小块,方便下面的处理。

DCT:这一步的目的和RGB转YCbCr有一些相似之处,都是将人眼较为敏感和不敏感的部分进行分离,然后就可以对减少人眼不敏感的部分的信息量。在这一步中,DCT可以将图像的低频(人眼敏感)和高频(人眼不敏感)部分进行分离。这样得到的结果是每个 8*8 小块得到 8*8 的系数矩阵。


量化:将DCT后得到的每个系数都除以量化矩阵中对应的值,然后进行取整。通常来说频率较高的部分对应的量化参数比较大,这样一来就能够在较好地保留图像的低频部分并去除一些高频部分。这一步下来得到的矩阵中高频部分几乎全部变为0,这也为进一步的操作提供了便利。值得注意的是,JPEG中压缩率的调整是在这一步中,量化参数越大,压缩后的大小就会越小,但信息的损失也就越多,图片的失真也会更严重。(这一步是有损的)

Huffman编码:准确地说是Huffman编码和RLE,将上一步得到的矩阵进行进一步地压缩(这一步是无损的)。量化后得到的矩阵左上角的那个数比其他数来得大得多,所以我们将它单独拿出来进行编码,称之为直流分量(DC),将剩下的称之为交流系数(AC)。这一步会将矩阵按照 zigzag 的顺序摊成一维,如下图所示:

\left[ \begin{matrix} DC & AC_{1} & AC_{5} & AC_{6} & AC_{14} & AC_{15} & AC_{27} & AC_{28} & \\ AC_{2} & AC_{4} & AC_{7} & AC_{13} & AC_{16} & AC_{26} & AC_{29} & AC_{42} & \\ AC_{3} & AC_{8} & AC_{12} & AC_{17} & AC_{25} & AC_{30} & AC_{41} & AC_{43} & \\ AC_{9} & AC_{11} & AC_{18} & AC_{24} & AC_{31} & AC_{40} & AC_{44} & AC_{53} & \\ AC_{10} & AC_{19} & AC_{23} & AC_{32} & AC_{39} & AC_{45} & AC_{52} & AC_{54} & \\ AC_{20} & AC_{22} & AC_{33} & AC_{38} & AC_{46} & AC_{51} & AC_{55} & AC_{60} & \\ AC_{21} & AC_{34} & AC_{37} & AC_{47} & AC_{50} & AC_{56} & AC_{59} & AC_{61} & \\ AC_{35} & AC_{36} & AC_{48} & AC_{49} & AC_{57} & AC_{58} & AC_{62} & AC_{63} & \\ \end{matrix} \right] \rightarrow \left[ DC \right] \left[ AC_{1}, AC2, AC3, ... \right]

这样做的好处是矩阵的高频部分(右下角)会被安排在后面,因为它们基本上全是0,所以在编码中有一个特殊的标记表示这之后的系数全是0,从而减少压缩后的大小。

(话说回来,Huffman解码这一步应该是解码中最麻烦的一部分……位的顺序搞了好久)

上面这些步骤完成之后,再加上一些必要的其他信息(量化矩阵和Huffman的信息,这两个是直接没有压缩就存储在文件中的),就得到了最终的JPEG数据。

暂时先整理这么多,以后有时间再认真写一下解码器,争取某一天能够达到 libjpeg 的水平吧 :) (以后应该会包含在 Medicat 中←某个妄图把各种图像/音频格式都自己实现一遍的轮子)



参考:

w3.org/Graphics/JPEG/it

en.wikipedia.org/wiki/J

编辑于 2018-01-01

文章被以下专栏收录