如云般飘过
调色师 / 剪辑师 / Mac重度用户/ 摄影爱好者
309 人赞同了该文章
由于视频是由一帧帧图像构成的,研究视频编码首先先要研究图像编码。这篇文章就详细说一下 JPEG 是如何压缩一个图像的。
先简单介绍一下 JPEG(Joint Photographic Experts Group,联合图像专家小组):此团队创立于1986年,其于1992年发布的 JPEG 标准在1994年获得了 ISO 10918-1 的认定,成为了图片压缩标准。
JPEG 压缩为有损压缩,下面介绍一下它的压缩算法。
首先 JPEG 文件是由 YUV 的色彩空间来表示颜色的,YUV 中 Y 表示明亮度(Luma),U 和 V 表示色度(Chrominance)和浓度(Chroma),UV 分量同时表示色差。
因为人眼对亮度的差异敏感度高于对色彩的变化。考虑到这种感知能力,允许降低色度以及浓度的带宽。YUV 的色彩空间更容易压缩 U、V 分量。
1.1 RGB 到 YUV 的转换 - 无损
RGB 转化 YUV 的公式(经过 PAL制式 CRT伽玛校正)如下:
Y = 0.299R’ + 0.587G’ + 0.114B'
U = -0.147R’ - 0.289G’ + 0.436B'
V = 0.615R’ - 0.515G’ - 0.100B'
未经伽玛校正(计算机色彩空间)的矩阵表示:
1.2 色度抽样-有损
在 YUV 采样的时候可以对 U、V 分量进行色度采样,在 JPEG 压缩算法采用的是 YUV 4:2:0 的色度抽样方法。
4:2:0 并非无 V 分量,它对于每行扫描的像素来说,只有一中色度分量以 2:1 的抽样率储存,相邻行储存不同的色度分量。可以理解为奇数行采样 U,YUV 4:2:0;偶数行采样 V,YUV 4:0:2。
YUV 4:2:0 的码流为:
Yo0 Uo0 Yo1 Yo2 Uo2 Yo3 Ye0 Ve0 Ye1 Ye2 Ve2 Ye3
映射成的四个像素为:
[Yo0 Uo0 Ve0] [Yo1 Uo0 Ve0] [Yo2 Uo2 Ve2] [Yo3 Uo2 Ve2] [Ye0 Uo0 Ve0] [Ye1 Uo0 Ve0] [Ye2 Uo2 Ve2] [Ye3 Uo2 Ve2]
YUV 4:2:0 的色度抽样率为 4:1,至此经历第一次压缩。
做好色彩空间转换和 YUV 4:2:0 色彩抽样后,将输入的图片分割成 8*8 像素的单元格。对每个单元格进行离散余弦变化。
以下面的图片作为例子,下图为 8*8 的只有 Y 分量的图形,其中亮度值为矩阵中的值:
数据来自 Wikipedia [1]
由于 DCT 变化需要定义域对称,在做 DCT 变化之前要先将矩阵中的数值左移 128,使得值域落在 -128~127:
到此,DCT 变化的准备工作已经完成。在进行 DCT 变化之前,先说一下 DCT 的原理。
信号学中,如果一个信号长度为8字节,则可以用8个不同频率的余弦波去表示它,形成频域编码。在图像中也是如此。
在 JPEG 算法中,图像被分为了 8*8 的像素组,每个像素组用自己的离散余弦变化进行频域编码。
顺带说一句,为什么选用 8*8 的像素组。采用比 8*8 更大的像素组,会大幅增加 DCT 的运算量,且编码质量也不会明显提升;采用比 8*8 更小的像素组会导致分组增多降低精度。所以8*8 的像素组是效率最优的结果。
这些像素组可以被 8*8 个余弦波精确表示,如下图所示有64个基本余弦波:
余弦波
这64个余弦波,可以组合成任意 8*8 的图形。我们只要用系数(系数表示每个单独的余弦波对整体图像所做的贡献)对这64个余弦波进行加权,就可以表示出任何的图形。
这个过程就是离线余弦变化,JPEG 中使用的是 DCT II 的公式。
根据 DTC II 的公式:
可以得出该图像在频域上的系数(经过取整,取值范围 -1024~1023):
经过 DCT 转换后的频率系数矩阵分别对应64个余弦波在 8*8 图形中的权重。可以看出,左上部分低频区的系数比较大,右下高频区的系数较小。鉴于人眼对高频区的识别不敏感,所以在下面量化部分可以舍弃一些高频区的数据。这里的 DCT 变化还没开始压缩。
在 DCT 变化后,舍弃高频区数据的过程称为量化。有两份量化表可供选择,分别为亮度量化表和色度量化表:
上表分别为亮度量化表和色彩量化表,表示 50% 的图像质量。这两张表中的数据基于人眼对不同频率的敏感程度制定。
量化表是控制 JPEG 压缩比的关键,可以根据输出图片的质量来自定义量化表,通常自定义量化表与标准量化表呈比例关系,表中数字越大则质量越低,压缩率越高。PhotoShop 有12张量化表。
量化过程为,使用量化矩阵与前面得到的 DCT 矩阵逐项相除并取整。之前为亮度矩阵,顾使用亮度量化表:
量化是有损的,在解码时,反量化会乘回量化表的相应值。由于存在取整,低频段会有所损失,高频段的0字段则会被舍弃,最终导致图像质量降低。
得到量化后的矩阵就要开始编码过程了,首先要把二维矩阵变为一维数组,这里采用了 zigzag 排列,将相似频率组在一起:
zigzag [2]
得出的序列为:
霍夫曼编码中,在 JPEG 有个 EOB(End Of Block) 字段,表示从字段开始后面全为0,然后再根据霍夫曼编码再进行压缩。
至此,这个亮度 8*8 的像素组压缩编码完毕。
将图像每个 8*8 像素组进行编码就可以压缩整个图像了。
关于 JPEG 编码的内容就写到这里,如有错误或遗漏,欢迎在评论区指正。
以后也会在这个新分类下写一些其他视频编码,如果大家有其他内容想了解,也可以写在评论里。
没有微信公众号,只在专栏里写些东西,顺便自己也可以学习,欢迎关注。
[1] JPEG-Wikipedia
[2] JPEG 标准 | itu-t81.pdf
编辑于 2018-07-27 19:13