帧间预测--运动补偿
運(yùn)動(dòng)補(bǔ)償
原理
百科上說“運(yùn)動(dòng)補(bǔ)償是通過先前的局部圖像來預(yù)測(cè)、補(bǔ)償當(dāng)前的局部圖像,它是減少幀序列冗余信息的有效方法”,通過前面的運(yùn)動(dòng)估計(jì)我們得到了MV(運(yùn)動(dòng)向量),大部分情況下MV是亞像素精度的,MV的作用就是定位參考?jí)K在參考幀中的位置,但是亞像素的MV定位出來的位置是沒有像素點(diǎn)的(亞像素就是指該位置在兩個(gè)像素之間),換句話說非整像素精度的MV定位出來的地方?jīng)]有像素點(diǎn)(即沒有像素塊),那么我們需要使用現(xiàn)有的像素點(diǎn)去構(gòu)造亞像素點(diǎn),這樣通過MV找到位置才有參考?jí)K。運(yùn)動(dòng)補(bǔ)償實(shí)際干的就是這么回事它通過MV和現(xiàn)有的像素塊去構(gòu)造一個(gè)亞像素塊,這個(gè)新被創(chuàng)建出來的像素塊就是當(dāng)前PU的參考?jí)K。這樣,得到了MV和參考?jí)K之后就可以進(jìn)行后續(xù)的工作了。
運(yùn)動(dòng)補(bǔ)償入口函數(shù)
motionCompensation()完成了運(yùn)動(dòng)補(bǔ)償?shù)墓ぷ鳎?/p>
motionCompensation()調(diào)用了xPredInterUni()完成了單向預(yù)測(cè)的運(yùn)動(dòng)補(bǔ)償;而調(diào)用xPredInterBi()完成了雙向預(yù)測(cè)的運(yùn)動(dòng)補(bǔ)償,它實(shí)際調(diào)用xPredInterBi和xWeightedPredictionBi來完成相應(yīng)的工作。其中xPredInterUni()調(diào)用xPredInterBlk()完成一個(gè)分量塊的運(yùn)動(dòng)補(bǔ)償。而xPredInterBlk()調(diào)用了TComInterpolationFilter類的filterHor()和filterVer()完成了亞像素的插值工作。
motionCompensation的流程:
1、如果指明了PU,那么只對(duì)這個(gè)PU進(jìn)行處理,如果沒有指明PU,那么對(duì)CU下面的所有PU進(jìn)行處理。
2、對(duì)于一個(gè)PU,如果指定了參考列表,那么表示進(jìn)行單向運(yùn)動(dòng)補(bǔ)償(雙向運(yùn)動(dòng)補(bǔ)償可以通過兩次單向操作來完成);如果沒有指定參考列表,那么默認(rèn)進(jìn)行雙向運(yùn)動(dòng)補(bǔ)償,但是在操作之前先確認(rèn)PU兩個(gè)方向上的參考幀是否相同,如果相同,表示只有一個(gè)參考幀那么它實(shí)際還是進(jìn)行單向運(yùn)動(dòng)補(bǔ)償,否則使用雙向運(yùn)動(dòng)補(bǔ)償。
3、無論是單向運(yùn)動(dòng)補(bǔ)償還是雙向運(yùn)動(dòng)補(bǔ)償,都需要在亞像素插值工作完成之后,檢測(cè)是否需要進(jìn)行加權(quán)預(yù)測(cè),相關(guān)的加權(quán)操作是在xWeightedPredictionUni中完成的,這個(gè)函數(shù)根據(jù)權(quán)重參數(shù)對(duì)目標(biāo)像素塊進(jìn)行權(quán)重轉(zhuǎn)換,對(duì)每一個(gè)像素通過一個(gè)公式去重新計(jì)算它的值。單向預(yù)測(cè)的運(yùn)動(dòng)補(bǔ)償中,xWeightedPredictionUni跟在xPredInterUni函數(shù)的后面,在雙向預(yù)測(cè)的運(yùn)動(dòng)補(bǔ)償中,xWeightedPredictionUni在xPredInterBi函數(shù)里面。
下面的它的流程圖和代碼:
[cpp] view plain copy
VoidTComPrediction::motionCompensation(TComDataCU*pcCU,TComYuv*pcYuvPred,RefPicListeRefPicList,IntiPartIdx)
{
IntiWidth;
IntiHeight;
UIntuiPartAddr;
//如果PU的索引是有效值,那么直接處理該P(yáng)U,然后返回
if(iPartIdx>=0)
{
pcCU->getPartIndexAndSize(iPartIdx,uiPartAddr,iWidth,iHeight);
//有效的參考列表,即明確的標(biāo)明了使用哪個(gè)參考列表,那么就在對(duì)應(yīng)的方向上進(jìn)行單向預(yù)測(cè)
if(eRefPicList!=REF_PIC_LIST_X)
{
//先進(jìn)行插值操作
if(pcCU->getSlice()->getPPS()->getUseWP())
{
xPredInterUni(pcCU,uiPartAddr,iWidth,iHeight,eRefPicList,pcYuvPred,true);//最后一個(gè)參數(shù)指明是否為雙向預(yù)測(cè)
}
else
{
xPredInterUni(pcCU,uiPartAddr,iWidth,iHeight,eRefPicList,pcYuvPred);
}
//加權(quán)預(yù)測(cè)
if(pcCU->getSlice()->getPPS()->getUseWP())
{
xWeightedPredictionUni(pcCU,pcYuvPred,uiPartAddr,iWidth,iHeight,eRefPicList,pcYuvPred);
}
}
//沒有指明明確的參考列表,那么判斷PU兩個(gè)方向上的參考幀是否一樣
else
{
//如果PU的兩個(gè)參考列表是相同的,即它們的運(yùn)動(dòng)是一致的
//那么直接使用單向預(yù)測(cè)
if(xCheckIdenticalMotion(pcCU,uiPartAddr))
{
xPredInterUni(pcCU,uiPartAddr,iWidth,iHeight,REF_PIC_LIST_0,pcYuvPred);
}
//否則使用雙向預(yù)測(cè)
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;
}
單向預(yù)測(cè)的運(yùn)動(dòng)補(bǔ)償
[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);
}
對(duì)亮度塊進(jìn)行亞像素插值工作
[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);
}
}
雙向預(yù)測(cè)運(yùn)動(dòng)補(bǔ)償
[cpp] view plain copy
VoidTComPrediction::xPredInterBi(TComDataCU*pcCU,UIntuiPartAddr,IntiWidth,IntiHeight,TComYuv*&rpcYuvPred)
{
TComYuv*pcMbYuv;
IntiRefIdx[2]={-1,-1};
//執(zhí)行兩次單向預(yù)測(cè)的運(yùn)動(dòng)補(bǔ)償,就可以完成雙向預(yù)測(cè)的運(yùn)動(dòng)補(bǔ)償了
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];
//單向預(yù)測(cè)的運(yùn)動(dòng)補(bǔ)償
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);
}
}
}
//加權(quán)預(yù)測(cè)
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);
}
}
加權(quán)預(yù)測(cè)
單向加權(quán)預(yù)測(cè)
[cpp] view plain copy
//getWpScaling的作用就是設(shè)置權(quán)重table的參數(shù)
//addWeightUni根據(jù)權(quán)重參數(shù)對(duì)目標(biāo)像素塊進(jìn)行權(quán)重轉(zhuǎn)換,即對(duì)每一個(gè)像素通過一個(gè)公式去重新計(jì)算它的值
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);
}
雙向加權(quán)預(yù)測(cè)
[cpp] view plain copy
/*
**雙向加權(quán)預(yù)測(cè)
*/
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的作用就是設(shè)置權(quán)重table的參數(shù)
getWpScaling(pcCU,iRefIdx0,iRefIdx1,pwp0,pwp1);
//addWeightUni根據(jù)權(quán)重參數(shù)對(duì)目標(biāo)像素塊進(jìn)行權(quán)重轉(zhuǎn)換,即對(duì)每一個(gè)像素通過一個(gè)公式去重新計(jì)算它的值
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);
}
}
平均加權(quán)預(yù)測(cè)
[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);
}
}
轉(zhuǎn)自:http://blog.csdn.net/NB_vol_1/article/details/55253979
總結(jié)
以上是生活随笔為你收集整理的帧间预测--运动补偿的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 功夫战警中弟弟吃的什么糖?
- 下一篇: 烤红薯机哪里卖 探寻烤红薯机的购买渠道?