lambda是率失真优化中的一个重要参数,其取值与量化参数QP有比较固定的函数关系。接下来将深入VTM4.0代码中探究lambda与QP的关系。
首先在cfg中可以得到QP值,本文档视为亮度QP,记作QP(Y);在cfg中还可以得到CbQpOffset和 CrQpOffset,供后续计算色度QP,记作QP( C);亮度lambda和色度lambda由以上两种QP算得,记作lambda(Y)和lambda( C)。
亮度lambda的计算公式为:
lambda(Y) = 0.57 * 2^(x/3)
其中
x = QP(Y)+ (bitdepth - 8) * 6 – 12
即比特深度为10时x等于QP(Y)值。如果在ME过程中使用hadamard变换,应在原基础上乘以0.95作为lambda(Y)最终值。
lambda(Y)= 0.57 * 2^(x/3) * 0.95
亮度部分在代码中的对应函数为calculateLambda。
#if SHARP_LUMA_DELTA_QP
double EncSlice::calculateLambda( const Slice* slice,
const int GOPid, // entry in the GOP table
const int depth, // slice GOP hierarchical depth.
const double refQP, // initial slice-level QP 初始的slice级QP
const double dQP, // initial double-precision QP 初始的双精度QP
int &iQP ) // returned integer QP.
{
enum SliceType eSliceType = slice->getSliceType();
const bool isField = slice->getPic()->fieldPic;
const int NumberBFrames = ( m_pcCfg->getGOPSize() - 1 );
const int SHIFT_QP = 12;
#if X0038_LAMBDA_FROM_QP_CAPABILITY
const int temporalId=m_pcCfg->getGOPEntry(GOPid).m_temporalId;//CFG里的
const std::vector<double> &intraLambdaModifiers=m_pcCfg->getIntraLambdaModifier();//CFG里的
#endif
int bitdepth_luma_qp_scale = 6
* (slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) - 8
- DISTORTION_PRECISION_ADJUSTMENT(slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)));//亮度深度
double qp_temp = dQP + bitdepth_luma_qp_scale - SHIFT_QP;//记作t,临时QP = 原QP+比特深度控制的QP-QP偏移(12)
// Case #1: I or P-slices (key-frame)
double dQPFactor = m_pcCfg->getGOPEntry(GOPid).m_QPFactor;//CFG里的
/********如果是I帧*********/
if /*true*/( eSliceType==I_SLICE )
{
if /*false*/(m_pcCfg->getIntraQpFactor()>=0.0 && m_pcCfg->getGOPEntry(GOPid).m_sliceType != I_SLICE)
{
dQPFactor=m_pcCfg->getIntraQpFactor();
}
else/*true*/
{
#if X0038_LAMBDA_FROM_QP_CAPABILITY
if/*false*/ (m_pcCfg->getLambdaFromQPEnable())
{
dQPFactor=0.57;
}
else/*true*/
{
#endif
double dLambda_scale = 1.0 - Clip3( 0.0, 0.5, 0.05*(double)(isField ? NumberBFrames/2 : NumberBFrames) );//记作a
dQPFactor=0.57*dLambda_scale;//记作b,b=0.57*a
#if X0038_LAMBDA_FROM_QP_CAPABILITY
}
#endif
}
}
#if X0038_LAMBDA_FROM_QP_CAPABILITY/****************如果CFG中使用了“从QP启用获取Lambda”***********/
else if/*false*/( m_pcCfg->getLambdaFromQPEnable() )
{
dQPFactor=0.57;
}
#endif
double dLambda = dQPFactor*pow( 2.0, qp_temp/3.0 );//记作x, x = b * 2^(t/3) = 0.57*a * 2^(t/3)
#if X0038_LAMBDA_FROM_QP_CAPABILITY /************如果CFG中没有使用“从QP启用获取Lambda”***********/
if/*false*/( !(m_pcCfg->getLambdaFromQPEnable()) && depth>0 )//当深度大于0时
#else
if ( depth>0 )
#endif
{
double qp_temp_ref = refQP + bitdepth_luma_qp_scale - SHIFT_QP;
dLambda *= Clip3(2.00, 4.00, (qp_temp_ref / 6.0)); // (j == B_SLICE && p_cur_frm->layer != 0 )
}
// if hadamard is used in ME process 如果在ME过程中使用hadamard变换
if/*true*/ ( !m_pcCfg->getUseHADME() && slice->getSliceType( ) != I_SLICE )
{
dLambda *= 0.95;//x = 0.57*a * 2^(t/3) *0.95
}
#if X0038_LAMBDA_FROM_QP_CAPABILITY
double lambdaModifier;//记作m
if/*true*/( eSliceType != I_SLICE || intraLambdaModifiers.empty())
{
lambdaModifier = m_pcCfg->getLambdaModifier( temporalId );
}
else/*false*/
{
lambdaModifier = intraLambdaModifiers[ (temporalId < intraLambdaModifiers.size()) ? temporalId : (intraLambdaModifiers.size()-1) ];
}
dLambda *= lambdaModifier;//x = 0.57*a * 2^(t/3) * 0.95 * m
#endif
iQP = Clip3( -slice->getSPS()->getQpBDOffset( CHANNEL_TYPE_LUMA ), MAX_QP, (int) floor( dQP + 0.5 ) );
if/*true*/( m_pcCfg->getDepQuantEnabledFlag() )
{//依赖量化的轻微lambda调整(由于量化器的斜率不同) x = 0.57*a * 2^(t/3) * 0.95 * m * 2^(0.25/3)
dLambda *= pow( 2.0, 0.25/3.0 ); // slight lambda adjustment for dependent quantization (due to different slope of quantizer)
}
// NOTE: the lambda modifiers that are sometimes applied later might be best always applied in here.
return dLambda;//x = 0.57*a * 2^(t/3) * 0.95 * m * 2^(0.25/3)
}
#endif
在cfg中读取CbQpOffset和 CrQpOffset,与QP(Y)值进行运算,可得到一个色度QP暂时值QP(t)
QP(t)=QP(Y)+CbQpOffset
或
QP(t)=QP(Y)+CrQpOffset
根据QP(t)值在ROM中寻得用于后续计算的色度QP真实值QP©,如下表所示。
色度QP暂时值QP(t) | 色度QP真实值QP( C) |
---|---|
30≤QP(t)≤33 | QP( C) = QP(t) - 1 |
35≤QP(t)≤36 | QP( C) = QP(t) - 2 |
37≤QP(t)≤38 | QP( C) = QP(t) - 3 |
39≤QP(t)≤40 | QP( C) = QP(t) - 4 |
41≤QP(t)≤42 | QP( C) = QP(t) – 5 |
43≤QP(t)≤69 | QP( C)= QP(t) – 6 |
设一个临时失真权重w,与GOP相关。
w = 2 ^ [(QP(Y)- QP( C)+ 0.1)/3.0] GOPsize<8
w = 2 ^ [(QP(Y)- QP( C)+ 0.2)/3.0] GOPsize≥8
最终得出色度lambda值:
lambda ( C)=lambda(Y) / w
色度部分在代码中对应函数为setUpLambda。
void
EncSlice::setUpLambda( Slice* slice, const double dLambda, int iQP)
{
// store lambda 保存lambda数值
m_pcRdCost ->setLambda( dLambda, slice->getSPS()->getBitDepths() );
// for RDO
// in RdCost there is only one lambda because the luma and chroma bits are not separated, instead we weight the distortion of chroma.
double dLambdas[MAX_NUM_COMPONENT] = { dLambda };
for( uint32_t compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ )//遍历2个色度通道的lambda,计算得出色度lambda的值(亮度lambda/权重)
{
const ComponentID compID = ComponentID( compIdx );
int chromaQPOffset = slice->getPPS()->getQpOffset( compID ) + slice->getSliceChromaQpDelta( compID );
int qpc = ( iQP + chromaQPOffset < 0 ) ? iQP : getScaledChromaQP( iQP + chromaQPOffset, m_pcCfg->getChromaFormatIdc() );
double tmpWeight = pow( 2.0, ( iQP - qpc ) / 3.0 ); // takes into account of the chroma qp mapping and chroma qp Offset 考虑色度qp映射和色度qp偏移
if( m_pcCfg->getDepQuantEnabledFlag() )
{
tmpWeight *= ( m_pcCfg->getGOPSize() >= 8 ? pow( 2.0, 0.1/3.0 ) : pow( 2.0, 0.2/3.0 ) ); // increase chroma weight for dependent quantization (in order to reduce bit rate shift from chroma to luma) 增加依赖量化的色度权重(为了减少从色度到亮度的比特率偏移)
}
m_pcRdCost->setDistortionWeight( compID, tmpWeight );
#if ENABLE_WPP_PARALLELISM
for( int jId = 1; jId < ( m_pcLib->getNumWppThreads() + m_pcLib->getNumWppExtraLines() ); jId++ )
{
m_pcLib->getRdCost( slice->getPic()->scheduler.getWppDataId( jId ) )->setDistortionWeight( compID, tmpWeight );
}
#endif
dLambdas[compIdx] = dLambda / tmpWeight;//赋值色度lambda
}
#if RDOQ_CHROMA_LAMBDA
// for RDOQ
m_pcTrQuant->setLambdas( dLambdas );//赋值全部lambda
#else
m_pcTrQuant->setLambda( dLambda );
#endif
// for SAO
slice->setLambdas( dLambdas );//赋值全部lambda
}
由以上关系,QP和lambda的关系整理可知:
lambda(Y)≈ 0.54 * 2^(QP(Y)/3)
lambda( C)≈ 0.53 * 2^(QP( C)/3)
初步得出结论,一般确定情况下,lambda仅与QP相关。