zoukankan      html  css  js  c++  java
  • 帧间预测--运动补偿

    运动补偿

    原理

        百科上说“运动补偿是通过先前的局部图像来预测、补偿当前的局部图像,它是减少帧序列冗余信息的有效方法”,通过前面的运动估计我们得到了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函数里面。

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


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


    单向预测的运动补偿

    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. }  

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

    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.   
    7.     Int dstStride = dstPic->getStride();  
    8.     Pel *dst      = dstPic->getLumaAddr( partAddr );  
    9.   
    10.     Int xFrac = mv->getHor() & 0x3;  
    11.     Int yFrac = mv->getVer() & 0x3;  
    12.   
    13.     if ( yFrac == 0 )  
    14.     {  
    15.         m_if.filterHorLuma( ref, refStride, dst, dstStride, width, height, xFrac,       !bi );  
    16.     }  
    17.     else if ( xFrac == 0 )  
    18.     {  
    19.         m_if.filterVerLuma( ref, refStride, dst, dstStride, width, height, yFrac, true, !bi );  
    20.     }  
    21.     else  
    22.     {  
    23.         Int tmpStride = m_filteredBlockTmp[0].getStride();  
    24.         Short *tmp    = m_filteredBlockTmp[0].getLumaAddr();  
    25.   
    26.         Int filterSize = NTAPS_LUMA;  
    27.         Int halfFilterSize = ( filterSize >> 1 );  
    28.   
    29.         m_if.filterHorLuma(ref - (halfFilterSize-1)*refStride, refStride, tmp, tmpStride, width, height+filterSize-1, xFrac, false     );  
    30.         m_if.filterVerLuma(tmp + (halfFilterSize-1)*tmpStride, tmpStride, dst, dstStride, width, height,              yFrac, false, !bi);      
    31.     }  
    32. }  

    双向预测运动补偿

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

    加权预测


    单向加权预测


    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.   
    12.     if ( eRefPicList == REF_PIC_LIST_0 )  
    13.     {  
    14.         getWpScaling(pcCU, iRefIdx, -1, pwp, pwpTmp);  
    15.     }  
    16.     else  
    17.     {  
    18.         getWpScaling(pcCU, -1, iRefIdx, pwpTmp, pwp);  
    19.     }  
    20.     addWeightUni( pcYuvSrc, uiPartAddr, iWidth, iHeight, pwp, rpcYuvPred );  
    21. }  

    双向加权预测

    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.   
    10.     // getWpScaling的作用就是设置权重table的参数  
    11.     getWpScaling(pcCU, iRefIdx0, iRefIdx1, pwp0, pwp1);  
    12.   
    13.   
    14.     // addWeightUni根据权重参数对目标像素块进行权重转换,即对每一个像素通过一个公式去重新计算它的值  
    15.     if( iRefIdx0 >= 0 && iRefIdx1 >= 0 )  
    16.     {  
    17.         addWeightBi(pcYuvSrc0, pcYuvSrc1, uiPartIdx, iWidth, iHeight, pwp0, pwp1, rpcYuvDst );  
    18.     }  
    19.     else if ( iRefIdx0 >= 0 && iRefIdx1 <  0 )  
    20.     {  
    21.         addWeightUni( pcYuvSrc0, uiPartIdx, iWidth, iHeight, pwp0, rpcYuvDst );  
    22.     }  
    23.     else if ( iRefIdx0 <  0 && iRefIdx1 >= 0 )  
    24.     {  
    25.         addWeightUni( pcYuvSrc1, uiPartIdx, iWidth, iHeight, pwp1, rpcYuvDst );  
    26.     }  
    27.     else  
    28.     {  
    29.         assert (0);  
    30.     }  
    31. }  

    平均加权预测

      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.     }  

     

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

  • 相关阅读:
    Hive-0.12.0 配置Mysql的Metasotre
    cdecl、stdcall、fastcall、thiscall函数调用约定区别 (转)
    汇编函数 哪些寄存器在使用时需要保护和恢复现场
    如何用C++ 写Python模块扩展(二)
    如何用C++ 写Python模块扩展(一)
    python装饰器装饰原理探秘
    Linux 命令
    iOS为所需要的视图添加模糊效果--UIVisualEffectView
    UIAlertView ----警告视图
    Virtual Box 下Ubuntu桥接网络设置
  • 原文地址:https://www.cnblogs.com/Bill-LHR/p/6825081.html
Copyright © 2011-2022 走看看