帧间预测的原理

AMVP的原理

帧间预测的实质就是为当前的PU在参考帧中寻找一块最相似块(相似度的判断准则有SAD等方法)。但是参考图像通常都比较大,我们直接去搜索的话就太费时了,应该使用某种方法在参考图像中确定一个搜索起始点,然后再该搜索起始点的周围进行搜索,那么就能降低搜索的时间了。
    AMVP模式就提供了这样一种方法,在开始搜索之前,先为当前PU预测出一个MV,这个预测的MV就被称为MVP,预测的MV可以直接从空域或者时域上的相邻块直接得到,因为相邻块有多个,因此MVP也会有多个,这些MVP组成了MVP候选列表,我们需要从中选择最优的一个来作为实际的MVP,得到MVP之后,我们根MVP(MVP实际也是一个MV)来确定搜索的起始点,然后在搜索起始点的附近按照某种方法做搜索,最后得到一个最优的MV,这个MV就是实际MV,MV确定了参考块的位置,参考块与当前PU相减得到残差,达到了数据压缩的目的;
同时MV与MVP相减得到MV残差也就是MVD,也能够达到数据压缩的目的。
    它的大致工作流程是:
    1、根据某种方法获取MVP候选列表
    2、从候选列表中选出最优的一个MVP
    3、根据MVP确定运动估计的起始点
    4、在起始点附近,按照某种方法进行搜索
    5、搜索完毕之后得到最优的MV
    6、由MV确定参考块在参考图像中的位置
    7、参考块减去当前块(PU)得到残差块
    8、MV减去MVP得到MVD
    9、通过7和8两个步骤就能达到数据压缩的目的

merge模式的原理

帧间预测的目的就是要得到一个MV(运动向量),然后根据该MV确定参考块在参考图像中的位置,
但是由于临近块的相似性(比如当前块和临近块都属于同一个物体,在镜头移动的时候,它们移动的距离和方向当然是相同的),因此很多时候我们并不需要去计算MV,我们把相邻块的MV直接当作当前块的MV。和AMVP相似,我们通过相邻块得到一个MVP候选列表,从中选出最优的一个MVP作为当前块的MV,然后根据该MV直接确定参考块的位置,确定了参考块之后就能计算残差了。因为MVP和MV相同,因此不存在MVD,因此编码的时候只需要编码MV(MVP)在候选列表中索引即可,不再需要编码MVD,解码可以按照类似的方法构造MVP候选列表,然后依据传送过来的索引就能得到MV了。
    工作流程是:
    1、根据某种方法获取MVP候选列表
    2、从候选列表中选出最优的一个MVP,同时得到该MVP在候选列表中的索引
    3、把该MVP作为当前块的MV
    4、根据MV确定参考块在参考图像中的位置
    5、参考块减去当前块得到残差块
    6、因为MVP和MV相同,因此没有MVD,只需把残差系数和MVP的索引传给解码器就行了

skip模式的原理

skip模式是merge模式的一种特例。按照merge模式得到MV之后,如果编码器根据某种方法判断了当前块和参考块基本一样,那么不需要传输残差数据,只需要传送MV的索引和一个标志,来表明当前块可以直接从参考块得到。

xEstimateMvPredAMVP的工作流程

AMVP中MVP的获取就是通过xEstimateMvPredAMVP这个函数得到的
1、判断bFilled标识,该标识表示MVP候选列表是否已经建立好
2、如果bFilled是false,通过fillMvpCand获取MVP候选列表;否则,不需要重新建立MVP候选列表
3、先把MVP候选列表中的第一个MVP作为最优的MVP
4、如果候选列表中MVP的数量小于等于1,那么直接把步骤3选出的MVP返回
5、如果bFilled是true,表示MVP候选列表是原来已经建立好的,那么直接根据PU的相关信息得到最优的MVP,然后返回
6、遍历MVP候选列表,选出代价最小的MVP作为当前PU的MVP,并设置相关信息,然后返回

