天天看點

幀内角度預測之planner和DC模式模式--幀内編碼學習(四)

 幀内角度預測函數如下

void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, const PredictionUnit &pu, const bool useFilteredPredSamples )
           

根據預測模式調用模式預測函數,這篇文章主要講planner和DC模式。

其他模式待更新。。。

1、planner模式

 planner模式預測的參考模闆示意圖如下

幀内角度預測之planner和DC模式模式--幀内編碼學習(四)

這裡公式都用乘除法給出,實際程式中采用移位。圖中LB為lC(i+1)和RT為tR(j+1)。

幀内角度預測之planner和DC模式模式--幀内編碼學習(四)

planner模式的具體程式注釋如下

void IntraPrediction::xPredIntraPlanar( const CPelBuf &pSrc, PelBuf &pDst, const SPS& sps )
{
  const uint32_t width  = pDst.width;
  const uint32_t height = pDst.height;
#if JVET_M0102_INTRA_SUBPARTITIONS
  const uint32_t log2W  = g_aucLog2[width  < 2 ? 2 : width];
  const uint32_t log2H  = g_aucLog2[height < 2 ? 2 : height];
#else
  const uint32_t log2W  = g_aucLog2[ width ];
  const uint32_t log2H  = g_aucLog2[ height ];
#endif

  int leftColumn[MAX_CU_SIZE + 1], topRow[MAX_CU_SIZE + 1], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE];
#if JVET_M0102_INTRA_SUBPARTITIONS
  const uint32_t offset = 1 << (log2W + log2H);
#else
  const uint32_t offset = width * height;
#endif

  // Get left and above reference column and row
  for( int k = 0; k < width + 1; k++ )
  {
    topRow[k] = pSrc.at( k + 1, 0 );//上參考
  }

  for( int k = 0; k < height + 1; k++ )
  {
    leftColumn[k] = pSrc.at( 0, k + 1 );//左參考
  }

  // Prepare intermediate variables used in interpolation
  int bottomLeft = leftColumn[height];//左下lc(i+1)
  int topRight = topRow[width];//右上tR(j+1)

  for( int k = 0; k < width; k++ )
  {
    bottomRow[k] = bottomLeft - topRow[k];//lC(i+1)-tR(j)
    topRow[k]    = topRow[k] << log2H;//tR(j)*H
  }

  for( int k = 0; k < height; k++ )
  {
    rightColumn[k] = topRight - leftColumn[k];//tR(j+1)-lC(i)
    leftColumn[k]  = leftColumn[k] << log2W;//lC(i)*W
  }

  const uint32_t finalShift = 1 + log2W + log2H;//2WH
  const uint32_t stride     = pDst.stride;
  Pel*       pred       = pDst.buf;
  for( int y = 0; y < height; y++, pred += stride )
  {
    int horPred = leftColumn[y];//W*lC(i)

    for( int x = 0; x < width; x++ )
    {
      horPred += rightColumn[y];//Ph(i,j)=W*lC(i)-j*rC(i)
      topRow[x] += bottomRow[x];//Pv(i,j)=H*tR(j)-i*bR(j)

      int vertPred = topRow[x];
      pred[x]      = ( ( horPred << log2H ) + ( vertPred << log2W ) + offset ) >> finalShift;
      //P(i,j)=(Ph(i,j)*H+Pv(i,j)*W+W*H)/(2*W*H)
    }
  }
}
           

2、DC模式

根據PU的形狀,對于正方形的PU計算上邊和左邊的參考像素的均值,對于非正方形計算長長邊的均值,然後填充PU。

DC模式的具體程式注釋如下

void IntraPrediction::xPredIntraDc( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const bool enableBoundaryFilter )
{
  const Pel dcval = xGetPredValDc( pSrc, pDst );//DC計算入口
  pDst.fill( dcval );

#if HEVC_USE_DC_PREDFILTERING
  if( enableBoundaryFilter )
  {
    xDCPredFiltering( pSrc, pDst, channelType );
  }
#endif
}
           

 DC值的具體計算

Pel IntraPrediction::xGetPredValDc( const CPelBuf &pSrc, const Size &dstSize )
{
  CHECK( dstSize.width == 0 || dstSize.height == 0, "Empty area provided" );

  int idx, sum = 0;
  Pel dcVal;
  const int width  = dstSize.width;
  const int height = dstSize.height;
  const auto denom     = (width == height) ? (width << 1) : std::max(width,height);//對于正方形計算所有參考像素,非正方形計算長邊
  const auto divShift  = g_aucLog2[denom];
  const auto divOffset = (denom >> 1);//偏置

  if ( width >= height )//計算上參考
  {
    for( idx = 0; idx < width; idx++ )
    {
      sum += pSrc.at( 1 + idx, 0 );
    }
  }
  if ( width <= height )//計算左參考
  {
    for( idx = 0; idx < height; idx++ )
    {
      sum += pSrc.at( 0, 1 + idx );
    }
  }

  dcVal = (sum + divOffset) >> divShift;//計算DC值
  return dcVal;
}
           

繼續閱讀