4. 预测编码(上):帧内预测原理,H264的9种Intra 4x4模式与DC模式
各位同学,今天我们进入视频编码里最核心的一个环节——预测编码。说白了,预测编码就是「猜」。编码器不直接存像素值,而是先猜这个像素大概是多少,然后只存「猜错了多少」。这个差值通常很小,压缩起来就特别省空间。
我刚开始接触编码时,觉得这玩意儿挺玄乎。后来自己动手写了一个简易的帧内预测模块,才真正理解——帧内预测的本质,就是用已经编好的像素,去推算还没编的像素。
4.1 为什么需要帧内预测?
先想一个问题:一张纯蓝色的天空图片,每个像素都是 (0, 0, 255)。如果直接存每个像素的值,数据量很大。但如果我只存第一个像素,然后告诉解码器「后面每个像素都和前面一样」,那后面的像素只需要存一个「和前面相同」的标记,是不是省了很多?
帧内预测就是这个思路的升级版。它不只在水平方向复制,而是支持多个方向——斜着、竖着、甚至取平均值。
4.2 H.264 的 Intra 4x4 预测:9 种方向模式
H.264 针对 4x4 大小的块,定义了 9 种预测模式。为什么是 4x4?因为小块能更好地适应图像细节——纹理变化剧烈的地方,用小块预测更准。
这 9 种模式里,有 8 种是方向预测,1 种是 DC 模式(平均值模式)。我习惯把它们分成三类来记:
- 水平类: 模式 1(水平预测)
- 垂直类: 模式 0(垂直预测)
- 对角线类: 模式 3~8(各种斜向预测)
- 平面类: 模式 2(DC 模式)
下面这张图,是我当年学习时自己画的,能帮你直观理解这 9 种模式的预测方向:
4.3 方向预测的直觉理解
方向预测到底怎么工作的?我举个例子你就明白了。
假设当前要预测 4x4 块里第 0 行第 0 列的像素(左上角第一个)。
- 模式 0(垂直预测): 直接用正上方那个像素的值。如果上方像素是 128,那这个像素就预测为 128。
- 模式 1(水平预测): 直接用左边那个像素的值。
- 模式 4(右下对角线预测): 沿着 45 度方向,用左上角的像素来预测。
你想想看,如果图像里有一条斜着的边缘,用模式 4 去预测,残差就会非常小。但如果用垂直预测,边缘处就会产生很大的误差。
4.4 DC 模式:最稳妥的「平均主义」
DC 模式是 9 种模式里最特殊的一个。它不沿任何方向预测,而是取上方和左侧参考像素的平均值。
公式很简单:
// 假设上方有 4 个参考像素 A0, A1, A2, A3
// 左侧有 4 个参考像素 B0, B1, B2, B3
// DC 值 = (A0 + A1 + A2 + A3 + B0 + B1 + B2 + B3 + 4) / 8
// 加 4 是为了四舍五入
uint8_t dc_value = (sum_above + sum_left + 4) >> 3;
DC 模式的好处是——它永远不会太差。即使方向预测全部猜歪,DC 模式至少能给出一个「平均水准」的预测。我在做移动端编码器时,经常把 DC 模式作为默认模式,因为它的计算量最小,硬件实现也最简单。
4.5 9 种模式的完整列表
为了方便你查阅,我把 9 种模式整理成了一张表:
| 模式编号 | 模式名称 | 预测方向 | 适用场景 |
|---|---|---|---|
| 0 | 垂直 | 从上到下 | 水平纹理 |
| 1 | 水平 | 从左到右 | 垂直纹理 |
| 2 | DC | 平均值 | 平坦区域 |
| 3 | 左下对角线 | 45° 左下 | 右上到左下边缘 |
| 4 | 右下对角线 | 45° 右下 | 左上到右下边缘 |
| 5 | 垂直偏右 | 偏右 22.5° | 接近垂直的斜边 |
| 6 | 水平偏下 | 偏下 22.5° | 接近水平的斜边 |
| 7 | 垂直偏左 | 偏左 22.5° | 接近垂直的斜边(反向) |
| 8 | 水平偏上 | 偏上 22.5° | 接近水平的斜边(反向) |
4.6 帧内预测的完整流程
最后,我把帧内预测在编码器里的完整流程梳理一下。嗯,这里要注意,预测只是第一步,后面还有变换、量化、熵编码。但今天我们只聚焦预测部分:
- 获取参考像素: 从当前块的上方和左侧,取出已经重建好的像素。
- 遍历预测模式: 对 9 种模式(4x4 块)或 4 种模式(16x16 块),分别计算预测块。
- 计算残差: 原始像素减去预测像素,得到残差块。
- 选择最优模式: 用率失真优化(RDO)选残差最小、码率最低的模式。
- 编码模式信息: 把选中的模式编号写入码流,解码器用同样的方式重建。
好了,帧内预测的原理和 H.264 的 9 种 Intra 4x4 模式就讲到这里。方向预测的直觉其实很简单——沿着图像纹理的方向去猜,猜中的概率最大。DC 模式则是「实在不行就取平均」,虽然不惊艳,但永远不会翻车。