#if ZERO_MVD_EST
Void TEncSearch::xEstimateMvPredAMVP( TComDataCU* pcCU, TComYuv* pcOrgYuv, UInt uiPartIdx, RefPicList eRefPicList, Int iRefIdx, TComMv& rcMvPred, Bool bFilled, UInt* puiDistBiP, UInt* puiDist  )
#else
Void TEncSearch::xEstimateMvPredAMVP( TComDataCU* pcCU, TComYuv* pcOrgYuv, UInt uiPartIdx, RefPicList eRefPicList, Int iRefIdx, TComMv& rcMvPred, Bool bFilled, UInt* puiDistBiP )
#endif
{AMVPInfo* pcAMVPInfo = pcCU->getCUMvField(eRefPicList)->getAMVPInfo();TComMv  cBestMv;Int     iBestIdx = 0;TComMv  cZeroMv;TComMv  cMvPred;UInt    uiBestCost = MAX_INT;UInt    uiPartAddr = 0;Int     iRoiWidth, iRoiHeight;Int     i;// 得到此次分割的索引和大小pcCU->getPartIndexAndSize( uiPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );// Fill the MV Candidates// 获取MVP(即预测的MV),MVP存放在pcAMVPInfo中if (!bFilled){pcCU->fillMvpCand( uiPartIdx, uiPartAddr, eRefPicList, iRefIdx, pcAMVPInfo );}// initialize Mvp index & Mvp// 最优MVP的默认索引是0iBestIdx = 0;// 最优MVP默认是列表的第一个cBestMv  = pcAMVPInfo->m_acMvCand[0];
#if !ZERO_MVD_EST// 如果MVP候选列表中MVP的数量是0或者1if (pcAMVPInfo->iN <= 1){// 得到了最优的MVPrcMvPred = cBestMv;pcCU->setMVPIdxSubParts( iBestIdx, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( pcAMVPInfo->iN, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));// 如果参考列表是list1(表示这是B slice)if(pcCU->getSlice()->getMvdL1ZeroFlag() && eRefPicList==REF_PIC_LIST_1){
#if ZERO_MVD_EST(*puiDistBiP) = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, rcMvPred, 0, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight, uiDist );
#else(*puiDistBiP) = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, rcMvPred, 0, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight);
#endif}// 返回return;}
#endif  // 如果MVP候选列表已经填充完毕,那么直接返回MVP就行了// 注意:fillMvpCand并不会修改bFilled的值,bFilled的值是函数传进来的if (bFilled){assert(pcCU->getMVPIdx(eRefPicList,uiPartAddr) >= 0);// 选择相应的MVPrcMvPred = pcAMVPInfo->m_acMvCand[pcCU->getMVPIdx(eRefPicList,uiPartAddr)];return;}m_cYuvPredTemp.clear();
#if ZERO_MVD_ESTUInt uiDist;
#endif//-- Check Minimum Cost.// 遍历每一个MVP,选出代价最小的那个for ( i = 0 ; i < pcAMVPInfo->iN; i++){UInt uiTmpCost;
#if ZERO_MVD_ESTuiTmpCost = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, pcAMVPInfo->m_acMvCand[i], i, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight, uiDist );
#elseuiTmpCost = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, pcAMVPInfo->m_acMvCand[i], i, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight);
#endif      if ( uiBestCost > uiTmpCost ){uiBestCost = uiTmpCost;cBestMv   = pcAMVPInfo->m_acMvCand[i];iBestIdx  = i;(*puiDistBiP) = uiTmpCost;
#if ZERO_MVD_EST(*puiDist) = uiDist;
#endif}}m_cYuvPredTemp.clear();// Setting Best MVPrcMvPred = cBestMv;pcCU->setMVPIdxSubParts( iBestIdx, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( pcAMVPInfo->iN, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));return;
}

MVP候选列表的建立

AMVP模式的候选列表,列表的长度是2,建立流程如下
     (1)空域列表的建立。假设当前PU的左下角是A0,左侧是A1,左上角是B2,上方是B1,右上角是B0。当前PU的左侧和上方需要各产生一个候选MV。对于左侧的候选MV的筛选,处理顺序是A0->A1->scaled A0->scaled A1;对上侧的候选MV的筛选,处理的顺序是B0->B1->B2(如果这几个都不存在,那么继续处理-> scaled B0-> scaled B2)。对于左侧(上方)来说,只要找到一个候选MV,就不继续处理后面的候选者了
     (2)时域列表的建立。与空域情况不同,时域候选列表不能直接使用候选块的运动信息,需要根据当前帧和参考帧之间的位置关系做相应的伸缩调整。时域最多只能提供一个候选MV。如果此时候选列表的候选MV的数量还不足2个,那么需要填充零向量。

