[置顶] HEVC帧间预测之四——运动估计(一)

其实HM的运动估计这部分与H.264相比基本没有变化,如果看过JMVC运动估计的代码,会发现xTZSearch的结构几乎就是一样的。所以,严格来讲,这部分的东西没有什么太多新鲜的东西,相信以前研究过TZSearch的人看这部分代码会很轻松。先看运动估计的主调函数:

//!< 运动估计
Void TEncSearch::xMotionEstimation( TComDataCU* pcCU, TComYuv* pcYuvOrg, Int iPartIdx, RefPicList eRefPicList, TComMv* pcMvPred, Int iRefIdxPred, TComMv& rcMv, UInt& ruiBits, UInt& ruiCost, Bool bBi  )
{
  UInt          uiPartAddr;
  Int           iRoiWidth;
  Int           iRoiHeight;
  
  TComMv        cMvHalf, cMvQter;
  TComMv        cMvSrchRngLT;
  TComMv        cMvSrchRngRB;
  
  TComYuv*      pcYuv = pcYuvOrg;
  m_iSearchRange = m_aaiAdaptSR[eRefPicList][iRefIdxPred]; //!< 根据参考帧列表类型、参考帧序号自适应设置搜索范围
  
  Int           iSrchRng      = ( bBi ? m_bipredSearchRange : m_iSearchRange ); //!< 根据是否是双向预测设置搜索范围
  TComPattern*  pcPatternKey  = pcCU->getPattern        (); //!< 用于获取neighbor的信息
  
  Double        fWeight       = 1.0;
  
  pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight ); //!< 获取PU的地址,宽度和高度
  
  if ( bBi )
  {
    TComYuv*  pcYuvOther = &m_acYuvPred[1-(Int)eRefPicList];
    pcYuv                = &m_cYuvPredTemp;
    
    pcYuvOrg->copyPartToPartYuv( pcYuv, uiPartAddr, iRoiWidth, iRoiHeight );
    
    pcYuv->removeHighFreq( pcYuvOther, uiPartAddr, iRoiWidth, iRoiHeight );
    
    fWeight = 0.5;
  }
  
  //  Search key pattern initialization
  pcPatternKey->initPattern( pcYuv->getLumaAddr( uiPartAddr ),
                            pcYuv->getCbAddr  ( uiPartAddr ),
                            pcYuv->getCrAddr  ( uiPartAddr ),
                            iRoiWidth,
                            iRoiHeight,
                            pcYuv->getStride(),
                            0, 0, 0, 0 ); //!< 设置待搜索的PU的相关参数,首地址,宽度,高度,跨度等
  //!< 获取参考图像首地址和跨度
  Pel*        piRefY      = pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getPicYuvRec()->getLumaAddr( pcCU->getAddr(), pcCU->getZorderIdxInCU() + uiPartAddr );
  Int         iRefStride  = pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getPicYuvRec()->getStride();
  
  TComMv      cMvPred = *pcMvPred;
  //!< 设置运动估计的搜索范围,LeftTop & RightBottom
  if ( bBi )  xSetSearchRange   ( pcCU, rcMv   , iSrchRng, cMvSrchRngLT, cMvSrchRngRB );
  else        xSetSearchRange   ( pcCU, cMvPred, iSrchRng, cMvSrchRngLT, cMvSrchRngRB );
  
  m_pcRdCost->getMotionCost ( 1, 0 );
  
  m_pcRdCost->setPredictor  ( *pcMvPred ); //!< m_mvPredictor = *pcMvPred
  m_pcRdCost->setCostScale  ( 2 );

  setWpScalingDistParam( pcCU, iRefIdxPred, eRefPicList ); //!< 设置跟weighted prediction相关的参数
  //  Do integer search
  if ( !m_iFastSearch || bBi ) //!< m_iFastSearch is true
  {
    xPatternSearch      ( pcPatternKey, piRefY, iRefStride, &cMvSrchRngLT, &cMvSrchRngRB, rcMv, ruiCost );
  }
  else //!< Fast Search
  {
    rcMv = *pcMvPred;
    xPatternSearchFast  ( pcCU, pcPatternKey, piRefY, iRefStride, &cMvSrchRngLT, &cMvSrchRngRB, rcMv, ruiCost );
  }
  
  m_pcRdCost->getMotionCost( 1, 0 );
  m_pcRdCost->setCostScale ( 1 );
  
  {//!< 分像素搜索
    xPatternSearchFracDIF( pcCU, pcPatternKey, piRefY, iRefStride, &rcMv, cMvHalf, cMvQter, ruiCost
                          ,bBi
                          );
  }
  
  
  
  m_pcRdCost->setCostScale( 0 );
  rcMv <<= 2;						//!< 整像素
  rcMv += (cMvHalf <<= 1);	//!< 1/2 像素
  rcMv +=  cMvQter;				//!< 1/4 像素
  //!< 故rcMv最终以1/4像素为单位
  UInt uiMvBits = m_pcRdCost->getBits( rcMv.getHor(), rcMv.getVer() );
  
  ruiBits      += uiMvBits;
  ruiCost       = (UInt)( floor( fWeight * ( (Double)ruiCost - (Double)m_pcRdCost->getCost( uiMvBits ) ) ) + (Double)m_pcRdCost->getCost( ruiBits ) );
}

基本思想就是用TZSearch算法先进行整像素搜索,确定一个局部的最佳值,然后以这个最佳点为中心再进行精度更高的分像素搜索。

 

接下来我们先考虑整像素搜索的情况,进入到xPatternSearchFast中去:

Void TEncSearch::xPatternSearchFast( TComDataCU* pcCU, TComPattern* pcPatternKey, Pel* piRefY, Int iRefStride, TComMv* pcMvSrchRngLT, TComMv* pcMvSrchRngRB, TComMv& rcMv, UInt& ruiSAD )
{//!< 获取相邻PU: A, B, C的运动矢量,作为预测运动矢量
  pcCU->getMvPredLeft       ( m_acMvPredictors[0] );
  pcCU->getMvPredAbove      ( m_acMvPredictors[1] );
  pcCU->getMvPredAboveRight ( m_acMvPredictors[2] );
  
  switch ( m_iFastSearch )
  {
    case 1:
      xTZSearch( pcCU, pcPatternKey, piRefY, iRefStride, pcMvSrchRngLT, pcMvSrchRngRB, rcMv, ruiSAD );
      break;
      
    default:
      break;
  }
}

我们可以看到,这个函数很短,先是获得预测的运动矢量,接着调用xTZSearch进行搜索,xTZSearch这个函数相对比较长,里面调用了很多子函数,因此,一口气讲完这个函数不容易,改为一步步分析各个子函数,再合起来分析xTZSearch的整体功能。


你可能感兴趣的:(hm,motion,HEVC,运动估计,Estimaion)