帧间预测--运动补偿

运动补偿

原理

百科上说“运动补偿是通过先前的局部图像来预测、补偿当前的局部图像,它是减少帧序列冗余信息的有效方法”,通过前面的运动估计我们得到了MV(运动向量),大部分情况下MV是亚像素精度的,MV的作用就是定位参考块在参考帧中的位置,但是亚像素的MV定位出来的位置是没有像素点的(亚像素就是指该位置在两个像素之间),换句话说非整像素精度的MV定位出来的地方没有像素点(即没有像素块),那么我们需要使用现有的像素点去构造亚像素点,这样通过MV找到位置才有参考块。运动补偿实际干的就是这么回事它通过MV和现有的像素块去构造一个亚像素块,这个新被创建出来的像素块就是当前PU的参考块。这样,得到了MV和参考块之后就可以进行后续的工作了。

运动补偿入口函数

motionCompensation()完成了运动补偿的工作;

motionCompensation()调用了xPredInterUni()完成了单向预测的运动补偿;而调用xPredInterBi()完成了双向预测的运动补偿,它实际调用xPredInterBi和xWeightedPredictionBi来完成相应的工作。其中xPredInterUni()调用xPredInterBlk()完成一个分量块的运动补偿。而xPredInterBlk()调用了TComInterpolationFilter类的filterHor()和filterVer()完成了亚像素的插值工作。

motionCompensation的流程:

1、如果指明了PU,那么只对这个PU进行处理,如果没有指明PU,那么对CU下面的所有PU进行处理。

2、对于一个PU,如果指定了参考列表,那么表示进行单向运动补偿(双向运动补偿可以通过两次单向操作来完成);如果没有指定参考列表,那么默认进行双向运动补偿,但是在操作之前先确认PU两个方向上的参考帧是否相同,如果相同,表示只有一个参考帧那么它实际还是进行单向运动补偿,否则使用双向运动补偿。

3、无论是单向运动补偿还是双向运动补偿,都需要在亚像素插值工作完成之后,检测是否需要进行加权预测,相关的加权操作是在xWeightedPredictionUni中完成的,这个函数根据权重参数对目标像素块进行权重转换,对每一个像素通过一个公式去重新计算它的值。单向预测的运动补偿中,xWeightedPredictionUni跟在xPredInterUni函数的后面,在双向预测的运动补偿中,xWeightedPredictionUni在xPredInterBi函数里面。

下面的它的流程图和代码:

[cpp] view plain copy

  1. Void TComPrediction::motionCompensation ( TComDataCU* pcCU, TComYuv* pcYuvPred, RefPicList eRefPicList, Int iPartIdx )
  2. {
  3. Int         iWidth;
  4. Int         iHeight;
  5. UInt        uiPartAddr;
  6. // 如果PU的索引是有效值,那么直接处理该PU,然后返回
  7. if ( iPartIdx >= 0 )
  8. {
  9. pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iWidth, iHeight );
  10. // 有效的参考列表,即明确的标明了使用哪个参考列表,那么就在对应的方向上进行单向预测
  11. if ( eRefPicList != REF_PIC_LIST_X )
  12. {
  13. // 先进行插值操作
  14. if( pcCU->getSlice()->getPPS()->getUseWP())
  15. {
  16. xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred, true ); // 最后一个参数指明是否为双向预测
  17. }
  18. else
  19. {
  20. xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred );
  21. }
  22. // 加权预测
  23. if ( pcCU->getSlice()->getPPS()->getUseWP() )
  24. {
  25. xWeightedPredictionUni( pcCU, pcYuvPred, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred );
  26. }
  27. }
  28. // 没有指明明确的参考列表,那么判断PU两个方向上的参考帧是否一样
  29. else
  30. {
  31. // 如果PU的两个参考列表是相同的,即它们的运动是一致的
  32. // 那么直接使用单向预测
  33. if ( xCheckIdenticalMotion( pcCU, uiPartAddr ) )
  34. {
  35. xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, REF_PIC_LIST_0, pcYuvPred );
  36. }
  37. // 否则使用双向预测
  38. else
  39. {
  40. xPredInterBi  (pcCU, uiPartAddr, iWidth, iHeight, pcYuvPred );
  41. }
  42. }
  43. return;
  44. }
  45. // 否则处理CU下的所有PU
  46. for ( iPartIdx = 0; iPartIdx < pcCU->getNumPartitions(); iPartIdx++ )
  47. {
  48. pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iWidth, iHeight );
  49. if ( eRefPicList != REF_PIC_LIST_X )
  50. {
  51. if( pcCU->getSlice()->getPPS()->getUseWP())
  52. {
  53. xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred, true );
  54. }
  55. else
  56. {
  57. xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred );
  58. }
  59. if ( pcCU->getSlice()->getPPS()->getUseWP() )
  60. {
  61. xWeightedPredictionUni( pcCU, pcYuvPred, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred );
  62. }
  63. }
  64. else
  65. {
  66. if ( xCheckIdenticalMotion( pcCU, uiPartAddr ) )
  67. {
  68. xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, REF_PIC_LIST_0, pcYuvPred );
  69. }
  70. else
  71. {
  72. xPredInterBi  (pcCU, uiPartAddr, iWidth, iHeight, pcYuvPred );
  73. }
  74. }
  75. }
  76. return;
  77. }

