(转载请注明出处)
HM10.0给出了两种预测算法:全搜索和TZSearch。
其中TZSearch算法步骤入下:
①由AMVP确定搜索起点即若干候选MV,选一个RDCost最小的作为起点。
②以菱形模板或正方形模板进行搜索。
③若上一步得到的最优步长为1,则再补充搜索最近的两个点。
若步长不是1,不用再搜索了。
若步长太长(大于某阈值),则以最优点为中心做全搜索。
④以上一步最优点为起始点,重复②③,直到连续两次得到的最优点相同,即为最优MV。
在xTZSearch中可以看到以上所述全过程。
H.265中还加入了亚像素精度估计,亮度达到了1/4像素估计,色度达到了1/8像素估计。
代码部分按HEVC_CJL给出的思路来的。链接:http://blog.youkuaiyun.com/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
}