AQ自适应量化
问题
HVS is more sensitive to distortion in a relatively homogenous area than in an area with high contrast.
简单的说就是,人更关注平坦区域的变化而对复杂纹理区域损失不敏感,因此需要适当降低平坦区域QP。
解决方法
首先需要一个指标来衡量什么是平坦区域什么是复杂区域,在x264和x265当中分别有三种和四种模式。主要的区别是分别使用了方差、自协方差、边密度。
模式
在x264当中有 X264_AQ_VARIANCE、X264_AQ_AUTOVARIANCE、X264_AQ_AUTOVARIANCE_BIASED
三种模式,x265当中增加了X265_AQ_EDGE
模式
计算过程
以X265_AQ_AUTO_VARIANCE
模式为例,主要框架是
1、遍历每一个block,计算每个block的自协方差并且根据自协方差求出
2、根据qp_adj
求出平均的avg_adj
3、再次遍历,修正 qp_adj = aqStrength * avg_adj *(qp_adj - avg_adj)
代码解读
以X265_AQ_AUTOVARIANCE
为例解读,在x265当中如果--tune
参数设定为ssim
即开启这种模式的AQ
x265
//空域AQ入口函数 slicetype.cpp 第445行
void LookaheadTLD::calcAdaptiveQuantFrame(Frame *curFrame, x265_param* param)
{
/*block数量*/
int maxCol = curFrame->m_fencPic->m_picWidth;
int maxRow = curFrame->m_fencPic->m_picHeight;
...
/*第一次遍历每个block计算对应的qp_adj*/
for (int blockY = 0; blockY < maxRow; blockY += loopIncr){
for (int blockX = 0; blockX < maxCol; blockX += loopIncr){
...
// energy 和模式有关,这里就是自协方差
energy = acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize);
qp_adj = pow(energy * bit_depth_correction + 1, 0.1);
// 存起来
curFrame->m_lowres.qpCuTreeOffset[blockXY] = qp_adj;
avg_adj += qp_adj;
...
}
}
// 求均值
avg_adj /= blockCount;
strength = param->rc.aqStrength * avg_adj;
...
/*第二次遍历,修正qp_adj */
for (int blockY = 0; blockY < maxRow; blockY += loopIncr){
for (int blockX = 0; blockX < maxCol; blockX += loopIncr){
...
qp_adj = curFrame->m_lowres.qpCuTreeOffset[blockXY];
qp_adj = strength * (qp_adj - avg_adj);
...
}
}
}
小结
根据代码来看,某一块自协方差如果大于帧的均值那么qp_adj是增大的,即QP增大,考虑到最初的设想,即变化剧烈的区域(复杂区域)QP增大,防止就是说平坦区域QP减小,分配更多的码率。
效果
Enable adaptive quantization. This mode distributes available bits between all CTUs of a frame, assigning more bits to low complexity areas. Turning this ON will usually affect PSNR negatively, however SSIM and visual quality generally improves. Default: X265_AQ_AUTO_VARIANCE
开启AQ会提升ssim及主观质量,但是对PSNR会有负面的影响