欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 综合教程 >内容正文

综合教程

帧间预测--运动补偿

发布时间:2024/8/26 综合教程 39 生活家
生活随笔 收集整理的这篇文章主要介绍了 帧间预测--运动补偿 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

运动补偿

原理



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

VoidTComPrediction::motionCompensation(TComDataCU*pcCU,TComYuv*pcYuvPred,RefPicListeRefPicList,IntiPartIdx)
{
IntiWidth;
IntiHeight;
UIntuiPartAddr;

//如果PU的索引是有效值,那么直接处理该PU,然后返回
if(iPartIdx>=0)
{
pcCU->getPartIndexAndSize(iPartIdx,uiPartAddr,iWidth,iHeight);

//有效的参考列表,即明确的标明了使用哪个参考列表,那么就在对应的方向上进行单向预测
if(eRefPicList!=REF_PIC_LIST_X)
{
//先进行插值操作
if(pcCU->getSlice()->getPPS()->getUseWP())
{
xPredInterUni(pcCU,uiPartAddr,iWidth,iHeight,eRefPicList,pcYuvPred,true);//最后一个参数指明是否为双向预测
}
else
{
xPredInterUni(pcCU,uiPartAddr,iWidth,iHeight,eRefPicList,pcYuvPred);
}

//加权预测
if(pcCU->getSlice()->getPPS()->getUseWP())
{
xWeightedPredictionUni(pcCU,pcYuvPred,uiPartAddr,iWidth,iHeight,eRefPicList,pcYuvPred);
}
}
//没有指明明确的参考列表,那么判断PU两个方向上的参考帧是否一样
else
{
//如果PU的两个参考列表是相同的,即它们的运动是一致的
//那么直接使用单向预测
if(xCheckIdenticalMotion(pcCU,uiPartAddr))
{
xPredInterUni(pcCU,uiPartAddr,iWidth,iHeight,REF_PIC_LIST_0,pcYuvPred);
}
//否则使用双向预测
else
{
xPredInterBi(pcCU,uiPartAddr,iWidth,iHeight,pcYuvPred);
}
}
return;
}

//否则处理CU下的所有PU
for(iPartIdx=0;iPartIdx<pcCU->getNumPartitions();iPartIdx++)
{
pcCU->getPartIndexAndSize(iPartIdx,uiPartAddr,iWidth,iHeight);

if(eRefPicList!=REF_PIC_LIST_X)
{
if(pcCU->getSlice()->getPPS()->getUseWP())
{
xPredInterUni(pcCU,uiPartAddr,iWidth,iHeight,eRefPicList,pcYuvPred,true);
}
else
{
xPredInterUni(pcCU,uiPartAddr,iWidth,iHeight,eRefPicList,pcYuvPred);
}
if(pcCU->getSlice()->getPPS()->getUseWP())
{
xWeightedPredictionUni(pcCU,pcYuvPred,uiPartAddr,iWidth,iHeight,eRefPicList,pcYuvPred);
}
}
else
{
if(xCheckIdenticalMotion(pcCU,uiPartAddr))
{
xPredInterUni(pcCU,uiPartAddr,iWidth,iHeight,REF_PIC_LIST_0,pcYuvPred);
}
else
{
xPredInterBi(pcCU,uiPartAddr,iWidth,iHeight,pcYuvPred);
}
}
}
return;
}

单向预测的运动补偿

[cpp] view plain copy

VoidTComPrediction::xPredInterUni(TComDataCU*pcCU,UIntuiPartAddr,IntiWidth,IntiHeight,RefPicListeRefPicList,TComYuv*&rpcYuvPred,Boolbi)
{
IntiRefIdx=pcCU->getCUMvField(eRefPicList)->getRefIdx(uiPartAddr);assert(iRefIdx>=0);
TComMvcMv=pcCU->getCUMvField(eRefPicList)->getMv(uiPartAddr);
pcCU->clipMv(cMv);
xPredInterLumaBlk(pcCU,pcCU->getSlice()->getRefPic(eRefPicList,iRefIdx)->getPicYuvRec(),uiPartAddr,&cMv,iWidth,iHeight,rpcYuvPred,bi);
xPredInterChromaBlk(pcCU,pcCU->getSlice()->getRefPic(eRefPicList,iRefIdx)->getPicYuvRec(),uiPartAddr,&cMv,iWidth,iHeight,rpcYuvPred,bi);
}

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