AMVP模式的MVP候选列表是通过fillMvpCand函数建立的

Void TComDataCU::fillMvpCand ( UInt uiPartIdx, UInt uiPartAddr, RefPicList eRefPicList, Int iRefIdx, AMVPInfo* pInfo )
{TComMv cMvPred;Bool bAddedSmvp = false;pInfo->iN = 0;  if (iRefIdx < 0){return;}//-- Get Spatial MVUInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;// 在宽度(横向)上有多少个分割数UInt uiNumPartInCUWidth = m_pcPic->getNumPartInWidth();Bool bAdded = false;// 该函数调用的三个参数是,当前分割的索引,左下角分割的索引,右上角分割的索引deriveLeftRightTopIdx( uiPartIdx, uiPartIdxLT, uiPartIdxRT );deriveLeftBottomIdx( uiPartIdx, uiPartIdxLB );// 空域候选MV的选择方式// 要找出两个候选MV// 假设 左下角a0,左边a1,右上角b0,上方b1,左上角b2// 首先 按照a0->a1->scale a0->scale a1的顺序找到一个候选MV,只要找到一个就不再继续判断后面// 然后 按照scale b0->scale b1->scale b2->b0->b1->b2的顺序再找出一个候选MV,只有在这个顺序中找到一个,就不再判断后面的了/*比例伸缩模式(scaled)是当参考块存在,当前Pu的参考图像跟参考块的参考图像不一致时才选用的方式(因为是空域MV选择,即参考块和当前块在同一帧中,因此才会出现当前块和参考块参考的图像是否一致这种问题;如果是时域MV候选,那么当前块和参考块的参考图像肯定是不一致的)。具体计算方法如下公式所示,curMV为当前Pu的候选MV,td与tb分别为当前块与参考块到他们的参考图像间的距离,colMV 为参考块的mv。*/TComDataCU* tmpCU = NULL;UInt idx;// 得到左下角的相邻的cutmpCU = getPUBelowLeft(idx, uiPartIdxLB);bAddedSmvp = (tmpCU != NULL) && (tmpCU->getPredictionMode(idx) != MODE_INTRA);// 没过没有左下角的if (!bAddedSmvp){// 得到左边的相邻的cutmpCU = getPULeft(idx, uiPartIdxLB);bAddedSmvp = (tmpCU != NULL) && (tmpCU->getPredictionMode(idx) != MODE_INTRA);}// Left predictor search// 添加到候选列表中bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_BELOW_LEFT);if (!bAdded) {// 左边相邻的cubAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_LEFT );}if(!bAdded){bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_BELOW_LEFT);if (!bAdded) {xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_LEFT );}}// Above predictor search// 右上角bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE_RIGHT);if (!bAdded) {// 上方bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE);}if(!bAdded){// 左上角xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxLT, MD_ABOVE_LEFT);}if (!bAddedSmvp){bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE_RIGHT);if (!bAdded) {bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE);}if(!bAdded){xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxLT, MD_ABOVE_LEFT);}}// 判断列表中候选者的数量,如果等于2,那么进入下面的判断if ( pInfo->iN == 2 ){if ( pInfo->m_acMvCand[ 0 ] == pInfo->m_acMvCand[ 1 ] ){pInfo->iN = 1;}}// 判断是否启用时域的MVP功能(TMVP中的T即时域的意思),如果启用了,那么选择时域候选MV// 选择的参考块的位置位于 (当前cu所在的LCU的右下角的相邻cu),注意这是位置上,因为实际上参考块在另一个帧// 如果不存在,那么直接用该位置的mv即可——若H位置的同位Pu(邻近已编码图像对应位置Pu)不可用,则用位置的同位Pu代替// 缩放的方式和上面的一样if ( getSlice()->getEnableTMVPFlag() ){// Get Temporal Motion PredictorInt iRefIdx_Col = iRefIdx;TComMv cColMv;UInt uiPartIdxRB;UInt uiAbsPartIdx;  UInt uiAbsPartAddr;deriveRightBottomIdx( uiPartIdx, uiPartIdxRB );uiAbsPartAddr = m_uiAbsIdxInLCU + uiPartAddr;//----  co-located RightBottom Temporal Predictor (H) ---//uiAbsPartIdx = g_auiZscanToRaster[uiPartIdxRB];Int uiLCUIdx = -1;if ( ( m_pcPic->getCU(m_uiCUAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdx] + m_pcPic->getMinCUWidth() ) >= m_pcSlice->getSPS()->getPicWidthInLumaSamples() )  // image boundary check{}else if ( ( m_pcPic->getCU(m_uiCUAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdx] + m_pcPic->getMinCUHeight() ) >= m_pcSlice->getSPS()->getPicHeightInLumaSamples() ){}else{if ( ( uiAbsPartIdx % uiNumPartInCUWidth < uiNumPartInCUWidth - 1 ) &&           // is not at the last column of LCU ( uiAbsPartIdx / uiNumPartInCUWidth < m_pcPic->getNumPartInHeight() - 1 ) ) // is not at the last row    of LCU{uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdx + uiNumPartInCUWidth + 1 ];uiLCUIdx = getAddr();}else if ( uiAbsPartIdx % uiNumPartInCUWidth < uiNumPartInCUWidth - 1 )           // is not at the last column of LCU But is last row of LCU{uiAbsPartAddr = g_auiRasterToZscan[ (uiAbsPartIdx + uiNumPartInCUWidth + 1) % m_pcPic->getNumPartInCU() ];}else if ( uiAbsPartIdx / uiNumPartInCUWidth < m_pcPic->getNumPartInHeight() - 1 ) // is not at the last row of LCU But is last column of LCU{uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdx + 1 ];uiLCUIdx = getAddr() + 1;}else //is the right bottom corner of LCU                       {uiAbsPartAddr = 0;}}// 对MV进行缩放处理if ( uiLCUIdx >= 0 && xGetColMVP( eRefPicList, uiLCUIdx, uiAbsPartAddr, cColMv, iRefIdx_Col ) ){// 存进MVP列表候选列表中pInfo->m_acMvCand[pInfo->iN++] = cColMv;}else {UInt uiPartIdxCenter;UInt uiCurLCUIdx = getAddr();xDeriveCenterIdx( uiPartIdx, uiPartIdxCenter );if (xGetColMVP( eRefPicList, uiCurLCUIdx, uiPartIdxCenter,  cColMv, iRefIdx_Col )){pInfo->m_acMvCand[pInfo->iN++] = cColMv;}}//----  co-located RightBottom Temporal Predictor  ---//}if (pInfo->iN > AMVP_MAX_NUM_CANDS){pInfo->iN = AMVP_MAX_NUM_CANDS;}// 如果没有达到指定的数量,就填充0向量while (pInfo->iN < AMVP_MAX_NUM_CANDS){pInfo->m_acMvCand[pInfo->iN].set(0,0);pInfo->iN++;}// MVP候选列表中MV存放的顺序是先空域MV(左边的MV,然后上方的MV)然后再时域MVreturn ;
}

