(轉載請註明出處)
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
}