单向预测的运动补偿

[cpp] view plain copy

  1. Void TComPrediction::xPredInterUni ( TComDataCU* pcCU, UInt uiPartAddr, Int iWidth, Int iHeight, RefPicList eRefPicList, TComYuv*& rpcYuvPred, Bool bi )
  2. {
  3. Int         iRefIdx     = pcCU->getCUMvField( eRefPicList )->getRefIdx( uiPartAddr );           assert (iRefIdx >= 0);
  4. TComMv      cMv         = pcCU->getCUMvField( eRefPicList )->getMv( uiPartAddr );
  5. pcCU->clipMv(cMv);
  6. xPredInterLumaBlk  ( pcCU, pcCU->getSlice()->getRefPic( eRefPicList, iRefIdx )->getPicYuvRec(), uiPartAddr, &cMv, iWidth, iHeight, rpcYuvPred, bi );
  7. xPredInterChromaBlk( pcCU, pcCU->getSlice()->getRefPic( eRefPicList, iRefIdx )->getPicYuvRec(), uiPartAddr, &cMv, iWidth, iHeight, rpcYuvPred, bi );
  8. }

对亮度块进行亚像素插值工作

[cpp] view plain copy

  1. Void TComPrediction::xPredInterLumaBlk( TComDataCU *cu, TComPicYuv *refPic, UInt partAddr, TComMv *mv, Int width, Int height, TComYuv *&dstPic, Bool bi )
  2. {
  3. Int refStride = refPic->getStride();
  4. Int refOffset = ( mv->getHor() >> 2 ) + ( mv->getVer() >> 2 ) * refStride;
  5. Pel *ref      = refPic->getLumaAddr( cu->getAddr(), cu->getZorderIdxInCU() + partAddr ) + refOffset;
  6. Int dstStride = dstPic->getStride();
  7. Pel *dst      = dstPic->getLumaAddr( partAddr );
  8. Int xFrac = mv->getHor() & 0x3;
  9. Int yFrac = mv->getVer() & 0x3;
  10. if ( yFrac == 0 )
  11. {
  12. m_if.filterHorLuma( ref, refStride, dst, dstStride, width, height, xFrac,       !bi );
  13. }
  14. else if ( xFrac == 0 )
  15. {
  16. m_if.filterVerLuma( ref, refStride, dst, dstStride, width, height, yFrac, true, !bi );
  17. }
  18. else
  19. {
  20. Int tmpStride = m_filteredBlockTmp[0].getStride();
  21. Short *tmp    = m_filteredBlockTmp[0].getLumaAddr();
  22. Int filterSize = NTAPS_LUMA;
  23. Int halfFilterSize = ( filterSize >> 1 );
  24. m_if.filterHorLuma(ref - (halfFilterSize-1)*refStride, refStride, tmp, tmpStride, width, height+filterSize-1, xFrac, false     );
  25. m_if.filterVerLuma(tmp + (halfFilterSize-1)*tmpStride, tmpStride, dst, dstStride, width, height,              yFrac, false, !bi);
  26. }
  27. }

双向预测运动补偿

