VTM4.0中 lambda與QP的關係

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(Y)

亮度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

二、設置色度lambda(C)

在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的關係

由以上關係,QP和lambda的關係整理可知:

lambda(Y)≈ 0.54 * 2^(QP(Y)/3)

lambda( C)≈ 0.53 * 2^(QP( C)/3)

初步得出結論,一般確定情況下,lambda僅與QP相關

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章