来源:papers/iVc/DVC_答疑03_H264核心流程与算法.md · 原始 Markdown
DVC|H.264 流程与算法
用户问题:讲完他,适当讲解算法
来源:本聊天
01a13ae4-6cb2-7f23-b09c-942490bf8387,公开回复记录第 218 行,2026-10-15 00:06:22 +08:00。可核实定位:分块、SAD、变换、量化、熵编码、RDO、重建与I/P/B。
原进度消息中的实质性补充(记录第 205 行)
需要特别分清:预测、变换和熵编码各有不同作用;量化才是这条流程中引入损失的主要环节。我会用数字例子说明这些步骤,再把它们连成完整的编解码流程。
可以。下面把 H.264 的核心编解码流程讲完整,并穿插必要的算法,让你能看懂它与 DVC 的对应关系。
上一题的答案是:残差为 108-100=8;如果解码出的残差为 6,重建值就是 100+6=106。
先统一三个符号:X 表示原始图像块,P 表示预测块,E=X-P 表示残差。下面主要以亮度像素为例。
- 先把图像分成块,分别处理不同区域。
一幅图像中,背景可能静止,人物可能运动,人物的手和身体还可能往不同方向运动。因此,编码器需要在局部区域选择合适的预测方法。
H.264 以包含 16\times16 个亮度像素的宏块作为基本组织单位。运动补偿时,可以进一步使用 16\times8、8\times16、8\times8 等分块,最小可到 4\times4。
大块需要描述的运动信息少,小块能更细致地适应局部运动,却需要更多分块和运动信息。如何分块,本身也是压缩中的选择题。 帧间预测与分块说明
- 帧内预测:利用同一帧中已经重建的邻居。
假设一个块上方的四个像素是:
text
100 102 104 103
如果当前区域主要沿竖直方向保持相似,可以把这行数值向下复制,作为整个块的预测。这叫竖直预测。
其他方法包括从左侧向右复制的水平预测、使用邻居平均值的 DC 预测,以及沿不同方向延伸的预测。
编码器尝试不同预测方式,选出合适的一种,然后编码:
E=X-P
接收端根据传来的预测模式,用相同的邻居生成 P,再加上解码出的残差。
帧内编码也有预测,也需要残差。 它利用的是当前帧内部的信息。帧内预测说明
- 帧间预测:先搜索运动,再根据运动取出预测块。
对当前块,编码器到已经重建的参考图像里寻找相似区域。两个位置之间的偏移,用运动向量表示:
v=(d_x,d_y)
一个基础搜索方法是比较候选块与当前块的 SAD,即绝对差之和:
\operatorname{SAD}(d_x,d_y) =\sum_{i,j} \left|X(i,j)-P_{d_x,d_y}(i,j)\right|
SAD 越小,候选块越接近当前块。教学用的穷举搜索可以写成:
```text 最小误差 = 无穷大
遍历搜索范围内所有合法偏移 (dx, dy): 从参考图像取出候选块 误差 = 当前块与候选块的绝对差之和
如果误差更小:
保存这个误差
保存偏移 (dx, dy)
返回保存的偏移 ```
寻找偏移叫运动估计;根据偏移生成预测块叫运动补偿。
穷举搜索计算量很大,实际编码器会采用更快的搜索策略,并考虑运动信息所需的比特数。H.264 亮度运动补偿还支持 1/4 像素精度:小数位置的像素通过插值得到。
运动向量本身也可以预测。例如邻块预测的向量为 (9,2),当前向量为 (10,2),就可以传输差值 (1,0)。亚像素补偿与运动向量预测
- 变换:把残差换成更容易压缩的表示。
相邻残差也可能相似。我们可以把它们分解成“整体变化”和“局部差异”。
用两个数演示:
E=[10,12]
做一个简单的求和、求差变换:
T=[10+12,\ 10-12]=[22,-2]
第一个数描述整体水平,第二个数描述两个位置的差异。如果原来是 [10,10],变换后就是 [20,0],差异项变成了零。
这里使用的是教学变换。H.264 常用的 4\times4 变换采用整数运算,是对 DCT 的近似;其核心运算可以通过加法和移位高效完成。H.264 变换设计论文
变换本身没有减少数值的数量;它为后面的量化和熵编码创造条件。
- 量化:用近似值换取更少的编码数据。
一个简化的量化模型是:
q=\operatorname{round}(T/\Delta)
其中 \Delta 是量化步长。接收端进行反量化:
\hat T=q\Delta
接着刚才的例子,令 \Delta=5:
[22,-2]\rightarrow[4,0]\rightarrow[20,0]
原来的细微差异丢失了。通过逆变换:
\hat E= \left[ \frac{20+0}{2}, \frac{20-0}{2} \right] =[10,10]
残差从 [10,12] 变成了 [10,10]。
H.264 使用量化参数 QP 控制量化粗细。对于常见的 8 位编码,亮度 QP 通常在 0~51;QP 每增加 6,量化步长加倍。QP 越大,通常码率越低、失真越大。实际运算还包含缩放和舍入规则,上面的除法模型用于理解原理。变换与量化说明
- 熵编码:把符号无损地变成比特。
量化后,经常出现大量零和小数值。如果每个符号都用同样长的编码,会浪费空间。熵编码利用符号的概率,让常见情况占用更少的平均比特。
H.264 中两种重要的方法是 CAVLC 和 CABAC。CABAC 可以从三个步骤理解:
- 把系数、运动差值等信息转换成二元决策。
- 根据邻近已编码信息等“上下文”,选择和更新概率模型。
- 使用二进制算术编码,将这些决策编码成比特流。
算术编码可以理解为不断缩小一个数值区间:概率大的结果分到较大的子区间,概率小的结果分到较小的子区间,最终用足够的比特指出落在哪个区间。
熵编码能够精确恢复输入符号。它不会修复量化丢失的信息,也不会进一步损失这些符号。 CABAC 设计者的算法说明
- 率失真优化:决定采用哪一种编码方案。
编码器面临许多选择:怎样分块、选哪个参考图像、使用哪种预测模式,以及量化多粗。
一个常用的目标是:
J=D+\lambda R
D 是重建失真,R 是需要的比特数,\lambda 控制比特成本的权重。编码器比较候选方案,倾向选择 J 更小的方案。
看一个自设例子:
| 方案 | 失真 D | 比特数 R |
|---|---|---|
| A | 10 | 100 |
| B | 20 | 20 |
当 \lambda=0.1,A 的成本为 20,B 为 22,选择 A。
当 \lambda=1,A 的成本为 110,B 为 40,选择 B。
所以,残差更小的预测方案,可能因为运动或模式信息太贵,整体反而不划算。 这就是率失真优化的作用。率失真编码器控制研究
- 编码器也要重建图像,再把它作为后续参考。
延续数字例子:原始像素为 [110,112],预测为 [100,100],解码残差为 [10,10],那么重建结果是:
\hat X=P+\hat E=[110,110]
接收端得到的是这个结果。因此,编码器预测后续图像时,也必须从同样的重建信息出发。
编码器内部会执行反量化、逆变换和重建。H.264 还对重建图像应用环内去块滤波,减轻分块处理造成的边界伪影;滤波后的图像可以用于后续帧间预测。H.264 总览中的重建与环内滤波
下面这张图体现了编码器中的两个分支:
mermaid
flowchart TB
A["原始块 X"] --> B["减去预测块 P"]
P["由已重建信息生成预测 P"] --> B
B --> C["残差:变换 → 量化"]
C --> D["熵编码"]
D --> E["输出比特流"]
C --> F["反量化 → 逆变换"]
F --> G["解码残差"]
G --> H["加上预测 P"]
P --> H
H --> I["重建与环内滤波"]
I --> J["存储,供后续帧间预测"]
- 最后把这些块放回视频序列,理解 I、P、B 的作用。
入门时,可以这样理解:
| 类型 | 主要允许的预测方式 |
|---|---|
| I | 使用当前图像内部的信息 |
| P | 可以使用已解码参考图像,也可以使用帧内预测 |
| B | 可以使用两组参考列表,并组合两份预测,也可以使用帧内预测 |
常见 B 帧例子是同时参考播放顺序中前面和后面的帧。假设播放顺序是:
text
I0 → B1 → B2 → P3
如果 B1、B2 都依赖 P3,那么可以先解码:
text
I0 → P3 → B1 → B2
再按播放顺序输出。因此,解码顺序和播放顺序可以不同。严格说,I/P/B 是切片类型;把它们当作帧类型,是入门时常用的简化。参考关系与图像顺序说明
你现在回到 DVC,可以直接对照这些模块:
| 已经理解的作用 | DVC 中的实现 |
|---|---|
| 搜索运动、生成预测 | 光流估计与运动补偿网络 |
| 表示和压缩运动信息 | 运动编码器、解码器 |
| 变换和恢复残差 | 残差编码器、解码器 |
| 估计编码成本 | 学习潜变量的概率分布 |
| 平衡码率与失真 | 用率失真损失联合训练 |
DVC 写的是 L=\lambda D+R,上面讲的是 J=D+\lambda R,权重放的位置不同。对正的权重而言:
\lambda D+R =\lambda\left(D+\frac{1}{\lambda}R\right)
所以 DVC 的 \lambda 越大,越重视画质;上面 D+\lambda R 中的 \lambda 越大,越重视省比特。阅读公式时,要先看权重乘在哪一项上。
这些对应关系见原文:DVC 主论文