幀間預測--運動估計代碼分析

(轉載請註明出處)

HM10.0給出了兩種預測算法:全搜索和TZSearch

其中TZSearch算法步驟入下:

AMVP確定搜索起點即若干候選MV,選一個RDCost最小的作爲起點。

②以菱形模板或正方形模板進行搜索。

若上一步得到的最優步長爲1,則再補充搜索最近的兩個點。

   若步長不是1,不用再搜索了。

   若步長太長(大於某閾值),則以最優點爲中心做全搜索。

④以上一步最優點爲起始點,重複②③,直到連續兩次得到的最優點相同,即爲最優MV。

xTZSearch中可以看到以上所述全過程。

H.265中還加入了亞像素精度估計,亮度達到了1/4像素估計,色度達到了1/8像素估計。

代碼部分按HEVC_CJL給出的思路來的。鏈接:http://blog.csdn.net/HEVC_CJL

運動估計xMotionEstimation中調用xPatternSearchFast做整像素搜索,xPatternSearchFast中調用了xTZSearch完成搜索。具體如下:

1.xMotionEstimation

//!<運動估計

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;//1/2步長、1/4步長

  TComMv        cMvSrchRngLT;//搜索左上

  TComMv        cMvSrchRngRB;//搜索右下

  

  TComYuv*      pcYuv = pcYuvOrg;

  m_iSearchRange = m_aaiAdaptSR[eRefPicList][iRefIdxPred];//根據參考幀列表、參考幀序號設置搜索範圍

  

  Int           iSrchRng      = ( bBi ? m_bipredSearchRange : m_iSearchRange );//是否雙向搜索

  TComPattern*  pcPatternKey  = pcCU->getPattern        ();

  

  Double        fWeight       = 1.0;

  

  pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );//由CU劃分方式調整width、height

  

  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搜索關鍵模式初始化

  // 設置待搜索PU的相關參數,首地址,寬度,高度,跨度等

  pcPatternKey->initPattern( pcYuv->getLumaAddr( uiPartAddr ),

                            pcYuv->getCbAddr  ( uiPartAddr ),

                            pcYuv->getCrAddr  ( uiPartAddr ),

                            iRoiWidth,

                            iRoiHeight,

                            pcYuv->getStride(),

                            0, 0 );

  

  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 )

  {

    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像素

  

  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 ) );

}


2.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 )//這裏只有TZsearch

  {

    case 1:

      xTZSearch( pcCU, pcPatternKey, piRefY, iRefStride, pcMvSrchRngLT, pcMvSrchRngRB, rcMv, ruiSAD );

      break;

      

    default:

      break;

  }

}


3.xTZSearch

Void TEncSearch::xTZSearch( TComDataCU* pcCU, TComPattern* pcPatternKey, Pel* piRefY, Int iRefStride, TComMv* pcMvSrchRngLT, TComMv* pcMvSrchRngRB, TComMv& rcMv, UInt& ruiSAD )

