SAO代碼解析補充(二)

作者:66

1. 理論部分--快速率失真計算方法:

在後面的代碼中用到了,在此說明一下方便後面的理解:

率失真(J = 像素誤差(D+語法編碼代價(λR),R是編碼所需bitλ是係數。

其中像素誤差可以有MSE(最小均方誤差)、MAD(最小平均絕對誤差)等。這裏用的MSE,即原始像素與重構像素的差值平方和。

org代表原始像素,rec代表重構像素,offset爲補償值,則有:

補償前:

補償後:

補償前後的誤差:


上式中N爲像素個數,因此率失真差值爲:


可以看出計算差值J比計算J少了約N次對差值進行平方的計算,因此選最優時只需要對比差值J即可。

2.補充:

昨天剩下的兩個函數,saoCOmponentParamDist中,計算過EOBO模式後的mergemergeup是計算取鄰塊SAO模式的率失真,也就是說,函數saoComponentParamDist計算並記錄了EOBO模式下最優模式,但並未在此函數中與融合模式進行對比,具體的對比在調用saoCOmponentParamDist的函數rdoSaoUnitAll的後半部分。

 

圖一、本文涉及的代碼結構(標紅部分)

saoCOmponentParamDist中計算merge率失真的代碼:

 

 // merge left or merge up

 

  for (Int idxNeighbor=0;idxNeighbor<2;idxNeighbor++)

  {

    saoLcuParamNeighbor = NULL;

    if (allowMergeLeft && addrLeft>=0 && idxNeighbor ==0)//!< 左鄰塊可用

    {

      saoLcuParamNeighbor = &(saoParam->saoLcuParam[yCbCr][addrLeft]);//!< 取左鄰塊的SAO參數

    }

    else if (allowMergeUp && addrUp>=0 && idxNeighbor ==1)//!< 上鄰塊可用

    {

      saoLcuParamNeighbor = &(saoParam->saoLcuParam[yCbCr][addrUp]);//!< 取上鄰塊的SAO參數

    }

    if (saoLcuParamNeighbor!=NULL)

    {

      estDist = 0;

      typeIdx = saoLcuParamNeighbor->typeIdx;//取鄰塊的SAO模式

      if (typeIdx>=0)

      {

        Int mergeBandPosition = (typeIdx == SAO_BO)?saoLcuParamNeighbor->subTypeIdx:0;

        Int   merge_iOffset;

        for(classIdx = 0; classIdx < m_iNumClass[typeIdx]; classIdx++)

        {

          merge_iOffset = saoLcuParamNeighbor->offset[classIdx];

          estDist   += estSaoDist(m_iCount [yCbCr][typeIdx][classIdx+mergeBandPosition+1], merge_iOffset, m_iOffsetOrg[yCbCr][typeIdx][classIdx+mergeBandPosition+1],  shift);

        }

      }

      else

      {

        estDist = 0;

      }

 

      copySaoUnit(&compSaoParam[idxNeighbor], saoLcuParamNeighbor );

      compSaoParam[idxNeighbor].mergeUpFlag   = idxNeighbor;

      compSaoParam[idxNeighbor].mergeLeftFlag = !idxNeighbor;

 

      compDistortion[idxNeighbor+1] += ((Double)estDist/lambda);

    }

  }

}

其中調用了計算率失真的函數estSaoDist,函數定義爲:

inline Int64 TEncSampleAdaptiveOffset::estSaoDist(Int64 count, Int64 offset, Int64 offsetOrg, Int shift)

{

  return (( count*offset*offset-offsetOrg*offset*2 ) >> shift);

}


這個函數用的是SAO率失真的快速計算方法,其中return (( count*offset*offset-offsetOrg*offset*2 ) >> shift);對應於公式

具體解析看前理論部分。

前面說過,merge模式參與率失真的比較在rdoSaoUnitAll函數後半部分,下面貼後半部分代碼:

 //計算亮度和色度模式下的參數融合率失真

      if( saoParam->bSaoFlag[0] || saoParam->bSaoFlag[1] )

      {

        // Cost of new SAO_params初始化參數

        m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[0][CI_CURR_BEST]);

        m_pcRDGoOnSbacCoder->resetBits();

        if (allowMergeLeft)

        {

          m_pcEntropyCoder->m_pcEntropyCoderIf->codeSaoMerge(0);

        }

        if (allowMergeUp)

        {

          m_pcEntropyCoder->m_pcEntropyCoderIf->codeSaoMerge(0);

        }

        for ( compIdx=0;compIdx<3;compIdx++)

        {

        if( (compIdx ==0 && saoParam->bSaoFlag[0]) || (compIdx >0 && saoParam->bSaoFlag[1]))

          {

           m_pcEntropyCoder->encodeSaoOffset(&saoParam->saoLcuParam[compIdx][addr], compIdx);

           //cost of merge

          }

        }

 

        rate = m_pcEntropyCoder->getNumberOfWrittenBits();

        bestCost = compDistortion[0] + (Double)rate;

        m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[0][CI_TEMP_BEST]);

 

        //計算參數融合模式下的率失真

        for(Int mergeUp=0; mergeUp<2; ++mergeUp)

        {

          if ( (allowMergeLeft && (mergeUp==0)) || (allowMergeUp && (mergeUp==1)) )

          {

            m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[0][CI_CURR_BEST]);

            m_pcRDGoOnSbacCoder->resetBits();

            if (allowMergeLeft)

            {

              m_pcEntropyCoder->m_pcEntropyCoderIf->codeSaoMerge(1-mergeUp);

            }

            if ( allowMergeUp && (mergeUp==1) )

            {

              m_pcEntropyCoder->m_pcEntropyCoderIf->codeSaoMerge(1);

            }

 

            rate = m_pcEntropyCoder->getNumberOfWrittenBits();//碼率

            mergeCost = compDistortion[mergeUp+1] + (Double)rate;//率失真

            if (mergeCost < bestCost)//更新最佳濾波模式

            {

              bestCost = mergeCost;

              m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[0][CI_TEMP_BEST]);              

              for ( compIdx=0;compIdx<3;compIdx++)

              {

                mergeSaoParam[compIdx][mergeUp].mergeLeftFlag = 1-mergeUp;

                mergeSaoParam[compIdx][mergeUp].mergeUpFlag = mergeUp;

                if( (compIdx==0 && saoParam->bSaoFlag[0]) || (compIdx>0 && saoParam->bSaoFlag[1]))

                {

                  copySaoUnit(&saoParam->saoLcuParam[compIdx][addr], &mergeSaoParam[compIdx][mergeUp] );             

                }

              }

            }

          }

        }

