帧内预测
HEVC 的帧内预测框架包括三个步骤:参考像素获取,像素预测,后处理。
HEVC 的角度预测为具有方向结构的物体提供了高质量的预测。我的理解:帧内预测只适合用于预测具有 HEVC 规定的 35 种角度的条纹状纹理,如果物体不具有这样的特性,那么就必须通过 RDO 把块分成小块进行预测才能获得更小的失真,但是相应的会增加码率。
参考像素获取
HEVC 中的帧内预测利用了周围已重建的像素对当前块的所有像素进行预测(利用了像素在空域上的相关性)。
参考像素填充
一个
2
N
×
2
N
2N\times 2N
2N×2N 块的参考像素位置如图所示:
其中,有些参考像素并不是可用的(位于图像边界,未进行编码等情况),必须对这些不可用位置的参考像素进行填充。
- 所有参考像素不可用的情况:所有位置使用 1 < < ( b i t d e p t h − 1 ) 1 << (bitdepth - 1) 1<<(bitdepth−1) 填充。
- 至少有一个可用的情况:顺时钟方向扫描参考像素位置,并且使用最近的可用参考像素来填充不可用位置。
情况 2 的具体过程如下:
-
当 p [ − 1 ] [ 2 N − 1 ] p[-1][2N-1] p[−1][2N−1] 不可用时,按照 p [ − 1 ] [ 2 N − 2 ] , . . . , p [ − 1 ] [ − 1 ] , . . . , p [ 2 N − 1 ] [ − 1 ] p[-1][2N-2],...,p[-1][-1],...,p[2N-1][-1] p[−1][2N−2],...,p[−1][−1],...,p[2N−1][−1] 的顺序扫描(顺时钟),遇到的第一个可用像素来填充。
-
所有 p [ − 1 ] [ y ] , y = 2 N − 2... − 1 p[-1][y], y=2N-2...-1 p[−1][y],y=2N−2...−1 的不可用位置,使用 p [ − 1 ] [ y + 1 ] p[-1][y+1] p[−1][y+1] 位置来替换。(1 和 2 可以简单理解为左边这一列的下半部不可用位置使用这一列最下面的可用位置的参考像素来填充)
-
所有 p [ x ] [ − 1 ] , x = 0...2 N − 1 p[x][-1], x=0...2N-1 p[x][−1],x=0...2N−1 的不可用位置,使用 p [ x − 1 ] [ − 1 ] p[x-1][-1] p[x−1][−1] 位置来替换。(3 可以简单理解为上边这一行的右半部不可用位置使用这一行最右边的可用位置的参考像素来填充)
参考像素填充举例:
参考像素滤波
HEVC 的帧内预测使用一个平滑滤波器有条件地对参考像素进行滤波。
- 对于 DC 模式以及帧内 4 × 4 4\times4 4×4 的 PU 不进行平滑滤波。
- 8 × 8 8\times8 8×8 的 PU 仅在角度模式 2,18,34 下进行滤波。
- 16 × 16 16\times16 16×16 的 PU 在大部分情况下进行滤波,除了角度模式 9,10,11,25,26,27。
- 32 × 32 32\times32 32×32 的 PU 在大部分情况下进行滤波,除了角度模式 10和26。
滤波时,根据块大小和参考像素的连续性从两个滤波处理中选择一个。
平滑滤波
默认情况下,使用三抽头
[
1
2
1
]
/
4
[1\ 2\ 1] / 4
[1 2 1]/4 的平滑滤波器。最外面的参考像素
p
[
−
1
]
[
2
N
−
1
]
p[-1][2N-1]
p[−1][2N−1] 和
p
[
2
N
−
1
]
[
−
1
]
p[2N-1][-1]
p[2N−1][−1] 不进行滤波,其他参考像素使用两个相邻参考像素进行滤波:
p
[
−
1
]
[
−
1
]
=
(
p
[
−
1
]
[
0
]
+
2
p
[
−
1
]
[
−
1
]
+
p
[
0
]
[
−
1
]
+
2
)
>
>
2
p[-1][-1] = (p[-1][0] + 2p[-1][-1] + p[0][-1] + 2) >> 2
p[−1][−1]=(p[−1][0]+2p[−1][−1]+p[0][−1]+2)>>2
p [ − 1 ] [ y ] = ( p [ − 1 ] [ y + 1 ] + 2 p [ − 1 ] [ y ] + p [ − 1 ] [ y − 1 ] + 2 ) > > 2 p[-1][y] = (p[-1][y+1] + 2p[-1][y] + p[-1][y-1] + 2) >> 2 p[−1][y]=(p[−1][y+1]+2p[−1][y]+p[−1][y−1]+2)>>2
p [ x ] [ − 1 ] = ( p [ x + 1 ] [ − 1 ] + 2 p [ x ] [ − 1 ] + p [ x − 1 ] [ − 1 ] + 2 ) > > 2 p[x][-1] = (p[x+1][-1] + 2p[x][-1] + p[x-1][-1] + 2) >> 2 p[x][−1]=(p[x+1][−1]+2p[x][−1]+p[x−1][−1]+2)>>2
强滤波
另外,如果 PU 大小等于
32
×
32
32\times32
32×32,并且参考样本足够平坦,则使用在三个角落的参考像素
p
[
−
1
]
[
63
]
p[-1][63]
p[−1][63],
p
[
−
1
]
[
−
1
]
p[-1][-1]
p[−1][−1] 和
p
[
63
]
[
−
1
]
p[63][-1]
p[63][−1] 进行线性插值。其使用以下两个不等式来确定平坦程度(阈值由实验来确定):
∣
p
[
−
1
]
[
−
1
]
+
p
[
2
N
−
1
]
[
−
1
]
−
2
p
[
N
−
1
]
[
−
1
]
∣
<
(
1
<
<
(
b
i
t
d
e
p
t
h
−
5
)
)
|p[-1][-1] + p[2N-1][-1] - 2p[N-1][-1]| < (1 << (bitdepth - 5))
∣p[−1][−1]+p[2N−1][−1]−2p[N−1][−1]∣<(1<<(bitdepth−5))
∣ p [ − 1 ] [ − 1 ] + p [ − 1 ] [ 2 N − 1 ] − 2 p [ − 1 ] [ N − 1 ] ∣ < ( 1 < < ( b i t d e p t h − 5 ) ) |p[-1][-1] + p[-1][2N-1] - 2p[-1][N-1]| < (1 << (bitdepth - 5)) ∣p[−1][−1]+p[−1][2N−1]−2p[−1][N−1]∣<(1<<(bitdepth−5))
如果满足以上两个不等式并且 PU 大小等于
32
×
32
32\times32
32×32,非角落的参考像素为:
p
[
−
1
]
[
y
]
=
(
(
63
−
y
)
×
p
[
−
1
]
[
−
1
]
+
(
y
+
1
)
×
p
[
−
1
]
[
63
]
+
32
)
>
>
6
p[-1][y] = ((63-y)\times p[-1][-1] + (y+1)\times p[-1][63] + 32) >> 6
p[−1][y]=((63−y)×p[−1][−1]+(y+1)×p[−1][63]+32)>>6
p [ x ] [ − 1 ] = ( ( 63 − x ) × p [ − 1 ] [ − 1 ] + ( x + 1 ) × p [ 63 ] [ − 1 ] + 32 ) > > 6 p[x][-1] = ((63-x)\times p[-1][-1] + (x+1)\times p[63][-1] + 32) >> 6 p[x][−1]=((63−x)×p[−1][−1]+(x+1)×p[63][−1]+32)>>6
其中, y = 0...62 , x = 0...62 y=0...62,x=0...62 y=0...62,x=0...62 。这个过程叫帧内强滤波,用来去除非常平滑的图像区域上的块效应和伪影。可以使用 SPS 中的 strong_intra_smoothing_enabled_flag 标志位来开关。
下面是 2 种滤波方式示意图:
像素预测
角度预测
HEVC 中的帧内角度预测旨在对视频内容中的不同方向结构进行有效地建模。通过一组事先定义好的预测方向集合来权衡编码复杂度和编码效率。
角度定义
HEVC 规定了帧内 33 种角度预测方向,精度为 1/32:
由于在普通图像中,水平和垂直方向的图案通常比其他方向的图案更加普遍,因此越接近水平方向和垂直方向的模式越多,为水平和垂直方向的图案提供了更准确的预测。而越接近于对角线方向则差异越大,从而可以降低不太频繁发生的角度模式的密度。
下面是预测模式到角度参数 A 的准确映射,角度参数 A 定义了预测模式对应的角度:
负预测方向的参考行/列扩展
为了简化像素的预测过程,上方的参考像素和左侧的参考像素被放置在一个一维数组中。
-
对于具有正角度参数 A (垂直模式 26 至 33 和水平模式 2 至 10 )的模式,则是直接从预测方向复制参考像素来创建一维参考数组。
r e f [ x ] = p [ − 1 + x ] [ − 1 ] , ( x ≥ 0 ) f o r v e r t i c a l m o d e s ref[x]=p[-1+x][-1],(x\geq0)\ for\ vertical \ modes ref[x]=p[−1+x][−1],(x≥0) for vertical modesr e f [ y ] = p [ − 1 ] [ − 1 + y ] , ( y ≥ 0 ) f o r h o r i z o n t a l m o d e s ref[y]=p[-1][-1+y],(y\geq0)\ for\ horizontal \ modes ref[y]=p[−1][−1+y],(y≥0) for horizontal modes
-
对于具有负角度参数 A 的模式,则需要来自块的左侧和上侧的像素作为参考像素数组。对于垂直的预测模式,将左侧参考像素投影到上方参考像素的左边来获得参考值;对于水平的预测模式,将上方参考像素扩展到左侧参考像素的上方来获得参考值。
r e f [ x ] = p [ − 1 ] [ − 1 + ( ( x × B + 128 ) > > 8 ) ] , ( x < 0 ) f o r v e r t i c a l m o d e s ref[x]=p[-1][-1+((x\times B + 128) >> 8)],(x < 0)\ for\ vertical \ modes ref[x]=p[−1][−1+((x×B+128)>>8)],(x<0) for vertical modesr e f [ y ] = p [ − 1 + ( ( y × B + 128 ) > > 8 ) ] [ − 1 ] , ( x < 0 ) f o r h o r i z o n t a l m o d e s ref[y]=p[-1+((y\times B + 128) >> 8)][-1],(x < 0)\ for\ horizontal \ modes ref[y]=p[−1+((y×B+128)>>8)][−1],(x<0) for horizontal modes
其中, B B B 是角度参数 A 的逆角度:
角度预测
通过将 p [ x ] [ y ] p[x][y] p[x][y] 投影到参考像素数组中,并利用当前模式的预测方向上最近的 2 个参考像素进行 1/32 精度的插值来获得该位置处的预测像素值。
-
水平模式 2-17 的插值公式:
p [ x ] [ y ] = ( ( 32 − f ) × r e f [ y + i + 1 ] + f × r e f [ y + i + 2 ] + 16 ) > > 5 p[x][y]=((32-f)\times ref[y + i + 1] + f \times ref[y+i+2]+16) >> 5 p[x][y]=((32−f)×ref[y+i+1]+f×ref[y+i+2]+16)>>5 -
数值模式 18-34 的插值公式
p [ x ] [ y ] = ( ( 32 − f ) × r e f [ x + i + 1 ] + f × r e f [ x + i + 2 ] + 16 ) > > 5 p[x][y]=((32-f)\times ref[x+i+1] + f \times ref[x+i+2]+16) >> 5 p[x][y]=((32−f)×ref[x+i+1]+f×ref[x+i+2]+16)>>5
其中, i i i 是投影位置的整数部分:
i = ( ( x + 1 ) × A ) > > 5 , f o r h o r i z o n t a l m o d e i = ( ( y + 1 ) × A ) > > 5 , f o r v e r t i c a l m o d e i=((x+1)\times A)>>5,for\ horizontal\ mode\\ i=((y+1)\times A)>>5,for\ vertical\ mode i=((x+1)×A)>>5,for horizontal modei=((y+1)×A)>>5,for vertical mode
f f f 是投影位置的小数部分:
f = ( ( x + 1 ) × A ) & 31 , f o r h o r i z o n t a l m o d e f = ( ( y + 1 ) × A ) & 31 , f o r v e r t i c a l m o d e f=((x+1)\times A)\&31,for\ horizontal\ mode\\ f=((y+1)\times A)\&31,for\ vertical\ mode f=((x+1)×A)&31,for horizontal modef=((y+1)×A)&31,for vertical mode
DC 预测
使用左侧和上方参考像素的均值 dcValue 来填充所有位置:
d
c
V
a
l
u
e
=
(
∑
x
=
0
N
−
1
p
[
x
]
[
−
1
]
+
∑
y
=
0
N
−
1
p
[
−
1
]
[
y
]
+
N
)
>
>
(
l
o
g
2
N
+
1
)
dcValue = (\sum_{x=0}^{N-1}{p[x][-1]} + \sum_{y=0}^{N-1}{p[-1][y]} + N) >>(log_2N+1)
dcValue=(x=0∑N−1p[x][−1]+y=0∑N−1p[−1][y]+N)>>(log2N+1)
Planar 预测
角度预测为具有显着边缘结构的块提供了良好的预测,但它会在平滑图像区域产生一些可见的轮廓。类似地,当 DC 预测应用于中低码率时,通常会在平滑的图像区域中观察到一些块效应。Planar 预测通过在块边界上生成预测表面来克服块边界不连续性。
p
h
[
x
]
[
y
]
=
(
N
−
1
−
x
)
×
p
[
−
1
]
[
y
]
+
(
x
+
1
)
×
p
[
N
]
[
−
1
]
p
v
[
x
]
[
y
]
=
(
N
−
1
−
y
)
×
p
[
x
]
[
−
1
]
+
(
y
+
1
)
×
p
[
−
1
]
[
N
]
p
[
x
]
[
y
]
=
(
p
h
[
x
]
[
y
]
+
p
v
[
x
]
[
y
]
+
N
)
>
>
(
l
o
g
2
N
+
1
)
p_h[x][y]=(N-1-x)\times p[-1][y]+(x+1)\times p[N][-1] \\ p_v[x][y]=(N-1-y)\times p[x][-1]+(y+1)\times p[-1][N] \\ p[x][y]=(p_h[x][y]+p_v[x][y]+N)>>(log_2N+1)
ph[x][y]=(N−1−x)×p[−1][y]+(x+1)×p[N][−1]pv[x][y]=(N−1−y)×p[x][−1]+(y+1)×p[−1][N]p[x][y]=(ph[x][y]+pv[x][y]+N)>>(log2N+1)
planar 预测的推导如下所示:
后处理
一些预测模式在 PU 边界上的预测像素不连续。对于 DC 和严格的水平、垂直角度预测,这种情况最为明显。例如:在 DC 预测下,所有预测像素都被替换为单个值,这种不连续性会发生在 PU 的上方和左侧边界上。在垂直角度(26)预测下,在 PU 的左侧边界处可能存在不连续性,因为最左列的预测像素复制了 PU 上方最左边的参考像素值。水平角度预测(10)模式下,在块的上边界也可能发生类似的不连续性。
为了减小 PU 边界上的不连续性,通过考虑块边界处的梯度来对 PU 的边界像素进行滤波。滤波过程只适用于 PU 尺寸小于 32 × 32 32\times32 32×32,并且预测模式为 DC,垂直(26)角度模式以及水平(10)角度模式下,并且只适用于亮度分量。
-
对于垂直(26)角度模式,第一列预测像素被修改为:
p [ 0 ] [ y ] = p [ 0 ] [ y ] + ( ( p [ − 1 ] [ y ] − p [ − 1 ] [ − 1 ] ) > > 1 p[0][y]=p[0][y]+((p[-1][y]-p[-1][-1])>>1 p[0][y]=p[0][y]+((p[−1][y]−p[−1][−1])>>1 -
对于水平(10)角度模式,第一行预测像素被修改为:
p [ x ] [ 0 ] = p [ x ] [ 0 ] + ( ( p [ x ] [ − 1 ] − p [ − 1 ] [ − 1 ] ) > > 1 ) p[x][0]=p[x][0]+((p[x][-1]-p[-1][-1])>>1) p[x][0]=p[x][0]+((p[x][−1]−p[−1][−1])>>1) -
对于 DC 模式:
p [ 0 ] [ 0 ] = ( p [ − 1 ] [ 0 ] + 2 × d c V a l + p [ 0 ] [ − 1 ] + 2 ) > > 2 p [ x ] [ 0 ] = ( p [ x ] [ − 1 ] + 3 × d c V a l + 2 ) > > 2 p [ 0 ] [ y ] = ( p [ − 1 ] [ y ] + 3 × d c V a l + 2 ) > > 2 p[0][0]=(p[-1][0]+2\times dcVal + p[0][-1] + 2) >> 2\\ p[x][0]=(p[x][-1]+3\times dcVal + 2)>>2 \\ p[0][y]=(p[-1][y]+3\times dcVal + 2)>>2 p[0][0]=(p[−1][0]+2×dcVal+p[0][−1]+2)>>2p[x][0]=(p[x][−1]+3×dcVal+2)>>2p[0][y]=(p[−1][y]+3×dcVal+2)>>2
帧内模式编码
帧内预测模式数量的增加提供了更准确的预测,但是需要有效的帧内模式编码来确保所选择的模式能够以最小的开销进行编码传输。
亮度帧内模式的预测
HEVC 基于相邻的 PU 的模式为当前 PU 设计了 3 种最可能的模式 (Most Probable Modes, MPM)。
定义如下符号:
A:当前 PU 左侧的 PU 的帧内模式。B:当前 PU 上方的 PU 的帧内模式。
并且,如果相邻的 PU 不做帧内编码或者采用脉冲编码调制 (pulse code modulation, PCM) 模式进行编码(PCM 是帧内的一种特殊编码模式,编码端直接传输像素值。适用于图像特别复杂,采用其他编码模式效果不理想,采用 PCM 模式效果还更好的情况。在无损编码中也采用PCM模式。),则认为该PU是DC模式。另外,如果上方 PU 超出了当前 CTU 的,则 B 也被当做 DC 模式。
这是为了减少帧内编码模式的存储,如果不这样做,则需要存储一整行 CTU 最下面那行的帧内编码模式,而左侧只需要存储一个 CTU 最右边那列的帧内编码模式
MPM 列表的详细推导过程如下:
色度帧内预测模式
对于色度 PU 来说,仅有 5 种帧内预测模式
- Planar 模式
- 角度模式 26(垂直)
- 角度模式 10(水平)
- DC 模式
- 对应亮度分量的预测模式
通常来说,色度信号的结构跟随亮度信号的结构。当对应亮度分量的预测模式是前 4 种模式中的一种时,用角度模式 34 来代替对应亮度分量的预测模式,具体过程如下所示:
帧内编码模式的语法设计
对于亮度模式,让已选择的 3 个 MPM 按升序排列,分别为 SMPM[0],SMPM[1],SMPM[2]。语法元素 prev_intra_luma_pred_flag 指定亮度帧内模式是否等于 3 个最可能模式之一。在这种情况下,附加语法元素 mpm_idx 用于表示 SMPM[mpm_idx] 是所选择的亮度帧内模式。
否则(prev_intra_luma_pred_flag 等于 0),语法元素 rem_intra_luma_pred_mode 用于指定亮度帧内模式。由于亮度模式的总数等于 35,MPM 的数量等于3,所以 rem_intra_luma_pred_mode 的范围是 0 到 31,可以通过 5 个比特来表示。
快速帧内编码算法
在 HM 中,使用了 SATD 计算的代价进行粗选,再使用完整的率失真代价进行细选。
对于 PU 尺寸为 4 × 4 4\times4 4×4, 8 × 8 8\times8 8×8,其粗选出 8 个亮度帧内模式,再进行细选。而其他尺寸的 PU 则粗选出 3 个亮度帧内模式。
对于色度则不使用 SATD 进行粗选。
性能:BD-rate 增加不到 1%,但是复杂度下降了 1/3。
目前,使用神经网络对帧内进行块划分和模式预选,可以降低 80% 复杂度, BD-rate 增加 3%。
HEVC 和 264 的帧内预测区别
HEVC 仅支持最大
32
×
32
32 \times 32
32×32 尺寸的帧内预测,所以对于
64
×
64
64 \times 64
64×64 尺寸的 CU,HEVC 会将其分成 4 个
32
×
32
32 \times 32
32×32 的区域进行帧内预测。注意:这里的 4 个
32
×
32
32 \times 32
32×32 的仅能选择相同的帧内预测模式。