{

  

  Int   iSrchRngHorLeft   = pcMvSrchRngLT->getHor();

  Int   iSrchRngHorRight  = pcMvSrchRngRB->getHor();

  Int   iSrchRngVerTop    = pcMvSrchRngLT->getVer();

  Int   iSrchRngVerBottom = pcMvSrchRngRB->getVer();

  

  TZ_SEARCH_CONFIGURATION

  

  UInt uiSearchRange = m_iSearchRange;

  pcCU->clipMv( rcMv );

  rcMv >>= 2;

  // init TZSearchStruct

  IntTZSearchStruct cStruct;

  cStruct.iYStride    = iRefStride;

  cStruct.piRefY      = piRefY;

  cStruct.uiBestSad   = MAX_UINT;

  

  // set rcMv (Median predictor) as start point and as best point

  //以中點爲做運動搜索起點

  xTZSearchHelp( pcPatternKey, cStruct, rcMv.getHor(), rcMv.getVer(), 0, 0 );

  //中值預測

  // test whether one of PRED_A, PRED_B, PRED_C MV is better start point than Median predictor

  if ( bTestOtherPredictedMV )

  {

    for ( UInt index = 0; index < 3; index++ )

    {

      TComMv cMv = m_acMvPredictors[index];

      pcCU->clipMv( cMv );

      cMv >>= 2;

      xTZSearchHelp( pcPatternKey, cStruct, cMv.getHor(), cMv.getVer(), 0, 0 );

    }

  }

  

  // test whether zero Mv is better start point than Median predictor

  if ( bTestZeroVector )

  {

    xTZSearchHelp( pcPatternKey, cStruct, 0, 0, 0, 0 );

  }

  

  // start search

  Int  iDist = 0;

  Int  iStartX = cStruct.iBestX;

  Int  iStartY = cStruct.iBestY;

  

  // first search

  for ( iDist = 1; iDist <= (Int)uiSearchRange; iDist*=2 )

  {

    if ( bFirstSearchDiamond == 1 )

    {

      xTZ8PointDiamondSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist );

    }

    else

    {

      xTZ8PointSquareSearch  ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist );

    }

    

    if ( bFirstSearchStop && ( cStruct.uiBestRound >= uiFirstSearchRounds ) ) // stop criterion

    {

      break;

    }

  }

  

  // test whether zero Mv is a better start point than Median predictor

  if ( bTestZeroVectorStart && ((cStruct.iBestX != 0) || (cStruct.iBestY != 0)) )

  {

    xTZSearchHelp( pcPatternKey, cStruct, 0, 0, 0, 0 );

    if ( (cStruct.iBestX == 0) && (cStruct.iBestY == 0) )

    {

      // test its neighborhood

      for ( iDist = 1; iDist <= (Int)uiSearchRange; iDist*=2 )

      {

        xTZ8PointDiamondSearch( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, 0, 0, iDist );

        if ( bTestZeroVectorStop && (cStruct.uiBestRound > 0) ) // stop criterion

        {

          break;

        }

      }

    }

  }

  

  // calculate only 2 missing points instead 8 points if cStruct.uiBestDistance == 1

  if ( cStruct.uiBestDistance == 1 )

  {

    cStruct.uiBestDistance = 0;

    xTZ2PointSearch( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB );

  }

  

  // raster search if distance is too big全搜索

  if ( bEnableRasterSearch && ( ((Int)(cStruct.uiBestDistance) > iRaster) || bAlwaysRasterSearch ) )

  {

    cStruct.uiBestDistance = iRaster;

    for ( iStartY = iSrchRngVerTop; iStartY <= iSrchRngVerBottom; iStartY += iRaster )

    {

      for ( iStartX = iSrchRngHorLeft; iStartX <= iSrchRngHorRight; iStartX += iRaster )

      {

        xTZSearchHelp( pcPatternKey, cStruct, iStartX, iStartY, 0, iRaster );

      }

    }

  }

  

  // raster refinement

  if ( bRasterRefinementEnable && cStruct.uiBestDistance > 0 )

  {

    while ( cStruct.uiBestDistance > 0 )

    {

      iStartX = cStruct.iBestX;

      iStartY = cStruct.iBestY;

      if ( cStruct.uiBestDistance > 1 )

      {

        iDist = cStruct.uiBestDistance >>= 1;

        if ( bRasterRefinementDiamond == 1 )

        {//菱形搜索

          xTZ8PointDiamondSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist );

        }

        else

        {//方形搜索

          xTZ8PointSquareSearch  ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist );

        }

      }

      

      // calculate only 2 missing points instead 8 points if cStruct.uiBestDistance == 1

      if ( cStruct.uiBestDistance == 1 )

      {

        cStruct.uiBestDistance = 0;

        if ( cStruct.ucPointNr != 0 )

        {

          xTZ2PointSearch( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB );

        }

      }

    }

  }

  

  // start refinement

  if ( bStarRefinementEnable && cStruct.uiBestDistance > 0 )

  {

    while ( cStruct.uiBestDistance > 0 )

    {

      iStartX = cStruct.iBestX;

      iStartY = cStruct.iBestY;

      cStruct.uiBestDistance = 0;

      cStruct.ucPointNr = 0;

      for ( iDist = 1; iDist < (Int)uiSearchRange + 1; iDist*=2 )

      {

        if ( bStarRefinementDiamond == 1 )

        {

          xTZ8PointDiamondSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist );

        }

        else

        {

          xTZ8PointSquareSearch  ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist );

        }

        if ( bStarRefinementStop && (cStruct.uiBestRound >= uiStarRefinementRounds) ) // stop criterion

        {

          break;

        }

      }

      

      // calculate only 2 missing points instead 8 points if cStrukt.uiBestDistance == 1

      if ( cStruct.uiBestDistance == 1 )

      {

        cStruct.uiBestDistance = 0;

        if ( cStruct.ucPointNr != 0 )

        {

          xTZ2PointSearch( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB );

        }

      }

    }

  }

  

  // write out best match

  rcMv.set( cStruct.iBestX, cStruct.iBestY );

  ruiSAD = cStruct.uiBestSad - m_pcRdCost->getCost( cStruct.iBestX, cStruct.iBestY );

}


