一、背景回顾:什么是传统角度预测?
在 VVC(Versatile Video Coding, H.266)标准中,帧内预测是提升编码效率的核心技术之一。其中:
- 共定义了67 种帧内预测模式
- 模式 0:
Planar(平面预测) - 模式 1:
DC(均值预测) - 模式 2~66:65 种传统角度预测模式
- 模式 0:
这些角度模式覆盖从-135° 到 +45°的方向范围,用于模拟图像中不同走向的边缘结构(如水平线、斜边、轮廓等)。
分类方式
| 类型 | 模式编号 | 特点 |
|---|---|---|
| 水平类模式 | 2 ~ 33 | 预测方向近似垂直传播 → 主要使用上方参考像素 |
| 垂直类模式 | 34 ~ 66 | 预测方向近似水平传播 → 使用左侧 + 上方参考像素 |
⚠️ 注意:“垂直类”并非指预测方向为垂直,而是指每一行的像素沿横向生成,即“逐列填充”,像画竖线一样向右扩展。
本节以垂直类模式 M = 30(偏移值 offset = -20)为例,深入解析其预测流程中的关键两步。
二、整体流程简述
对于一个N×N N \times NN×N的亮度编码单元(CU),传统角度预测的基本流程如下:
构造参考像素数组
Ref[]
整合左侧(Left)、左上(Top-Left)、上方(Top)已重建像素,形成一条长度为2×max(N,N)+1 2 \times \max(N,N) + 12×max(N,N)+1的一维参考线。计算当前像素对应的参考位置整数偏移量:
ildx=(y⋅offset[M])≫5 \text{ildx} = (y \cdot \text{offset}[M]) \gg 5ildx=(y⋅offset[M])≫5计算分像素插值权重:
w=(y⋅offset[M])& 31 w = (y \cdot \text{offset}[M]) \&\ 31w=(y⋅offset[M])&31根据
ildx和w查找或插值得到预测值
下面我们重点讲解第(2)步和第(3)步。
三、步骤(2)详解:计算整数偏移量ildx
公式表达:
ildx=(y⋅offset[M])≫5 \text{ildx} = (y \cdot \text{offset}[M]) \gg 5ildx=(y⋅offset[M])≫5
等价于:
ildx=⌊y⋅offset[M]32⌋ \text{ildx} = \left\lfloor \frac{y \cdot \text{offset}[M]}{32} \right\rfloorildx=⌊32y⋅offset[M]⌋
参数说明:
| 符号 | 含义 |
|---|---|
| y yy | 当前像素在 CU 内的行索引(从上到下,起始于 0) |
| offset[M] \text{offset}[M]offset[M] | 查表得到的角度偏移参数(见后文表) |
| ≫5 \gg 5≫5 | 右移 5 位,相当于除以25=32 2^5 = 3225=32,实现快速整数除法 |
物理意义:
该值表示:当前第 y 行的预测起点相对于基准位置 TL 的整数级偏移量。
由于每个角度模式都有固定的“斜率”,越往下(y 越大),需要读取的参考像素就越靠左(当 offset < 0)或靠右(当 offset > 0)。
这是一种将连续空间投影离散化的方法,使得硬件友好的整数运算即可完成高精度的方向控制。
示例:8×8 CU,模式 M=30,offset = -20
我们手动计算每一行的ildx值:
| y yy | 计算式 | 结果(ildx) |
|---|---|---|
| 0 | (0×−20)≫5=0 (0 \times -20) \gg 5 = 0(0×−20)≫5=0 | 0 |
| 1 | (−20)≫5=−20/32≈−0.625 (-20) \gg 5 = -20 / 32 \approx -0.625(−20)≫5=−20/32≈−0.625→ 向下取整 | -1 |
| 2 | (−40)≫5=−1.25 (-40) \gg 5 = -1.25(−40)≫5=−1.25→ -2? 实际为 -1 或 -2? | 视实现而定 |
| 3 | (−60)≫5=−1.875 (-60) \gg 5 = -1.875(−60)≫5=−1.875→ -2 | |
| 4 | (−80)≫5=−2.5 (-80) \gg 5 = -2.5(−80)≫5=−2.5→ -3 |
✅ 实际标准中采用向负无穷取整(floor division)来保证跨平台一致性。
在 C++ 中可通过添加偏移修正负数右移行为:intdiff=y*offset;intildx=(diff+(diff<0?-31:0))>>5;
四、步骤(3)详解:计算分像素位置权重w
公式表达:
w=(y⋅offset[M])& 31 w = (y \cdot \text{offset}[M]) \&\ 31w=(y⋅offset[M])&31
参数说明:
| 符号 | 含义 |
|---|---|
| y⋅offset[M] y \cdot \text{offset}[M]y⋅offset[M] | 总偏移量(带符号整数) |
| & 31 \&\ 31&31 | 按位与操作,提取低 5 位 → 相当于对 32 取模(mod 32) |
物理意义:
虽然ildx给出了整数位置,但真实的采样点往往落在两个像素之间(例如介于ref[i]和ref[i+1]之间)。这时就需要进行亚像素插值。
w=0 w = 0w=0:正好落在整数像素上 → 直接取ref[i]
w≠0 w \neq 0w=0:位于两个像素之间 → 使用双线性插值
pred(x,y)=(32−w)⋅ref[i]+w⋅ref[i+1]+1632 \text{pred}(x,y) = \frac{(32 - w) \cdot \text{ref}[i] + w \cdot \text{ref}[i+1] + 16}{32}pred(x,y)=32(32−w)⋅ref[i]+w⋅ref[i+1]+16
其中加16是为了实现四舍五入。
插值精度达到1/32 像素,这是 VVC 实现高预测精度的关键设计之一。
示例:继续以y=2,offset=−20 y=2, \text{offset}=-20y=2,offset=−20为例
计算:
y⋅offset=2×(−20)=−40 y \cdot \text{offset} = 2 \times (-20) = -40y⋅offset=2×(−20)=−40
ildx=(−40)≫5=−2 \text{ildx} = (-40) \gg 5 = -2ildx=(−40)≫5=−2(假设 floor division)
w=(−40)& 31 w = (-40) \&\ 31w=(−40)&31
如何计算负数的按位与?
在补码系统中(如 x86 架构):
- -40 的二进制(32位)为:
11111111111111111111111111011000 - 低 5 位为:
11000₂ =2410 24 ₁₀2410
✅ 所以:
w=24 w = 24w=24
这意味着:实际采样点位于ref[i]和ref[i+1]之间,更靠近后者(权重更大)。
代入插值公式:
pred=(32−24)⋅ref[i]+24⋅ref[i+1]+1632=8a+24b+1632 \text{pred} = \frac{(32 - 24)\cdot \text{ref}[i] + 24 \cdot \text{ref}[i+1] + 16}{32} = \frac{8a + 24b + 16}{32}pred=32(32−24)⋅ref[i]+24⋅ref[i+1]+16=328a+24b+16
≈ 75% 权重来自右边像素。
五、图示还原:图4.12 解析(8×8 CU,模式 M=30)
正确理解投影像素法(Projection Method)
对于垂直类模式 M=30(offset = -20),其预测方向是从左上往右下倾斜(负斜率),因此:
- 第 0 行(y=0):起始于 TL(index=8)
- 第 1 行(y=1):起始于 L[0](index=7)
- 第 2 行(y=2):起始于 L[1](index=6)
- …
- 第 7 行(y=7):可能延伸至 L[6] 或更左
用 ASCII 图表示如下:
Reference Line (index): ... 5 6 7 | 8 | 9 10 11 12 13 14 15 16 [L2] [L1] [L0] [TL] [T0] [T1] [T2] [T3] [T4] [T5] [T6] [T7] ↑ base_idx = 8 Projection for each row: Row y=0: ────────────────→ starts at index 8 (TL) Row y=1: ──────────────────→ starts at index 7 (L0) Row y=2: ────────────────────→ starts at index 6 (L1) Row y=3: ──────────────────────→ starts at index 5 (L2) ... Row y=7: ──────────────────────────→ far left (index ≈ 1) Arrow shows diagonal projection from left side into top.👉 每一行的预测值都来源于这条斜线上经过插值后的参考样本。
这就是所谓的“投影像素法”——把左侧像素沿着一定角度“投射”到上方区域形成虚拟参考线。
六、完整预测流程总结(垂直类模式)
| 步骤 | 内容 | 公式 |
|---|---|---|
| (1) | 构造参考线Ref[] | 长度 =2N+1 2N + 12N+1,顺序:[L[N-1], ..., L[0], TL, T[0], ..., T[N-1]] |
| (2) | 计算整数偏移 | ildx=(y⋅offset)≫5 \text{ildx} = (y \cdot \text{offset}) \gg 5ildx=(y⋅offset)≫5 |
| (3) | 计算分数权重 | w=(y⋅offset)& 31 w = (y \cdot \text{offset}) \&\ 31w=(y⋅offset)&31 |
| (4) | 定位参考索引 | pos=base_idx+ildx \text{pos} = \text{base\_idx} + \text{ildx}pos=base_idx+ildx 其中base_idx=N \text{base\_idx} = Nbase_idx=N |
| (5) | 插值得到预测值 | |
| w=0 w = 0w=0 | pred[y][x]=ref[pos] \text{pred}[y][x] = \text{ref}[\text{pos}]pred[y][x]=ref[pos] | |
| 否则: | pred[y][x]=(32−w)⋅ref[i]+w⋅ref[i+1]+1632 \text{pred}[y][x] = \dfrac{(32-w)\cdot \text{ref}[i] + w\cdot \text{ref}[i+1] + 16}{32}pred[y][x]=32(32−w)⋅ref[i]+w⋅ref[i+1]+16 |
对于水平类模式(M=2~33),逻辑类似,只是改为对列进行循环,并逐列向下预测。
七、为何选择 32 作为缩放因子?
VVC 使用5-bit 精度(1/32)来表示亚像素偏移,主要原因包括:
| 优点 | 说明 |
|---|---|
| 高分辨率控制 | 支持多达 65 个精细角度,适应各种纹理方向 |
| 避免锯齿效应 | 提升预测连续性,减少块效应和振铃 |
| 便于硬件实现 | 位移和掩码操作远快于浮点除法 |
| 统一插值核 | 可复用相同的 5-tap 滤波器表(MDIS) |
例如:
- offset = 32 → 每行移动 1 像素 → 对应 45° 斜线
- offset = 16 → 每两行移动 1 像素 → 更平缓
- offset = -32 → 每行左移 1 像素 → -45° 斜线
八、伪代码实现(C++ 风格,适用于 Markdown 展示)
voidpredictIntraAngular(intmode,intwidth,intheight,constPel*refLine,Pel**pred){intoffset=angTable[mode];// 查表得偏移值,如 mode=30 → -20intbase_idx=height;// TL 在 refLine 中的位置boolisVerticalMode=(mode>=34);// 是否为垂直类模式?if(isVerticalMode){// 垂直类:逐行处理,每行所有像素相同for(inty=0;y<height;y++){intdiff=y*offset;intildx=(diff+(diff<0?-31:0))>>5;// floor divisionintw=diff&31;intrefIdx=base_idx+ildx;Pel val;if(w==0){val=refLine[refIdx];}else{val=((32-w)*refLine[refIdx]+w*refLine[refIdx+1]+16)>>5;}// 该行所有像素赋相同值(横向复制)for(intx=0;x<width;x++){pred[y][x]=Clip1(val);}}}else{// 水平类:逐列处理(逻辑对称)for(intx=0;x<width;x++){intdiff=x*offset;intildx=(diff+(diff<0?-31:0))>>5;intw=diff&31;intrefIdx=base_idx+ildx;Pel val=(w==0)?refLine[refIdx]:((32-w)*refLine[refIdx]+w*refLine[refIdx+1]+16)>>5;for(inty=0;y<height;y++){pred[y][x]=Clip1(val);}}}}九、附录:角度偏移表(表4.2 整理版)
| 模式编号 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 偏移值 | 32 | 29 | 26 | 23 | 20 | 18 | 16 | 14 | 12 | 10 | 8 | 6 | 4 | 3 | 2 | 1 | 0 |
| 模式编号 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 偏移值 | -1 | -2 | -3 | -4 | -6 | -8 | -10 | -12 | -14 | -16 | -18 | -20 | -23 | -26 | -29 | -32 | -29 |
| 模式编号 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 偏移值 | -26 | -23 | -20 | -18 | -16 | -14 | -12 | -10 | -8 | -6 | -4 | -3 | -2 | -1 | 0 | 1 | 2 |
| 模式编号 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 偏移值 | 3 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 23 | 26 | 29 | 32 |
注:偏移值正负决定投影方向;绝对值大小决定斜率陡峭程度。
十、总结
| 步骤 | 名称 | 功能 | 关键技术 |
|---|---|---|---|
| (2) | ildx = (y × offset) >> 5 | 获取整数级参考位置 | 实现斜率投影的离散化 |
| (3) | w = (y × offset) & 31 | 获取亚像素插值权重 | 实现 1/32 精度插值,提升预测精度 |
✅二者共同完成了一个关键任务:
将理想中的连续角度投影过程,转化为高效的整数运算 + 插值,既保证预测精度,又满足实时编码需求。