HEVC學習(十二) —— CU的最終劃分

相信會有不少人對如何確定CU最終的劃分有所困惑(包括我在內,剛開始接觸時也不知道該怎麼做),我覺得很大的一個原因就是CU是遞歸劃分的,這就導致在尋找確定最佳分割位置時比較困難。

 

其實,解決問題的辦法說難也不難,關鍵在於思路的轉換,既然對於xCompressCU中是如何保存劃分模式的覺得難以理解,何不跳出這個小圈子尋找新的方法呢?

 

我們可以從解碼器的角度來考慮,因爲最終編碼後的碼流是要經過解碼器解碼的,解碼器事先也是不知道CU到底最終是如何劃分的。因此,可以推斷,編碼器必然會保存下這個信息,至少是提示信息。不妨參考encodeCU這個函數的實現,因爲它是最終將信息編碼成碼流的函數。該函數調用的是xEncodeCU來完成實際工作,截取它當中其中一段對我們有用的代碼:

  1. // We need to split, so don't try these modes.  
  2.   if(!bSliceStart&&( uiRPelX < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( uiBPelY < pcSlice->getSPS()->getPicHeightInLumaSamples() ) )  
  3.   {  
  4.     m_pcEntropyCoder->encodeSplitFlag( pcCU, uiAbsPartIdx, uiDepth );  
  5.   }  


不錯,encodeSplitFlag就是用於編碼CU分割信息的函數,它的實現如下:

  1. // Split mode  
  2. Void TEncEntropy::encodeSplitFlag( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, Bool bRD )  
  3. {  
  4.   if( bRD )  
  5.   {  
  6.     uiAbsPartIdx = 0;  
  7.   }  
  8.   if( !bRD )  
  9.   {  
  10.     if( pcCU->getLastCUSucIPCMFlag() && pcCU->getIPCMFlag(uiAbsPartIdx) )  
  11.     {  
  12.       return;  
  13.     }  
  14.   }  
  15.   
  16.   m_pcEntropyCoderIf->codeSplitFlag( pcCU, uiAbsPartIdx, uiDepth );  
  17. }  


對我們有用的函數是最後的codeSplitFlag函數,它的實現如下:

  1. Void TEncSbac::codeSplitFlag   ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth )  
  2. {  
  3.   if( uiDepth == g_uiMaxCUDepth - g_uiAddCUDepth )  
  4.     return;  
  5.     
  6.   UInt uiCtx           = pcCU->getCtxSplitFlag( uiAbsPartIdx, uiDepth );  
  7.   UInt uiCurrSplitFlag = ( pcCU->getDepth( uiAbsPartIdx ) > uiDepth ) ? 1 : 0;  
  8.     
  9.   assert( uiCtx < 3 );  
  10.   m_pcBinIf->encodeBin( uiCurrSplitFlag, m_cCUSplitFlagSCModel.get( 0, 0, uiCtx ) );  
  11.   DTRACE_CABAC_VL( g_nSymbolCounter++ )  
  12.   DTRACE_CABAC_T( "\tSplitFlag\n" )  
  13.   return;  
  14. }  


可以看到最爲有用的一句:

  1. UInt uiCurrSplitFlag = ( pcCU->getDepth( uiAbsPartIdx ) > uiDepth ) ? 1 : 0;  


也就是說,通過判斷pcCU->getDepth( uiAbsPartIdx )是否大於uiDepth來確定當前CU是否還要繼續分割,後者我們知道,是當前CU的深度,那麼前者呢?自然就是在xCompressCU中確定下來的當前CU的最佳分割模式。至此,我們最想獲得的信息就在這裏。

 

經過上述分析後,一句話總結獲取CU最佳劃分的方法:在HM中調用完xCompressCU之後(至少也應該是compressCU調用完它之後,此時最佳PU爲m_ppcBestCU[0]),在調用encodeCU之前(也可以之後,這個只要保證pcCU沒被修改過即可),對compressCU的參數pcCU進行類似語句: pcCU->getDepth( uiAbsPartIdx ),即可獲得Z order爲uiAbsPartIdx的4x4塊的深度,如果把整個CU每個4x4塊的深度確定下來,那麼它的劃分自然也就確定下來了。

 

下圖是我打印出的某一塊CU在最大尺寸64 x 64,最大深度爲4(即depth = 0 ~ 3)的某一種劃分情況,每個數字代表對應位置的4x4塊的實際深度,紅線給出CU的最佳劃分。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章