4.xTZSearchHelp

//計算SAD並對比,選最佳

__inline Void TEncSearch::xTZSearchHelp( TComPattern* pcPatternKey, IntTZSearchStruct& rcStruct, const Int iSearchX, const Int iSearchY, const UChar ucPointNr, const UInt uiDistance )

{

  UInt  uiSad;

  

  Pel*  piRefSrch;

  //參考圖像亮度分量的起始地址

  piRefSrch = rcStruct.piRefY + iSearchY * rcStruct.iYStride + iSearchX;

  

  //-- jclee for using the SAD function  pointer

  //設置計算SAD函數指針,後面分析

  m_pcRdCost->setDistParam( pcPatternKey, piRefSrch, rcStruct.iYStride,  m_cDistParam );

  

  // fast encoder decision: use subsampled SAD when rows > 8 for integer ME

  if ( m_pcEncCfg->getUseFastEnc() )

  {

    if ( m_cDistParam.iRows > 8 )

    {

      m_cDistParam.iSubShift = 1;

    }

  }

 

  setDistParamComp(0);  // Y component

 

  // distortion 失真

  m_cDistParam.bitDepth = g_bitDepthY;//位深

  uiSad = m_cDistParam.DistFunc( &m_cDistParam );//計算SAD

  

  // motion cost

  uiSad += m_pcRdCost->getCost( iSearchX, iSearchY );//考慮加上MV本身帶來的開銷

  

  if( uiSad < rcStruct.uiBestSad )//更新最佳值

  {

    rcStruct.uiBestSad      = uiSad;//SAD

    rcStruct.iBestX         = iSearchX;//mv_x,

    rcStruct.iBestY         = iSearchY;//mv_y

    rcStruct.uiBestDistance = uiDistance;//搜索步長

    rcStruct.uiBestRound    = 0;//搜索次數

    rcStruct.ucPointNr      = ucPointNr;//搜索點序號

  }

}


5.xTZ2PointSearch

__inline Void TEncSearch::xTZ2PointSearch( TComPattern* pcPatternKey, IntTZSearchStruct& rcStruct, TComMv* pcMvSrchRngLT, TComMv* pcMvSrchRngRB )