#if SAO_ENCODING_CHOICE

#if SAO_ENCODING_CHOICE_CHROMA

if( saoParam->saoLcuParam[0][addr].typeIdx == -1)//Y分量不存在SAO參數

{

  numNoSao[0]++;

}

if( saoParam->saoLcuParam[1][addr].typeIdx == -1)//CbCr分量不存在SAO參數

{

  numNoSao[1]+=2;

}

#else

        for ( compIdx=0;compIdx<3;compIdx++)

        {

          if( depth == 0 && saoParam->saoLcuParam[compIdx][addr].typeIdx == -1)

          {

            numNoSao++;

          }

        }

#endif

#endif

        m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[0][CI_TEMP_BEST]);

        m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[0][CI_CURR_BEST]);

      }//!< if( saoParam->bSaoFlag[0] || saoParam->bSaoFlag[1] )

    }//!< for (idxX = 0; idxX< frameWidthInCU; idxX++)

  }//!< for (idxY = 0; idxY< frameHeightInCU; idxY++)

#if SAO_ENCODING_CHOICE

#if SAO_ENCODING_CHOICE_CHROMA

  if( !saoParam->bSaoFlag[0])

  {

    m_depthSaoRate[0][depth] = 1.0;

  }

  else

  {

    m_depthSaoRate[0][depth] = numNoSao[0]/((Double) frameHeightInCU*frameWidthInCU);

  }

  if( !saoParam->bSaoFlag[1])

  {

    m_depthSaoRate[1][depth] = 1.0;

  }

  else

  {

    m_depthSaoRate[1][depth] = numNoSao[1]/((Double) frameHeightInCU*frameWidthInCU*2);

  }

#else

  if( depth == 0)

  {

    // update SAO Rate

    m_depth0SaoRate = numNoSao/((Double) frameHeightInCU*frameWidthInCU*3);

  }

#endif

#endif

 

}
(轉載請註明出處)

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