[cpp] view plain copy

  1. Void TComPrediction::xPredInterBi ( TComDataCU* pcCU, UInt uiPartAddr, Int iWidth, Int iHeight, TComYuv*& rpcYuvPred )
  2. {
  3. TComYuv* pcMbYuv;
  4. Int      iRefIdx[2] = {-1, -1};
  5. // 执行两次单向预测的运动补偿,就可以完成双向预测的运动补偿了
  6. for ( Int iRefList = 0; iRefList < 2; iRefList++ )
  7. {
  8. RefPicList eRefPicList = (iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
  9. iRefIdx[iRefList] = pcCU->getCUMvField( eRefPicList )->getRefIdx( uiPartAddr );
  10. if ( iRefIdx[iRefList] < 0 )
  11. {
  12. continue;
  13. }
  14. assert( iRefIdx[iRefList] < pcCU->getSlice()->getNumRefIdx(eRefPicList) );
  15. pcMbYuv = &m_acYuvPred[iRefList];
  16. // 单向预测的运动补偿
  17. if( pcCU->getCUMvField( REF_PIC_LIST_0 )->getRefIdx( uiPartAddr ) >= 0 && pcCU->getCUMvField( REF_PIC_LIST_1 )->getRefIdx( uiPartAddr ) >= 0 )
  18. {
  19. xPredInterUni ( pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcMbYuv, true );
  20. }
  21. else
  22. {
  23. if ( ( pcCU->getSlice()->getPPS()->getUseWP()       && pcCU->getSlice()->getSliceType() == P_SLICE ) ||
  24. ( pcCU->getSlice()->getPPS()->getWPBiPred() && pcCU->getSlice()->getSliceType() == B_SLICE ) )
  25. {
  26. xPredInterUni ( pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcMbYuv, true );
  27. }
  28. else
  29. {
  30. xPredInterUni ( pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcMbYuv );
  31. }
  32. }
  33. }
  34. // 加权预测
  35. if ( pcCU->getSlice()->getPPS()->getWPBiPred() && pcCU->getSlice()->getSliceType() == B_SLICE  )
  36. {
  37. xWeightedPredictionBi( pcCU, &m_acYuvPred[0], &m_acYuvPred[1], iRefIdx[0], iRefIdx[1], uiPartAddr, iWidth, iHeight, rpcYuvPred );
  38. }
  39. else if ( pcCU->getSlice()->getPPS()->getUseWP() && pcCU->getSlice()->getSliceType() == P_SLICE )
  40. {
  41. xWeightedPredictionUni( pcCU, &m_acYuvPred[0], uiPartAddr, iWidth, iHeight, REF_PIC_LIST_0, rpcYuvPred );
  42. }
  43. else
  44. {
  45. xWeightedAverage( &m_acYuvPred[0], &m_acYuvPred[1], iRefIdx[0], iRefIdx[1], uiPartAddr, iWidth, iHeight, rpcYuvPred );
  46. }
  47. }

加权预测

单向加权预测

[cpp] view plain copy

  1. // getWpScaling的作用就是设置权重table的参数
  2. // addWeightUni根据权重参数对目标像素块进行权重转换,即对每一个像素通过一个公式去重新计算它的值
  3. Void TComWeightPrediction::xWeightedPredictionUni( TComDataCU* pcCU, TComYuv* pcYuvSrc, UInt uiPartAddr, Int iWidth, Int iHeight, RefPicList eRefPicList, TComYuv*& rpcYuvPred, Int iRefIdx)
  4. {
  5. wpScalingParam  *pwp, *pwpTmp;
  6. if ( iRefIdx < 0 )
  7. {
  8. iRefIdx   = pcCU->getCUMvField( eRefPicList )->getRefIdx( uiPartAddr );
  9. }
  10. assert (iRefIdx >= 0);
  11. if ( eRefPicList == REF_PIC_LIST_0 )
  12. {
  13. getWpScaling(pcCU, iRefIdx, -1, pwp, pwpTmp);
  14. }
  15. else
  16. {
  17. getWpScaling(pcCU, -1, iRefIdx, pwpTmp, pwp);
  18. }
  19. addWeightUni( pcYuvSrc, uiPartAddr, iWidth, iHeight, pwp, rpcYuvPred );
  20. }

双向加权预测

[cpp] view plain copy

  1. /*
  2. ** 双向加权预测
  3. */
  4. Void TComWeightPrediction::xWeightedPredictionBi( TComDataCU* pcCU, TComYuv* pcYuvSrc0, TComYuv* pcYuvSrc1, Int iRefIdx0, Int iRefIdx1, UInt uiPartIdx, Int iWidth, Int iHeight, TComYuv* rpcYuvDst )
  5. {
  6. wpScalingParam  *pwp0, *pwp1;
  7. TComPPS         *pps = pcCU->getSlice()->getPPS();
  8. assert( pps->getWPBiPred());
  9. // getWpScaling的作用就是设置权重table的参数
  10. getWpScaling(pcCU, iRefIdx0, iRefIdx1, pwp0, pwp1);
  11. // addWeightUni根据权重参数对目标像素块进行权重转换,即对每一个像素通过一个公式去重新计算它的值
  12. if( iRefIdx0 >= 0 && iRefIdx1 >= 0 )
  13. {
  14. addWeightBi(pcYuvSrc0, pcYuvSrc1, uiPartIdx, iWidth, iHeight, pwp0, pwp1, rpcYuvDst );
  15. }
  16. else if ( iRefIdx0 >= 0 && iRefIdx1 <  0 )
  17. {
  18. addWeightUni( pcYuvSrc0, uiPartIdx, iWidth, iHeight, pwp0, rpcYuvDst );
  19. }
  20. else if ( iRefIdx0 <  0 && iRefIdx1 >= 0 )
  21. {
  22. addWeightUni( pcYuvSrc1, uiPartIdx, iWidth, iHeight, pwp1, rpcYuvDst );
  23. }
  24. else
  25. {
  26. assert (0);
  27. }
  28. }

平均加权预测

[cpp] view plain copy

    1. Void TComPrediction::xWeightedAverage( TComYuv* pcYuvSrc0, TComYuv* pcYuvSrc1, Int iRefIdx0, Int iRefIdx1, UInt uiPartIdx, Int iWidth, Int iHeight, TComYuv*& rpcYuvDst )
    2. {
    3. if( iRefIdx0 >= 0 && iRefIdx1 >= 0 )
    4. {
    5. rpcYuvDst->addAvg( pcYuvSrc0, pcYuvSrc1, uiPartIdx, iWidth, iHeight );
    6. }
    7. else if ( iRefIdx0 >= 0 && iRefIdx1 <  0 )
    8. {
    9. pcYuvSrc0->copyPartToPartYuv( rpcYuvDst, uiPartIdx, iWidth, iHeight );
    10. }
    11. else if ( iRefIdx0 <  0 && iRefIdx1 >= 0 )
    12. {
    13. pcYuvSrc1->copyPartToPartYuv( rpcYuvDst, uiPartIdx, iWidth, iHeight );
    14. }
    15. }

转自:http://blog.csdn.net/NB_vol_1/article/details/55253979

时间: 2024-11-06 23:18:08

帧间预测--运动补偿的相关文章

H.264学习笔记3——帧间预测

帧间预测主要包括运动估计(运动搜索方法.运动估计准则.亚像素插值和运动矢量估计)和运动补偿. 对于H.264,是对16x16的亮度块和8x8的色度块进行帧间预测编码. A.树状结构分块 H.264的宏块,对于16x16的亮度宏块,可以分成16x16.16x8.8x16和8x8的子块进行帧间预测.对于8x8的块(亚宏块,亮度和色度),往下又可以分成8x8.8x4.4x8.4x4的子块.在运动估计中,每一种分割都需要尝试,并计算出运动搜索结果的代价,选择最小代价的分割方式进行预测编码. B.运动估计

HEVC算法和体系结构:预测编码之帧间预测

预测编码之帧间预测(Inter-Picture Prediction) 帧间预测是指利用视频时间域相关性,使用临近已编码图像像素预测当前图像的像素,以达到有效去除视频时域冗余的目的.由于视频序列通常包括较强的时域相关性,因此预测残差值接近于0,将残差信号作为后续模块的输入进行变换.量化.扫描及熵编码,可实现对视频信号的高效压缩. 一.帧间预测编码原理 目前主要的视频编码标准帧间预测部分都采用了基于块的运动补偿技术,如下图所示,其基本原理为:当前图像的每个像素块在之前已编码图像中寻找一个最佳匹配块

【HEVC帧间预测论文】P1.1 基于运动特征的HEVC快速帧间预测算法

基于运动特征的 HEVC 快速帧间预测算法/Fast Inter-Frame Prediction Algorithm for HEVC Based on Motion Features <HEVC标准介绍.HEVC帧间预测论文笔记>系列博客,目录见:http://www.cnblogs.com/DwyaneTalk/p/5711333.html 上海大学学报(自然科学版)第19卷第3期. 利用当前深度CU与时域对应位置已编码CU的亮度像素值的差值平方和均值来判断当前CU的运动特征.属于A类算

HM编码器代码阅读(14)——帧间预测之二predInterSearch(inter模式)

predInterSearch主要的工作是ME(运动估计)和MC(运动补偿). 函数中有一个bTestNormalMC变量,它表示是否进行正常的MC过程,正常的MC过程就是进行ME再进行MC. 正常的MC流程是,遍历所有的参考帧,进行ME(运动估计:xEstimateMvPredAMVP和xMotionEstimation),然后记录AVP或者MV的信息,进行MC(运动补偿,目的是选出最优的参数),然后更新最优的参数,遍历完所有的参考帧之后,就选出了最优的参数了:然后循环结束,接着进行正式的MC

x264源代码简单分析:宏块分析(Analysis)部分-帧间宏块(Inter)

本文记录x264的 x264_slice_write()函数中调用的x264_macroblock_analyse()的源代码.x264_macroblock_analyse()对应着x264中的分析模块.分析模块主要完成了下面2个方面的功能: (1)对于帧内宏块,分析帧内预测模式(2)对于帧间宏块,进行运动估计,分析帧间预测模式 上一篇文章记录了帧内宏块预测模式的分析,本文继续记录帧间宏块预测模式的分析. 函数调用关系图 宏块分析(Analysis)部分的源代码在整个x264中的位置如下图所示

HEVC算法和体系结构:预测编码之帧内预测

预测编码之帧内预测(Intra-Picture Prediction) 预测编码(Prediction Coding)是视频编码的核心技术之一,指利用已编码的一个或几个样本值,根据某种模型或方法,对当前的样本值进行预测,并对样本真实值和预测值之间的差值进行编码.视频编码器对预测后的残差而不是原始像素值进行变换.量化.熵编码,由此大幅度提高编码效率. 对于视频信号来说,一帧图像内临近像素之间有着较强的空间相关性,即空域冗余:相邻图像之间也有很强的相关性,即时域冗余.去除空域冗余和时域冗余的技术分别

H.264学习笔记2——帧内预测

帧内预测:根据经过反量化和反变换(没有进行去块效应)之后的同一条带内的块进行预测. A.4x4亮度块预测: 用到的像素和预测方向如图: a~f是4x4块中要预测的像素值,A~Q是临块中解码后的参考值.0~8是4x4的亮度块的9个预测方向(模式).当E~H不可得时,用D代替. A~Q在下面情况下不可用: >不在当前图像或条带:在该4x4块之前还没有被编码:位于帧间编码宏块,且constrained_intra_pred为1: 对于9个预测模式,简述如下: >模式0:垂直模式,条件:A~D可用.

OpenCV运动目标检测——帧间差,混合高斯模型方法

一.简单的帧间差方法 帧差法是在连续的图像序列中两个或三个相邻帧间采用基于像素的时间差分并且闽值化来提取图像中的运动区域. 代码: int _tmain(int argc, _TCHAR* argv[]) { VideoCapture capture("bike.avi"); if(!capture.isOpened()) return -1; double rate = capture.get(CV_CAP_PROP_FPS); int delay = 1000/rate; Mat

x264 亮度信号8x8帧内预测模式

1 该模式的8个预测方向与4x4帧内预测模式一样. 2 该模式只有High profile及更高的Profile的才有可能使用,Baseline.Main Profile.Preset为ultrafast时不支持,命令行参数为--8x8dct与--no-8x8dct控制是否使用,x264内部参数结构x264_param_t的成员b_transform_8x8的值控制是否使用. 1 x264_param_default函数中将b_transform_8x8设为1,即默认为使用亮度信号8x8帧内预测