{

  Int   iSrchRngHorLeft   = pcMvSrchRngLT->getHor();

  Int   iSrchRngHorRight  = pcMvSrchRngRB->getHor();

  Int   iSrchRngVerTop    = pcMvSrchRngLT->getVer();

  Int   iSrchRngVerBottom = pcMvSrchRngRB->getVer();

  

  // 2 point search,                   //   1 2 3

  // check only the 2 untested points  //   4 0 5

  // around the start point            //   6 7 8

  // 1 3 6 8 是搜索步長IDist==2的時候由IDist>>1進行賦值的,\

     實際距離以1計算

  // 在前面經過xTZ8PointSearch確定最佳步長爲1後,\

     會在這裏對以最佳點爲中心、周圍沒搜索過的點進行運動估計

  Int iStartX = rcStruct.iBestX;

  Int iStartY = rcStruct.iBestY;

  switch( rcStruct.ucPointNr )//主要思想是根據最佳點的位置處理未搜索過的點

  {

    //點的分佈,0代表(iStartX,iStartY)

    //1 2 3

    //4 0 5

    //6 7 8

    //僅是一個選擇點的過程,兩點過程選擇一個點後,對這個點做兩點搜索

    case 1://若爲1,選擇離1最近的兩個點,2和4

    {

      if ( (iStartX - 1) >= iSrchRngHorLeft )

      {//左,4

        xTZSearchHelp( pcPatternKey, rcStruct, iStartX - 1, iStartY, 0, 2 );

      }

      if ( (iStartY - 1) >= iSrchRngVerTop )

      {//上,2

        xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iStartY - 1, 0, 2 );

      }

    }

      break;

    case 2://同樣離2最近爲1,3

    {

      if ( (iStartY - 1) >= iSrchRngVerTop )

      {

        if ( (iStartX - 1) >= iSrchRngHorLeft )

        {//左上,點1

          xTZSearchHelp( pcPatternKey, rcStruct, iStartX - 1, iStartY - 1, 0, 2 );

        }

        if ( (iStartX + 1) <= iSrchRngHorRight )

        {//右上,點3

          xTZSearchHelp( pcPatternKey, rcStruct, iStartX + 1, iStartY - 1, 0, 2 );

        }

      }

    }

      break;

    case 3://離3最近爲2,5

    {

      if ( (iStartY - 1) >= iSrchRngVerTop )

      {//上,點2

        xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iStartY - 1, 0, 2 );

      }

      if ( (iStartX + 1) <= iSrchRngHorRight )

      {//右,點5

        xTZSearchHelp( pcPatternKey, rcStruct, iStartX + 1, iStartY, 0, 2 );

      }

    }

      break;

    case 4://1,6

    {

      if ( (iStartX - 1) >= iSrchRngHorLeft )

      {

        if ( (iStartY + 1) <= iSrchRngVerBottom )

        {//左下,點6

          xTZSearchHelp( pcPatternKey, rcStruct, iStartX - 1, iStartY + 1, 0, 2 );

        }

        if ( (iStartY - 1) >= iSrchRngVerTop )

        {//左上,點1

          xTZSearchHelp( pcPatternKey, rcStruct, iStartX - 1, iStartY - 1, 0, 2 );

        }

      }

    }

      break;

    case 5://離5最近3,8

    {

      if ( (iStartX + 1) <= iSrchRngHorRight )

      {

        if ( (iStartY - 1) >= iSrchRngVerTop )

        {

          xTZSearchHelp( pcPatternKey, rcStruct, iStartX + 1, iStartY - 1, 0, 2 );

        }

        if ( (iStartY + 1) <= iSrchRngVerBottom )

        {

          xTZSearchHelp( pcPatternKey, rcStruct, iStartX + 1, iStartY + 1, 0, 2 );

        }

      }

    }

      break;

    case 6://4,7

    {

      if ( (iStartX - 1) >= iSrchRngHorLeft )

      {

        xTZSearchHelp( pcPatternKey, rcStruct, iStartX - 1, iStartY , 0, 2 );

      }

      if ( (iStartY + 1) <= iSrchRngVerBottom )

      {

        xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iStartY + 1, 0, 2 );

      }

    }

      break;

    case 7://6,8

    {

      if ( (iStartY + 1) <= iSrchRngVerBottom )

      {

        if ( (iStartX - 1) >= iSrchRngHorLeft )

        {

          xTZSearchHelp( pcPatternKey, rcStruct, iStartX - 1, iStartY + 1, 0, 2 );

        }

        if ( (iStartX + 1) <= iSrchRngHorRight )

        {

          xTZSearchHelp( pcPatternKey, rcStruct, iStartX + 1, iStartY + 1, 0, 2 );

        }

      }

    }

      break;

    case 8://5,7

    {

      if ( (iStartX + 1) <= iSrchRngHorRight )

      {

        xTZSearchHelp( pcPatternKey, rcStruct, iStartX + 1, iStartY, 0, 2 );

      }

      if ( (iStartY + 1) <= iSrchRngVerBottom )

      {

        xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iStartY + 1, 0, 2 );

      }

    }

      break;

    default:

    {

      assert( false );

    }

      break;

  } // switch( rcStruct.ucPointNr )

}


6.xTZ8PointDiamondSearch

__inline Void TEncSearch::xTZ8PointDiamondSearch( TComPattern* pcPatternKey, IntTZSearchStruct& rcStruct, TComMv* pcMvSrchRngLT, TComMv* pcMvSrchRngRB, const Int iStartX, const Int iStartY, const Int iDist )

