量化矩阵的原理是对应不同位置的系数使用不同的量化系步长进行量化,人眼对高频不敏感,对低频分量进行小步长量化,对高频分量进行大步长量化,在保证主观质量的情况下,提高压缩效率。HEVC支持量化矩阵,但是默认不启用。HEVC的量化矩阵与TU大小相同,分为4x4,8x8,16x16,32x32 4种尺寸。
HEVC可以使用两种形式的量化矩阵:默认量化矩阵、自定义量化矩阵。下面来学习默认量化矩阵。
默认量化矩阵的定义
HEVC定义了4x4,8x8,16x16,32x32 4种尺寸的默认量化矩阵,其中8x8及以上 帧内、帧间使用不同矩阵。4x4、8x8帧内、8x8帧间的量化矩阵如下图,16x16、32x32的矩阵由8x8矩阵插值得到,后边会详细说明计算过程。在TComRom
中定义,解码端可以直接拿到,不需要传输。量化矩阵中的元素可以看作放缩系数,量化系数除以对应位置的元素得到最终的量化系数。
默认量化矩阵详细推导过程推荐阅读论文Adaptive Quantization Matrices for HD and UHD Display Resolutions in Scalable HEVC。
量化矩阵的作用
量化的公式如下:
abs(x)=(abs(d) * MF + f_temp) >> (qbits + T_Shift)
qbits = + floor(QP/6)
MF = 2^qbits / Qstep
f_temp = f << (qbits + T_Shift)
一般情况下,对于I帧,f=1/3,对于P、B帧,f=1/6,x是量化后的系数,d是量化之前的系数,MF
即量化系数,量化矩阵即根据位置改变MF
值。
编码端量化系数矩阵的计算
编码端,会在xInitScalingLists
中初始化量化矩阵,当ScalingListId
为SCALING_LIST_DEFAULT
,即使用默认量化矩阵,会调用setScalingList
初始化默认量化矩阵。这里也可以看到,默认量化矩阵是不需要在SPS和PPS里传的。
setScalingList
是设置量化系数矩阵的入口函数,遍历4种尺寸、6种模式(Y/Cb/Cr、帧内/帧间)、6种qp(qp%6)设置量化矩阵。其中xSetScalingListEnc
计算量化矩阵,xSetScalingListDec
计算反量化矩阵,setErrScaleCoeff
这个没具体看,应该是在反量化时用到。
xSetScalingListEnc
计算编码端量化系数矩阵的入口函数,调用processScalingListEnc
计算量化矩阵。其中quantScales
即与QP%6对应的量化系数,quantScales[6]={26214,23302,20560,18396,16384,14564}
,为保持精度,在传给processScalingListEnc
时quantScales
根据TU尺寸放大4倍。
processScalingListEnc
中计算最终的量化系数矩阵。因为之前quantScales
已经放大了4倍,这里quantcoeff
实际等于quantScales*4
除以对应位置量化矩阵元素得到最终的量化系数,即量化矩阵元素16对应位置的量化系数不进行调整,大于16位置的系数会相应的缩小,使量化系数MF
变小。量化公式如下,MF
变小从而量化后的值会变小。
以8x8 intra为例,量化矩阵各位置系数对MF
的改变情况如下,左上角16对应1.0000,即MF
不变;系数越大,会给MF
乘以更小的数,使MF
变小。
在HM中只存了4x4和8x8的矩阵,这里通过对8x8插值计算16x16和32x32,插值过程很简单,如下图,对于16x16的矩阵,即使用8x8矩阵的一个系数填充2x2的区域,32x32的矩阵,即1个系数填充4x4的区域。
xSetScalingListDec
反量化矩阵与量化矩阵处理类似,不做具体介绍了。