HTM-16.2代码(11)——xTZSearch
来源:互联网 发布:淘宝待清洗订单 编辑:程序博客网 时间:2024/06/05 10:22
TZSearch的基本流程:
1、搜索预测得到的mv所指向的点:中值预测mv,当前PU的左,上及右上PU的mv,还有零运动矢量(0,0);
2、在步骤1中找到匹配误差最小的点作为接下来搜索的起始点;
3、步长从1开始,以2的指数递增,进行8点钻石搜索,该步骤中可以设置搜索的最大次数(以某个步长遍历一遍就算1次);
4、如果步骤3搜索得到的最佳步长为1,则需要以该最佳点为起点做1次两点钻石搜索,因为前面8点搜索的时候,这个最佳点的8个邻点会有两个没有搜索到;
5、如果步骤3搜索得到的最佳步长大于某个阈值(iRaster),则以步骤2得到的点作为起点,做步长为iRaster的光栅扫描(即在运动搜索的范围内遍历所有点);
6、 最后,在经过前面1~5歩之后,以得到的最佳点为起点,再次重复步骤3和4;
7、保存最佳mv和SAD。
Void TEncSearch::xTZSearch( const TComDataCU* const pcCU, const TComPattern* const pcPatternKey, const Pel* const piRefY, const Int iRefStride, const TComMv* const pcMvSrchRngLT, const TComMv* const pcMvSrchRngRB, TComMv &rcMv, Distortion &ruiSAD, const TComMv* const pIntegerMv2Nx2NPred, const Bool bExtendedSettings){ const Bool bUseAdaptiveRaster = bExtendedSettings; const Int iRaster = 5; const Bool bTestOtherPredictedMV = bExtendedSettings; const Bool bTestZeroVector = true; const Bool bTestZeroVectorStart = bExtendedSettings; const Bool bTestZeroVectorStop = false; const Bool bFirstSearchDiamond = true; // 1 = xTZ8PointDiamondSearch 0 = xTZ8PointSquareSearch const Bool bFirstCornersForDiamondDist1 = bExtendedSettings; const Bool bFirstSearchStop = m_pcEncCfg->getFastMEAssumingSmootherMVEnabled(); const UInt uiFirstSearchRounds = 3; // first search stop X rounds after best match (must be >=1) const Bool bEnableRasterSearch = true; const Bool bAlwaysRasterSearch = bExtendedSettings; // true: BETTER but factor 2 slower const Bool bRasterRefinementEnable = false; // enable either raster refinement or star refinement const Bool bRasterRefinementDiamond = false; // 1 = xTZ8PointDiamondSearch 0 = xTZ8PointSquareSearch const Bool bRasterRefinementCornersForDiamondDist1 = bExtendedSettings; const Bool bStarRefinementEnable = true; // enable either star refinement or raster refinement const Bool bStarRefinementDiamond = true; // 1 = xTZ8PointDiamondSearch 0 = xTZ8PointSquareSearch const Bool bStarRefinementCornersForDiamondDist1 = bExtendedSettings; const Bool bStarRefinementStop = false; const UInt uiStarRefinementRounds = 2; // star refinement stop X rounds after best match (must be >=1) const Bool bNewZeroNeighbourhoodTest = bExtendedSettings; UInt uiSearchRange = m_iSearchRange; pcCU->clipMv( rcMv );#if NH_3D_INTEGER_MV_DEPTH if( ! pcCU->getSlice()->getIsDepth() )#endif#if ME_ENABLE_ROUNDING_OF_MVS rcMv.divideByPowerOf2(2);#else rcMv >>= 2;#endif // 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 < NUM_MV_PREDICTORS; index++ ) { TComMv cMv = m_acMvPredictors[index]; pcCU->clipMv( cMv );#if NH_3D_INTEGER_MV_DEPTH if( ! pcCU->getSlice()->getIsDepth() ) { #endif#if ME_ENABLE_ROUNDING_OF_MVS cMv.divideByPowerOf2(2);#else cMv >>= 2;#endif#if NH_3D_INTEGER_MV_DEPTH }#endif if (cMv != rcMv && (cMv.getHor() != cStruct.iBestX && cMv.getVer() != cStruct.iBestY)) { // only test cMV if not obviously previously tested. xTZSearchHelp( pcPatternKey, cStruct, cMv.getHor(), cMv.getVer(), 0, 0 ); //A, B, C相邻PU的mv } } } // test whether zero Mv is better start point than Median predictor if ( bTestZeroVector ) { if ((rcMv.getHor() != 0 || rcMv.getVer() != 0) && (0 != cStruct.iBestX || 0 != cStruct.iBestY)) { // only test 0-vector if not obviously previously tested. xTZSearchHelp( pcPatternKey, cStruct, 0, 0, 0, 0 );//!< 零mv } } Int iSrchRngHorLeft = pcMvSrchRngLT->getHor(); Int iSrchRngHorRight = pcMvSrchRngRB->getHor(); Int iSrchRngVerTop = pcMvSrchRngLT->getVer(); Int iSrchRngVerBottom = pcMvSrchRngRB->getVer(); if (pIntegerMv2Nx2NPred != 0) { TComMv integerMv2Nx2NPred = *pIntegerMv2Nx2NPred; integerMv2Nx2NPred <<= 2; pcCU->clipMv( integerMv2Nx2NPred );#if ME_ENABLE_ROUNDING_OF_MVS integerMv2Nx2NPred.divideByPowerOf2(2);#else integerMv2Nx2NPred >>= 2;#endif if ((rcMv != integerMv2Nx2NPred) && (integerMv2Nx2NPred.getHor() != cStruct.iBestX || integerMv2Nx2NPred.getVer() != cStruct.iBestY)) { // only test integerMv2Nx2NPred if not obviously previously tested. xTZSearchHelp(pcPatternKey, cStruct, integerMv2Nx2NPred.getHor(), integerMv2Nx2NPred.getVer(), 0, 0); } // reset search range TComMv cMvSrchRngLT; TComMv cMvSrchRngRB; Int iSrchRng = m_iSearchRange; TComMv currBestMv(cStruct.iBestX, cStruct.iBestY ); currBestMv <<= 2; xSetSearchRange( pcCU, currBestMv, iSrchRng, cMvSrchRngLT, cMvSrchRngRB ); iSrchRngHorLeft = cMvSrchRngLT.getHor(); iSrchRngHorRight = cMvSrchRngRB.getHor(); iSrchRngVerTop = cMvSrchRngLT.getVer(); iSrchRngVerBottom = cMvSrchRngRB.getVer(); } // start search //从以前面几个mv作为搜索起点得到的最好的位置开始进行接下来的搜索 Int iDist = 0; Int iStartX = cStruct.iBestX; Int iStartY = cStruct.iBestY; const Bool bBestCandidateZero = (cStruct.iBestX == 0) && (cStruct.iBestY == 0); // first search around best position up to now. // The following works as a "subsampled/log" window search around the best candidate for ( iDist = 1; iDist <= (Int)uiSearchRange; iDist*=2 )//!< 以2的幂次逐步扩大搜索步长 { if ( bFirstSearchDiamond == 1 ) { xTZ8PointDiamondSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist, bFirstCornersForDiamondDist1 ); } else { xTZ8PointSquareSearch ( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, iStartX, iStartY, iDist ); } if ( bFirstSearchStop && ( cStruct.uiBestRound >= uiFirstSearchRounds ) ) // stop criterion { break; } } if (!bNewZeroNeighbourhoodTest) { // 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, false ); if ( bTestZeroVectorStop && (cStruct.uiBestRound > 0) ) // stop criterion { break; } } } } } else { // Test also zero neighbourhood but with half the range // It was reported that the original (above) search scheme using bTestZeroVectorStart did not // make sense since one would have already checked the zero candidate earlier // and thus the conditions for that test would have not been satisfied if (bTestZeroVectorStart == true && bBestCandidateZero != true) { for ( iDist = 1; iDist <= ((Int)uiSearchRange >> 1); iDist*=2 ) { xTZ8PointDiamondSearch( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB, 0, 0, iDist, false ); if ( bTestZeroVectorStop && (cStruct.uiBestRound > 2) ) // stop criterion { break; } } } } // calculate only 2 missing points instead 8 points if cStruct.uiBestDistance == 1 if ( cStruct.uiBestDistance == 1 )//!< 当最佳搜索步长等于1时,补充搜索前面8点钻石扫描遗漏的两点 { cStruct.uiBestDistance = 0; xTZ2PointSearch( pcPatternKey, cStruct, pcMvSrchRngLT, pcMvSrchRngRB ); } // raster search if distance is too big ////!< 当前面搜索得到的最佳步长过大时,改用光栅搜索法,步长定为iRaster,搜索范围为设定的运动估计范围 if (bUseAdaptiveRaster) { int iWindowSize = iRaster; Int iSrchRngRasterLeft = iSrchRngHorLeft; Int iSrchRngRasterRight = iSrchRngHorRight; Int iSrchRngRasterTop = iSrchRngVerTop; Int iSrchRngRasterBottom = iSrchRngVerBottom; if (!(bEnableRasterSearch && ( ((Int)(cStruct.uiBestDistance) > iRaster)))) { iWindowSize ++; iSrchRngRasterLeft /= 2; iSrchRngRasterRight /= 2; iSrchRngRasterTop /= 2; iSrchRngRasterBottom /= 2; } cStruct.uiBestDistance = iWindowSize; for ( iStartY = iSrchRngRasterTop; iStartY <= iSrchRngRasterBottom; iStartY += iWindowSize ) { for ( iStartX = iSrchRngRasterLeft; iStartX <= iSrchRngRasterRight; iStartX += iWindowSize ) { xTZSearchHelp( pcPatternKey, cStruct, iStartX, iStartY, 0, iWindowSize ); } } } else { 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, bRasterRefinementCornersForDiamondDist1 ); } 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 ); } } } } // star refinement //!< 在经过了上面几个步骤的搜索后,从最佳点开始进行第2次的8点钻石扫描以及利用两点扫描对遗漏点进行补充 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, bStarRefinementCornersForDiamondDist1 ); } 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 获得最佳匹配结果,mv和SAD rcMv.set( cStruct.iBestX, cStruct.iBestY ); ruiSAD = cStruct.uiBestSad - m_pcRdCost->getCostOfVectorWithPredictor( cStruct.iBestX, cStruct.iBestY );}
xTZSearchHelp是当中最为重要的子函数之一。它实现最基本的功能:根据输入的搜索点坐标,参考图像首地址,原始图像首地址,以及当前PU大小等相关信息,计算出SAD,并与之前保存的最佳值进行比较,更新到目前为止的最佳值相关参数,如uiBestSad,搜索点坐标,搜索步长等。其他的函数如xTZ8PointSearch等搜索函数,最终都是调用xTZSearchHelp进行误差匹配的。因此,我们有必要了解xTZSearchHelp这个函数:
__inline Void TEncSearch::xTZSearchHelp( const TComPattern* const pcPatternKey, IntTZSearchStruct& rcStruct, const Int iSearchX, const Int iSearchY, const UChar ucPointNr, const UInt uiDistance ){ Distortion uiSad = 0; const Pel* const piRefSrch = rcStruct.piRefY + iSearchY * rcStruct.iYStride + iSearchX;//参考图像Y分量的起始地址#if NH_3D_IC m_cDistParam.bUseIC = pcPatternKey->getICFlag();#endif#if NH_3D_SDC_INTER m_cDistParam.bUseSDCMRSAD = pcPatternKey->getSDCMRSADFlag();#endif //-- jclee for using the SAD function pointer m_pcRdCost->setDistParam( pcPatternKey, piRefSrch, rcStruct.iYStride, m_cDistParam );//该函数主要职能是设置计算SAD的函数指针 setDistParamComp(COMPONENT_Y); // distortion m_cDistParam.bitDepth = pcPatternKey->getBitDepthY(); m_cDistParam.m_maximumDistortionForEarlyExit = rcStruct.uiBestSad; if((m_pcEncCfg->getRestrictMESampling() == false) && m_pcEncCfg->getMotionEstimationSearchMethod() == MESEARCH_SELECTIVE) { Int isubShift = 0; // motion cost Distortion uiBitCost = m_pcRdCost->getCostOfVectorWithPredictor( iSearchX, iSearchY ); // Skip search if bit cost is already larger than best SAD if (uiBitCost < rcStruct.uiBestSad) { if ( m_cDistParam.iRows > 32 ) { m_cDistParam.iSubShift = 4; } else if ( m_cDistParam.iRows > 16 ) { m_cDistParam.iSubShift = 3; } else if ( m_cDistParam.iRows > 8 ) { m_cDistParam.iSubShift = 2; } else { m_cDistParam.iSubShift = 1; } Distortion uiTempSad = m_cDistParam.DistFunc( &m_cDistParam ); if((uiTempSad + uiBitCost) < rcStruct.uiBestSad) { uiSad += uiTempSad >> m_cDistParam.iSubShift; while(m_cDistParam.iSubShift > 0) { isubShift = m_cDistParam.iSubShift -1; m_cDistParam.pOrg = pcPatternKey->getROIY() + (pcPatternKey->getPatternLStride() << isubShift); m_cDistParam.pCur = piRefSrch + (rcStruct.iYStride << isubShift); uiTempSad = m_cDistParam.DistFunc( &m_cDistParam ); uiSad += uiTempSad >> m_cDistParam.iSubShift; if(((uiSad << isubShift) + uiBitCost) > rcStruct.uiBestSad) { break; } m_cDistParam.iSubShift--; } if(m_cDistParam.iSubShift == 0) { uiSad += uiBitCost; if( uiSad < rcStruct.uiBestSad ) { rcStruct.uiBestSad = uiSad; rcStruct.iBestX = iSearchX; rcStruct.iBestY = iSearchY; rcStruct.uiBestDistance = uiDistance; rcStruct.uiBestRound = 0; rcStruct.ucPointNr = ucPointNr; m_cDistParam.m_maximumDistortionForEarlyExit = uiSad; } } } } } else { // fast encoder decision: use subsampled SAD when rows > 8 for integer ME if ( m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE1 || m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE3 ) { if ( m_cDistParam.iRows > 8 ) { m_cDistParam.iSubShift = 1; } } uiSad = m_cDistParam.DistFunc( &m_cDistParam ); // only add motion cost if uiSad is smaller than best. Otherwise pointless // to add motion cost. if( uiSad < rcStruct.uiBestSad ) { // motion cost uiSad += m_pcRdCost->getCostOfVectorWithPredictor( iSearchX, iSearchY );//!< 考虑上mv本身带来的开销 if( uiSad < rcStruct.uiBestSad )//!< 更新最佳值 { rcStruct.uiBestSad = uiSad;//!< SAD rcStruct.iBestX = iSearchX;//!< mv_x rcStruct.iBestY = iSearchY; rcStruct.uiBestDistance = uiDistance;//!< 搜索步长 rcStruct.uiBestRound = 0;//!< 搜索次数 rcStruct.ucPointNr = ucPointNr;//!< 搜索点序号 m_cDistParam.m_maximumDistortionForEarlyExit = uiSad; } } }}
// Setting the Distortion Parameter for Inter (ME)Void TComRdCost::setDistParam( const TComPattern* const pcPatternKey, const Pel* piRefY, Int iRefStride, DistParam& rcDistParam ){ // set Original & Curr Pointer / Stride rcDistParam.pOrg = pcPatternKey->getROIY();//!< 感兴趣区即待搜索的原始图像首地址 rcDistParam.pCur = piRefY;//!< 参考图像首地址 rcDistParam.iStrideOrg = pcPatternKey->getPatternLStride();//!< 原始图像跨度 rcDistParam.iStrideCur = iRefStride;//!< 参考图像跨度 // set Block Width / Height rcDistParam.iCols = pcPatternKey->getROIYWidth();//!< PU宽度 rcDistParam.iRows = pcPatternKey->getROIYHeight(); rcDistParam.DistFunc = m_afpDistortFunc[DF_SAD + g_aucConvertToBit[ rcDistParam.iCols ] + 1 ];//!< 根据PU的大小选择相应的失真计算函数 rcDistParam.m_maximumDistortionForEarlyExit = std::numeric_limits<Distortion>::max(); //!< 为非对称分区AMP预测模式提供专用的失真函数 if (rcDistParam.iCols == 12) { rcDistParam.DistFunc = m_afpDistortFunc[DF_SAD12];//!< TComRdCost::xGetSAD12 } else if (rcDistParam.iCols == 24) { rcDistParam.DistFunc = m_afpDistortFunc[DF_SAD24];//!< TComRdCost::xGetSAD24 } else if (rcDistParam.iCols == 48) { rcDistParam.DistFunc = m_afpDistortFunc[DF_SAD48];//!< TComRdCost::xGetSAD48 }#if NH_3D_DBBP if( m_bUseMask ) { rcDistParam.DistFunc = TComRdCost::xGetMaskedSAD; }#endif // initialize rcDistParam.iSubShift = 0;//!< (vertical) subsampling shift (for reducing complexity)}
0 0
- HTM-16.2代码(11)——xTZSearch
- HTM-16.2代码(6)——xMotionEstimation
- HTM-16.2代码(10)——xPatternSearch和xPatternSearchFast
- HTM-16.2代码(12)——xTZ8PointDiamondSearch和xTZ2PointSearch
- HTM-16.2代码(5)——predInterSearch
- HTM-16.2代码(9)——fillMvpCand
- HTM-16.2代码(8)——xEstimateMvPredAMVP
- HTM-16.2代码(7)——motionCompensation
- HTM-16.2代码(13)——getInterMergeCandidates
- HTM-16.2代码(3)——xCompressCU
- HTM-16.2代码(4)——xCheckRDCostInter
- HTM-16.2代码(2)——帧间预测(理论)
- HTM-16.2代码(1)——编码端一些函数的说明
- HEVC代码追踪(十一。五):运动估计/补偿之xTZSearch
- HEVC代码学习21:xTZSearch函数
- xTZSearch函数
- HTM代码疑问
- htm页面中调用htm文件代码
- vim编辑时insert模式粘贴代码,造成格式混乱
- MySQL 连接查询
- 从曹操杀华陀而联想到的系统性能问题才是真正的致命的问题
- java的插入排序算法学习
- oracle中sql语句中多个查询结果的交集、差集和并集
- HTM-16.2代码(11)——xTZSearch
- Android中view的加载机制(三)
- linux内核编译问题——undefined reference to `error'
- 深入浅出RxJava三--响应式的好处
- Java设计模式(14)行为型:模板方法模式
- Mybatis传多个参数(三种解决方案)
- Android 布局文件单行显示,多余文字用“...”代替
- php的pow函数
- CentOS 6.7 安装Scala 2.10.4 和 Spark 1.6.0