HM编码器代码阅读(16)——帧间预测之AMVP模式(四)预测MV的获取相关推荐

  1. HM编码器代码阅读(32)——帧间预测之AMVP/Merge模式(七)encodeResAndCalcRdInterCU函数:残差计算、变换量化

    encodeResAndCalcRdInterCU 原理和细节 经过运动估计.运动补偿,我们得到了MV以及参考块,那么接下来是计算残差.计算MVD,然后对系数进行变换.量化. encodeResAnd ...

  2. HM编码器代码阅读(13)——帧间预测之AMVP模式(一)总体流程

    帧间预测的原理 AMVP的原理 帧间预测的实质就是为当前的PU在参考帧中寻找一块最相似块(相似度的判断准则有SAD等方法).但是参考图像通常都比较大,我们直接去搜索的话就太费时了,应该使用某种方法在参 ...

  3. HM编码器代码阅读(30)——帧间预测之AMVP模式(五)运动估计

    运动估计 通过 点击打开链接 介绍的方法得到MVP之后,可以根据该MVP确定运动估计的搜索起点,然后进行运动估计 xMotionEstimation就是进行运动估计的入口函数     1.先进行一些初 ...

  4. HM编码器代码阅读(14)——帧间预测之AMVP模式(二)predInterSearch函数

    简介     predInterSearch主要的工作是ME(运动估计)和MC(运动补偿).     函数中有一个bTestNormalMC变量,它表示是否进行正常的MC过程,正常的MC过程就是进行M ...

  5. HM编码器代码阅读(14)——帧间预測之AMVP模式(二)predInterSearch函数

    简单介绍     predInterSearch基本的工作是ME(运动预计)和MC(运动补偿).     函数中有一个bTestNormalMC变量.它表示是否进行正常的MC过程,正常的MC过程就是进 ...

  6. HM编码器代码阅读(31)——帧间预测之AMVP/Merge模式(六)运动补偿

    运动补偿 原理 说实话一直很难理解运动补偿中"补偿"二字的意思,在参考了 http://blog.csdn.net/hevc_cjl/article/details/8457642 ...

  7. HM编码器代码阅读(15)——帧间预测之AMVP模式(三)xGetBlkBits函数

    GetBlkBits函数的主要功能是计算使用某种PU划分模式的时候,该种模式占用的比特数 Void TEncSearch::xGetBlkBits( PartSize eCUMode, Bool bP ...

  8. HM编码器代码阅读(38)——帧内预测(五)帧内预测之正式的预测操作

    正式的预测操作 在前面的操作中,我们已经得到了模式候选列表,但是我们的目的是要得到一个最优的模式,因此我们还需要对这个列表中的模式进行遍历,对于每一个模式,进行预测操作,为了计算率失真代价还必须进行变 ...

  9. HM编码器代码阅读(5)——参考帧的选择

    参考帧是怎么来的以及如何设置这个问题困扰了我很久,现在理出了一点头绪. 参考帧的选择主要涉及几个函数: selectReferencePictureSet createExplicitReferenc ...

最新文章

  1. MySQL 的存储引擎
  2. NHibernate之旅(10):探索父子(一对多)关联查询
  3. 2013年最 “酷”科技产品回顾
  4. HA 高可用之V1版
  5. win7(64)与samba不兼容
  6. MyBatis-Plus 高级功能 —— 自动填充功能
  7. 面试官:聊一下你对MySQL索引实现原理?
  8. matlab微分的语句格式,偏微分差分四种格式的matlab程序.doc
  9. String.Format和StringBuilder的效率
  10. 基于matlab的回波,基于MATLAB回波信号产生与消除.doc
  11. 牛客题霸 反转链表 C++题解/答案
  12. WinCE Boot方式及 Bootloader架构概述
  13. 基于java SSM springboot景区行李寄存管理系统设计和实现
  14. ibatis的ibatorForEclipse的安装与配置和ibator的错误日志查看
  15. 学计算机好还是学西点,女生学西点师有后悔的吗 西点师有前途吗
  16. wps表格l制作甘特图_十分钟学会制作Excel甘特图,工作进度一目了然!
  17. excel自动调整列宽_Knime数据分析入门- 06 自动调整Excel中列序
  18. java计算机毕业设计医院住院部信息管理系统源程序+mysql+系统+lw文档+远程调试
  19. WPS怎么转换成office
  20. 智慧档案馆档案库房一体化平台建设

热门文章

  1. 调用百度aip实现短语音翻译(附代码)
  2. (十八)树莓派3B+ wiringPi库的使用--外部中断
  3. [NLP --- 3] 文档检索算法TF-IDF
  4. Unity UGUI DoTween 学习笔记
  5. 手机APP远程控制树莓派
  6. matlab升幂降幂排列,升幂排列与降幂排列
  7. 5W字穿透 ELK(史上最全):elasticsearch +logstash+kibana
  8. java 好学_java是什么?对于新手好学吗?
  9. 交叉销售功能介绍-功能
  10. (送票)2020广州敏捷之旅暨第11届广州DevOps社区Meetup火热报名中!