{

  Int   iSrchRngHorLeft   = pcMvSrchRngLT->getHor();

  Int   iSrchRngHorRight  = pcMvSrchRngRB->getHor();

  Int   iSrchRngVerTop    = pcMvSrchRngLT->getVer();

  Int   iSrchRngVerBottom = pcMvSrchRngRB->getVer();

  

  // 8 point search,                   //   1 2 3

  // search around the start point     //   4 0 5

  // with the required  distance       //   6 7 8

  assert ( iDist != 0 );

  const Int iTop        = iStartY - iDist;//iDist爲每次搜索的步長

  const Int iBottom     = iStartY + iDist;

  const Int iLeft       = iStartX - iDist;

  const Int iRight      = iStartX + iDist;

  rcStruct.uiBestRound += 1;//每次調用xTZSearchHelp,一旦發現當前搜索點的SAD小於最佳值\

  將uiBestRound清零

  

  if ( iDist == 1 ) // iDist == 1

  {//步長爲1時,菱形就上下左右四個點

    if ( iTop >= iSrchRngVerTop ) // check top

    {

      xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iTop, 2, iDist );

    }

    if ( iLeft >= iSrchRngHorLeft ) // check middle left

    {

      xTZSearchHelp( pcPatternKey, rcStruct, iLeft, iStartY, 4, iDist );

    }

    if ( iRight <= iSrchRngHorRight ) // check middle right

    {

      xTZSearchHelp( pcPatternKey, rcStruct, iRight, iStartY, 5, iDist );

    }

    if ( iBottom <= iSrchRngVerBottom ) // check bottom

    {

      xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iBottom, 7, iDist );

    }

  }

  else // if (iDist != 1)

  {

    if ( iDist <= 8 )

    {

      const Int iTop_2      = iStartY - (iDist>>1);

      const Int iBottom_2   = iStartY + (iDist>>1);

      const Int iLeft_2     = iStartX - (iDist>>1);

      const Int iRight_2    = iStartX + (iDist>>1);

      

      if (  iTop >= iSrchRngVerTop && iLeft >= iSrchRngHorLeft &&

          iRight <= iSrchRngHorRight && iBottom <= iSrchRngVerBottom ) // check border

      {//共8個點,實現的具體原理得需要把Help理清才能明白

        xTZSearchHelp( pcPatternKey, rcStruct, iStartX,  iTop,      2, iDist    );

        xTZSearchHelp( pcPatternKey, rcStruct, iLeft_2,  iTop_2,    1, iDist>>1 );

        xTZSearchHelp( pcPatternKey, rcStruct, iRight_2, iTop_2,    3, iDist>>1 );

        xTZSearchHelp( pcPatternKey, rcStruct, iLeft,    iStartY,   4, iDist    );

        xTZSearchHelp( pcPatternKey, rcStruct, iRight,   iStartY,   5, iDist    );

        xTZSearchHelp( pcPatternKey, rcStruct, iLeft_2,  iBottom_2, 6, iDist>>1 );

        xTZSearchHelp( pcPatternKey, rcStruct, iRight_2, iBottom_2, 8, iDist>>1 );

        xTZSearchHelp( pcPatternKey, rcStruct, iStartX,  iBottom,   7, iDist    );

      }

      else // check border,不能全部同時滿足,把能搜的搜了

      {

        if ( iTop >= iSrchRngVerTop ) // check top

        {

          xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iTop, 2, iDist );

        }

        if ( iTop_2 >= iSrchRngVerTop ) // check half top

        {

          if ( iLeft_2 >= iSrchRngHorLeft ) // check half left

          {

            xTZSearchHelp( pcPatternKey, rcStruct, iLeft_2, iTop_2, 1, (iDist>>1) );

          }

          if ( iRight_2 <= iSrchRngHorRight ) // check half right

          {

            xTZSearchHelp( pcPatternKey, rcStruct, iRight_2, iTop_2, 3, (iDist>>1) );

          }

        } // check half top

        if ( iLeft >= iSrchRngHorLeft ) // check left

        {

          xTZSearchHelp( pcPatternKey, rcStruct, iLeft, iStartY, 4, iDist );

        }

        if ( iRight <= iSrchRngHorRight ) // check right

        {

          xTZSearchHelp( pcPatternKey, rcStruct, iRight, iStartY, 5, iDist );

        }

        if ( iBottom_2 <= iSrchRngVerBottom ) // check half bottom

        {

          if ( iLeft_2 >= iSrchRngHorLeft ) // check half left

          {

            xTZSearchHelp( pcPatternKey, rcStruct, iLeft_2, iBottom_2, 6, (iDist>>1) );

          }

          if ( iRight_2 <= iSrchRngHorRight ) // check half right

          {

            xTZSearchHelp( pcPatternKey, rcStruct, iRight_2, iBottom_2, 8, (iDist>>1) );

          }

        } // check half bottom

        if ( iBottom <= iSrchRngVerBottom ) // check bottom

        {

          xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iBottom, 7, iDist );

        }

      } // check border

    }

    else // iDist > 8,搜索步長大於8後,uiPointNr統一設置爲0

    {

      if ( iTop >= iSrchRngVerTop && iLeft >= iSrchRngHorLeft &&

          iRight <= iSrchRngHorRight && iBottom <= iSrchRngVerBottom ) // check border

      {

        xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iTop,    0, iDist );

        xTZSearchHelp( pcPatternKey, rcStruct, iLeft,   iStartY, 0, iDist );

        xTZSearchHelp( pcPatternKey, rcStruct, iRight,  iStartY, 0, iDist );

        xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iBottom, 0, iDist );

        for ( Int index = 1; index < 4; index++ )

        {

          Int iPosYT = iTop    + ((iDist>>2) * index);

          Int iPosYB = iBottom - ((iDist>>2) * index);

          Int iPosXL = iStartX - ((iDist>>2) * index);

          Int iPosXR = iStartX + ((iDist>>2) * index);

          xTZSearchHelp( pcPatternKey, rcStruct, iPosXL, iPosYT, 0, iDist );

          xTZSearchHelp( pcPatternKey, rcStruct, iPosXR, iPosYT, 0, iDist );

          xTZSearchHelp( pcPatternKey, rcStruct, iPosXL, iPosYB, 0, iDist );

          xTZSearchHelp( pcPatternKey, rcStruct, iPosXR, iPosYB, 0, iDist );

        }

      }

      else // check border

      {

        if ( iTop >= iSrchRngVerTop ) // check top

        {

          xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iTop, 0, iDist );

        }

        if ( iLeft >= iSrchRngHorLeft ) // check left

        {

          xTZSearchHelp( pcPatternKey, rcStruct, iLeft, iStartY, 0, iDist );

        }

        if ( iRight <= iSrchRngHorRight ) // check right

        {

          xTZSearchHelp( pcPatternKey, rcStruct, iRight, iStartY, 0, iDist );

        }

        if ( iBottom <= iSrchRngVerBottom ) // check bottom

        {

          xTZSearchHelp( pcPatternKey, rcStruct, iStartX, iBottom, 0, iDist );

        }

        for ( Int index = 1; index < 4; index++ )

        {

          Int iPosYT = iTop    + ((iDist>>2) * index);

          Int iPosYB = iBottom - ((iDist>>2) * index);

          Int iPosXL = iStartX - ((iDist>>2) * index);

          Int iPosXR = iStartX + ((iDist>>2) * index);

          

          if ( iPosYT >= iSrchRngVerTop ) // check top

          {

            if ( iPosXL >= iSrchRngHorLeft ) // check left

            {

              xTZSearchHelp( pcPatternKey, rcStruct, iPosXL, iPosYT, 0, iDist );

            }

            if ( iPosXR <= iSrchRngHorRight ) // check right

            {

              xTZSearchHelp( pcPatternKey, rcStruct, iPosXR, iPosYT, 0, iDist );

            }

          } // check top

          if ( iPosYB <= iSrchRngVerBottom ) // check bottom

          {

            if ( iPosXL >= iSrchRngHorLeft ) // check left

            {

              xTZSearchHelp( pcPatternKey, rcStruct, iPosXL, iPosYB, 0, iDist );

            }

            if ( iPosXR <= iSrchRngHorRight ) // check right

            {

              xTZSearchHelp( pcPatternKey, rcStruct, iPosXR, iPosYB, 0, iDist );

            }

          } // check bottom

        } // for ...

      } // check border

    } // iDist <= 8

  } // iDist == 1

}



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