[cpp] view plain copy

VoidTComPrediction::xPredInterLumaBlk(TComDataCU*cu,TComPicYuv*refPic,UIntpartAddr,TComMv*mv,Intwidth,Intheight,TComYuv*&dstPic,Boolbi)
{
IntrefStride=refPic->getStride();
IntrefOffset=(mv->getHor()>>2)+(mv->getVer()>>2)*refStride;
Pel*ref=refPic->getLumaAddr(cu->getAddr(),cu->getZorderIdxInCU()+partAddr)+refOffset;

IntdstStride=dstPic->getStride();
Pel*dst=dstPic->getLumaAddr(partAddr);

IntxFrac=mv->getHor()&0x3;
IntyFrac=mv->getVer()&0x3;

if(yFrac==0)
{
m_if.filterHorLuma(ref,refStride,dst,dstStride,width,height,xFrac,!bi);
}
elseif(xFrac==0)
{
m_if.filterVerLuma(ref,refStride,dst,dstStride,width,height,yFrac,true,!bi);
}
else
{
InttmpStride=m_filteredBlockTmp[0].getStride();
Short*tmp=m_filteredBlockTmp[0].getLumaAddr();

IntfilterSize=NTAPS_LUMA;
InthalfFilterSize=(filterSize>>1);

m_if.filterHorLuma(ref-(halfFilterSize-1)*refStride,refStride,tmp,tmpStride,width,height+filterSize-1,xFrac,false);
m_if.filterVerLuma(tmp+(halfFilterSize-1)*tmpStride,tmpStride,dst,dstStride,width,height,yFrac,false,!bi);
}
}

双向预测运动补偿

[cpp] view plain copy

VoidTComPrediction::xPredInterBi(TComDataCU*pcCU,UIntuiPartAddr,IntiWidth,IntiHeight,TComYuv*&rpcYuvPred)
{
TComYuv*pcMbYuv;
IntiRefIdx[2]={-1,-1};

//执行两次单向预测的运动补偿,就可以完成双向预测的运动补偿了
for(IntiRefList=0;iRefList<2;iRefList++)
{
RefPicListeRefPicList=(iRefList?REF_PIC_LIST_1:REF_PIC_LIST_0);
iRefIdx[iRefList]=pcCU->getCUMvField(eRefPicList)->getRefIdx(uiPartAddr);

if(iRefIdx[iRefList]<0)
{
continue;
}

assert(iRefIdx[iRefList]<pcCU->getSlice()->getNumRefIdx(eRefPicList));

pcMbYuv=&m_acYuvPred[iRefList];

//单向预测的运动补偿
if(pcCU->getCUMvField(REF_PIC_LIST_0)->getRefIdx(uiPartAddr)>=0&&pcCU->getCUMvField(REF_PIC_LIST_1)->getRefIdx(uiPartAddr)>=0)
{
xPredInterUni(pcCU,uiPartAddr,iWidth,iHeight,eRefPicList,pcMbYuv,true);
}
else
{
if((pcCU->getSlice()->getPPS()->getUseWP()&&pcCU->getSlice()->getSliceType()==P_SLICE)||
(pcCU->getSlice()->getPPS()->getWPBiPred()&&pcCU->getSlice()->getSliceType()==B_SLICE))
{
xPredInterUni(pcCU,uiPartAddr,iWidth,iHeight,eRefPicList,pcMbYuv,true);
}
else
{
xPredInterUni(pcCU,uiPartAddr,iWidth,iHeight,eRefPicList,pcMbYuv);
}
}
}

//加权预测
if(pcCU->getSlice()->getPPS()->getWPBiPred()&&pcCU->getSlice()->getSliceType()==B_SLICE)
{
xWeightedPredictionBi(pcCU,&m_acYuvPred[0],&m_acYuvPred[1],iRefIdx[0],iRefIdx[1],uiPartAddr,iWidth,iHeight,rpcYuvPred);
}
elseif(pcCU->getSlice()->getPPS()->getUseWP()&&pcCU->getSlice()->getSliceType()==P_SLICE)
{
xWeightedPredictionUni(pcCU,&m_acYuvPred[0],uiPartAddr,iWidth,iHeight,REF_PIC_LIST_0,rpcYuvPred);
}
else
{
xWeightedAverage(&m_acYuvPred[0],&m_acYuvPred[1],iRefIdx[0],iRefIdx[1],uiPartAddr,iWidth,iHeight,rpcYuvPred);
}
}

