H.265帧内预测的Angular模式
角度(Angular)模式通过 33 种精细的方向来模拟图像的纹理和边缘。
其核心流程可以概括为:为块内每个像素点,沿着指定角度反向投影到参考像素行/列上,再通过插值计算出预测值。
第 1 步:模式与角度的映射
首先,33 个角度模式(模式号 2 到 34)需要映射为具体的几何角度和位移参数。这些模式被分为两大类:
- 水平类模式 (Horizontal-like, 模式 2-17):预测角度比 45 度更接近水平。主要使用左侧的参考像素列进行预测。
- 垂直类模式 (Vertical-like, 模式 18-34):预测角度比 45 度更接近垂直。主要使用上方的参考像素行进行预测。
每个模式都对应一个整数化的角度位移参数 intraPredAngle。这个参数的绝对值越大,表示角度越偏离纯粹的水平或垂直。这是一个预定义的查找表。
| 模式 (Mode) | intraPredAngle | 角度 (近似) | 
|---|---|---|
| 10 (水平) | 32 | 0° | 
| 11 | 26 | -7° | 
| … | … | … | 
| 17 | 2 | -45° | 
| 18 | -2 | 45° | 
| … | … | … | 
| 26 (垂直) | 0 | 90° | 
| … | … | … | 
| 34 | -32 | 180° | 
注意:intraPredAngle 是一个位移因子,32 对应 tan(angle) 的 32 倍。例如,intraPredAngle = 32 意味着每向下移动一个像素,就向右平移 32/32 = 1 个像素。
第 2 步:构建扩展参考像素数组
为了处理各种角度的投影,算法需要一个比块尺寸更大的参考像素集合。它会根据模式的类别(水平类/垂直类)来构建一个一维的扩展参考数组 ref[]。
对于垂直类模式 (18-34):
- 主参考 (Main Array):ref[]的主体是上方的参考像素p[x][-1],从左上角p[-1][-1]一直延伸到右上角p[2N-1][-1]。
- 侧参考 (Side Array):当投影角度非常陡峭,导致投影点为负数时,需要用到左侧的参考像素。
ASCII 图示 (垂直类模式):
     <- Main Array ->
p[-1][-1] p[0][-1] ... p[N-1][-1] ... p[2N-1][-1]
   +----------------+
   |  (x,y)         |
   |     * |
   |   /            |
   |  / (投影)      |
   | /              |
   +----------------+
对于水平类模式 (2-17):
- 主参考 (Main Array):ref[]的主体是左侧的参考像素p[-1][y],从左上角p[-1][-1]一直延伸到左下角p[-1][2N-1]。
- 侧参考 (Side Array):当投影角度非常平缓时,需要用到上方的参考像素。
第 3 步:逐像素投影与插值计算
这是算法的核心,对块内的每一个像素 (x, y)(x, y 从 0 到 N-1)循环执行。我们以垂直类模式 (mode ≥ 18) 为例:
- 计算整数投影位置 i和小数位移f:- 首先计算一个总位移:delta_pos = (y + 1) * intraPredAngle
- 这个位移 delta_pos是一个带小数的偏移量,在实现中用 32 倍的整数表示。
- 小数位移 f(fraction) 是总位移的低 5 位:f = delta_pos & 31。
- 整数投影位置的偏移是总位移的高位(带符号右移 5 位,相当于除以 32):delta_ref = delta_pos >> 5。
 
- 首先计算一个总位移:
- 确定最终参考像素索引 ref_idx:- 最终的索引是当前像素的 x坐标加上这个整数偏移:ref_idx = x + delta_ref。
 
- 最终的索引是当前像素的 
- 插值计算预测值:
    - 情况 A:无小数位移 (f == 0)- 投影点正好落在整数位置上,无需插值。
- 直接复制参考像素:pred(x, y) = ref[ref_idx]
 
- 情况 B:有小数位移 (f != 0)- 投影点落在两个参考像素 ref[ref_idx]和ref[ref_idx + 1]之间。
- 使用线性插值计算预测值: pred(x, y) = ((32 - f) * ref[ref_idx] + f * ref[ref_idx + 1] + 16) >> 5
- 这个公式是一个加权平均:pred ≈ ref[ref_idx] * (1 - f/32) + ref[ref_idx+1] * (f/32)。+16是为了四舍五入,>>5是除以 32。
 
- 投影点落在两个参考像素 
 
- 情况 A:无小数位移 (
水平类模式 (mode < 18) 的计算过程完全类似,只是 x 和 y 的角色互换。
第 4 步:特殊情况处理 (负索引投影)
当 ref_idx 计算出来是负数时,意味着投影点落在了左上角 p[-1][-1] 的左边或上边。这时就需要用到侧参考数组,并且插值计算方式会略有不同,通常是使用一个预定义的 invAngle 参数(角度的倒数)来进行二次投影。
例如,对于垂直模式,当 ref_idx 为 -1 时,说明投影到了 p[-1][-1] 和 p[-2][-1] 之间(p[-2][-1] 并不存在),此时会改用 invAngle 从 p[-1][-1] 沿着左侧参考列向下投影来计算。
总结
对于块内每一个像素 (x, y):
- 输入:Intra 模式号、x和y坐标、扩展参考像素数组ref[]。
- 查找:根据模式号查到 intraPredAngle。
- 计算投影:
    - delta_pos = (y+1) * intraPredAngle(以垂直模式为例)
- f = delta_pos & 31
- ref_idx = x + (delta_pos >> 5)
 
- 插值:
    - 如果 f == 0,pred(x,y) = ref[ref_idx]
- 如果 f != 0,pred(x,y) = ((32-f)*ref[ref_idx] + f*ref[ref_idx+1] + 16) >> 5
 
- 如果 
- 输出:预测像素值 pred(x,y)。