帧间预测--运动补偿
運動補償
原理
百科上說“運動補償是通過先前的局部圖像來預測、補償當前的局部圖像,它是減少幀序列冗余信息的有效方法”,通過前面的運動估計我們得到了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
總結
以上是生活随笔為你收集整理的帧间预测--运动补偿的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 功夫战警中弟弟吃的什么糖?
- 下一篇: SQL参数化查询