加权预测

单向加权预测

[cpp] view plain copy

//getWpScaling的作用就是设置权重table的参数
//addWeightUni根据权重参数对目标像素块进行权重转换,即对每一个像素通过一个公式去重新计算它的值
VoidTComWeightPrediction::xWeightedPredictionUni(TComDataCU*pcCU,TComYuv*pcYuvSrc,UIntuiPartAddr,IntiWidth,IntiHeight,RefPicListeRefPicList,TComYuv*&rpcYuvPred,IntiRefIdx)
{
wpScalingParam*pwp,*pwpTmp;
if(iRefIdx<0)
{
iRefIdx=pcCU->getCUMvField(eRefPicList)->getRefIdx(uiPartAddr);
}
assert(iRefIdx>=0);

if(eRefPicList==REF_PIC_LIST_0)
{
getWpScaling(pcCU,iRefIdx,-1,pwp,pwpTmp);
}
else
{
getWpScaling(pcCU,-1,iRefIdx,pwpTmp,pwp);
}
addWeightUni(pcYuvSrc,uiPartAddr,iWidth,iHeight,pwp,rpcYuvPred);
}

双向加权预测

[cpp] view plain copy

/*
**双向加权预测
*/
VoidTComWeightPrediction::xWeightedPredictionBi(TComDataCU*pcCU,TComYuv*pcYuvSrc0,TComYuv*pcYuvSrc1,IntiRefIdx0,IntiRefIdx1,UIntuiPartIdx,IntiWidth,IntiHeight,TComYuv*rpcYuvDst)
{
wpScalingParam*pwp0,*pwp1;
TComPPS*pps=pcCU->getSlice()->getPPS();
assert(pps->getWPBiPred());

//getWpScaling的作用就是设置权重table的参数
getWpScaling(pcCU,iRefIdx0,iRefIdx1,pwp0,pwp1);


//addWeightUni根据权重参数对目标像素块进行权重转换,即对每一个像素通过一个公式去重新计算它的值
if(iRefIdx0>=0&&iRefIdx1>=0)
{
addWeightBi(pcYuvSrc0,pcYuvSrc1,uiPartIdx,iWidth,iHeight,pwp0,pwp1,rpcYuvDst);
}
elseif(iRefIdx0>=0&&iRefIdx1<0)
{
addWeightUni(pcYuvSrc0,uiPartIdx,iWidth,iHeight,pwp0,rpcYuvDst);
}
elseif(iRefIdx0<0&&iRefIdx1>=0)
{
addWeightUni(pcYuvSrc1,uiPartIdx,iWidth,iHeight,pwp1,rpcYuvDst);
}
else
{
assert(0);
}
}

平均加权预测

[cpp] view plain copy

VoidTComPrediction::xWeightedAverage(TComYuv*pcYuvSrc0,TComYuv*pcYuvSrc1,IntiRefIdx0,IntiRefIdx1,UIntuiPartIdx,IntiWidth,IntiHeight,TComYuv*&rpcYuvDst)
{
if(iRefIdx0>=0&&iRefIdx1>=0)
{
rpcYuvDst->addAvg(pcYuvSrc0,pcYuvSrc1,uiPartIdx,iWidth,iHeight);
}
elseif(iRefIdx0>=0&&iRefIdx1<0)
{
pcYuvSrc0->copyPartToPartYuv(rpcYuvDst,uiPartIdx,iWidth,iHeight);
}
elseif(iRefIdx0<0&&iRefIdx1>=0)
{
pcYuvSrc1->copyPartToPartYuv(rpcYuvDst,uiPartIdx,iWidth,iHeight);
}
}

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

总结

以上是生活随笔为你收集整理的帧间预测--运动补偿的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。