H.266 / VVCコード学習:MIPテクノロジー関連コードのinitIntraMip関数

initIntraMip関数は、主に参照ピクセルをダウンサンプリングし、MIP行列乗算用の入力データを準備するためのものです。関数の構造は次のとおりです。

MIPは、ブロックサイズに応じて次の3つのケースに分けることができます。

  ブロックサイズ

ダウンサンプリング後の境界の長さ

m_reducedBdrySize

行列乗算の出力境界の長さ

m_reducedPredSize

mipSizeId = 0 4x4 2 4
mipSizeId = 1 4xN、Nx4、8x8 4 4
mipSizeId = 2 レストブロック 4 8

initIntraMip関数は、主に境界参照ピクセルを準備し、prepareInputForPred関数を呼び出して、MIP予測用の入力データを準備します。

注: MIPで使用される参照ピクセルは、フィルタリングされていない参照ピクセルです。

initIntraMip関数コードは次のとおりです。

void IntraPrediction::initIntraMip( const PredictionUnit &pu, const CompArea &area )
{
  CHECK( area.width > MIP_MAX_WIDTH || area.height > MIP_MAX_HEIGHT, "Error: block size not supported for MIP" );

  // prepare input (boundary) data for prediction
  // 准备输入(边界)数据进行预测
  // MIP使用未滤波的参考像素
  CHECK( m_ipaParam.refFilterFlag, "ERROR: unfiltered refs expected for MIP" );
#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
  Pel       *ptrSrc     = getPredictorPtr(area.compID);//获取参考像素
  const int  srcStride  = m_refBufferStride[area.compID];
  const int  srcHStride = 2;

  m_matrixIntraPred.prepareInputForPred(CPelBuf(ptrSrc, srcStride, srcHStride), area,
                                        pu.cu->slice->getSPS()->getBitDepth(toChannelType(area.compID)), area.compID);
#else
  Pel *ptrSrc = getPredictorPtr( COMPONENT_Y );
  const int srcStride  = m_refBufferStride[COMPONENT_Y];
  const int srcHStride = 2;

  m_matrixIntraPred.prepareInputForPred( CPelBuf( ptrSrc, srcStride, srcHStride ), area, pu.cu->slice->getSPS()->getBitDepth( CHANNEL_TYPE_LUMA ) );
#endif
}

prepareInputForPred関数は、主に次の4つのステップに分かれています。

  • ステップ1:ブロックサイズを保存し、initPredBlockParams関数を呼び出してMIP関連のパラメーターを計算します
  • ステップ2:入力データを取得します(前の行の参照ピクセルと左の列の参照ピクセル)
  • ステップ3:Haarダウンサンプリングを使用して削減境界を計算し、boundaryDownsampling1D関数を使用して実装します。
  • ステップ4:行列乗算の入力ベクトルを導出する

prepareInputForPred関数コードは次のとおりです

#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
void MatrixIntraPrediction::prepareInputForPred(const CPelBuf &pSrc, const Area &block, const int bitDepth,
                                                const ComponentID compId)
{
  m_component = compId;
#else
void MatrixIntraPrediction::prepareInputForPred(const CPelBuf &pSrc, const Area& block, const int bitDepth)
{
#endif
  // Step 1: Save block size and calculate dependent values
  // Step 1: 保存块大小并计算MIP相关参数
  initPredBlockParams(block);

  // Step 2: Get the input data (left and top reference samples)
  // Step 2: 获取输入数据(左上参考像素)
  // 获取上一行参考像素
  m_refSamplesTop.resize(block.width);
  for (int x = 0; x < block.width; x++)
  {
    m_refSamplesTop[x] = pSrc.at(x + 1, 0);
  }
  // 获取左一列参考像素
  m_refSamplesLeft.resize(block.height);
  for (int y = 0; y < block.height; y++)
  {
    m_refSamplesLeft[y] = pSrc.at(y + 1, 1);
  }

  // Step 3: Compute the reduced boundary via Haar-downsampling (input for the prediction)
  // Step 3: 通过Haar下采样计算缩减边界(预测输入)
  // 下采样后输入向量的尺寸为4或者8
  const int inputSize = 2 * m_reducedBdrySize;
  // 不需要转置时,下采样像素的顺序:先上后左
  m_reducedBoundary          .resize( inputSize );
  // 转置时,下采样像素的顺序:先左后上
  m_reducedBoundaryTransposed.resize( inputSize );

  int* const topReduced = m_reducedBoundary.data();
  boundaryDownsampling1D( topReduced, m_refSamplesTop.data(), block.width, m_reducedBdrySize );

  int* const leftReduced = m_reducedBoundary.data() + m_reducedBdrySize;
  boundaryDownsampling1D( leftReduced, m_refSamplesLeft.data(), block.height, m_reducedBdrySize );

  int* const leftReducedTransposed = m_reducedBoundaryTransposed.data();
  int* const topReducedTransposed  = m_reducedBoundaryTransposed.data() + m_reducedBdrySize;
  for( int x = 0; x < m_reducedBdrySize; x++ )
  {
    topReducedTransposed[x] = topReduced[x];
  }
  for( int y = 0; y < m_reducedBdrySize; y++ )
  {
    leftReducedTransposed[y] = leftReduced[y];
  }

  // Step 4: Rebase the reduced boundary
  // Step 4: 缩小边界
  // 推导矩阵乘法输入向量p,mipSizeId=0/1和mipSizeId=2的推导方法不一样
  m_inputOffset       = m_reducedBoundary[0];
  m_inputOffsetTransp = m_reducedBoundaryTransposed[0];
  const bool hasFirstCol = (m_sizeId < 2);

  m_reducedBoundary          [0] = hasFirstCol ? ((1 << (bitDepth - 1)) - m_inputOffset      ) : 0; // first column of matrix not needed for large blocks
  m_reducedBoundaryTransposed[0] = hasFirstCol ? ((1 << (bitDepth - 1)) - m_inputOffsetTransp) : 0;
  for (int i = 1; i < inputSize; i++)
  {
    m_reducedBoundary          [i] -= m_inputOffset;
    m_reducedBoundaryTransposed[i] -= m_inputOffsetTransp;
  }
}

1.MIP関連のパラメーターを初期化します

initPredBlockParams関数は、MIP関連のパラメーターを初期化するために使用されます。主に、現在のブロックのサイズに従ってmipSizeIdを初期化し、次にダウンサンプリング後の境界長、行列乗算の出力境界長、およびmipSizeIdに従ってアップサンプリング係数を初期化します。

void MatrixIntraPrediction::initPredBlockParams(const Size& block)
{
  //获得当前块尺寸
  m_blockSize = block;
  // init size index
  // 根据当前块尺寸初始化sizeId
  m_sizeId = getMipSizeId( m_blockSize );
  // init reduced boundary size
  // 初始缩减边界尺寸
  // 对于4x4的块宽度和高度分别缩减为2个像素
  // 对于其余尺寸的块宽度和高度分别缩减为4个像素
  m_reducedBdrySize = (m_sizeId == 0) ? 2 : 4;
  // init reduced prediction size
  // 初始化缩减预测后的尺寸
  // 对于mipSizeId = 0、1的块,MIP预测后输出4x4的块
  // 对于mipSizeId = 2的块,MIP预测后输出8x8的块
  m_reducedPredSize = ( m_sizeId < 2 ) ? 4 : 8;
  // init upsampling factors
  // 初始上采样因子
  m_upsmpFactorHor = m_blockSize.width  / m_reducedPredSize;
  m_upsmpFactorVer = m_blockSize.height / m_reducedPredSize;

  CHECKD( (m_upsmpFactorHor < 1) || ((m_upsmpFactorHor & (m_upsmpFactorHor - 1)) != 0), "Need power of two horizontal upsampling factor." );
  CHECKD( (m_upsmpFactorVer < 1) || ((m_upsmpFactorVer & (m_upsmpFactorVer - 1)) != 0), "Need power of two vertical upsampling factor." );
}

2.ダウンサンプリング

境界参照ピクセルのダウンサンプリングプロセスは、boundaryDownsampling1D関数によって実装されます。ダウンサンプリングプロセスは、実際には境界参照ピクセルを平均化するプロセスです。下の図に示すように、8x8ブロックを例にとると次のようになります。前の行の8つの参照ピクセル。2つの隣接する参照ピクセルを平均した後、4つのダウンサンプリングされた参照ピクセルが取得されます。左の列の参照ピクセルのダウンサンプリングプロセスは同じです。

/*
一维下采样
reducedDst表示下采样后的边界
fullSrc表示下采样前的边界
srcLen表示下采样前的边界长度
dstLen表示下采样后的边界长度
*/
void MatrixIntraPrediction::boundaryDownsampling1D(int* reducedDst, const int* const fullSrc, const SizeType srcLen, const SizeType dstLen)
{
  if (dstLen < srcLen)
  {
    //当下采样后的边界尺寸小于当前块的边界尺寸时,需要进行下采样,下采样操作即相当于求平均操作
    // Create reduced boundary by downsampling 通过下采样创建缩小边界
    const SizeType downsmpFactor = srcLen / dstLen;
    const int log2DownsmpFactor = floorLog2(downsmpFactor);
    const int roundingOffset = (1 << (log2DownsmpFactor - 1));

    SizeType srcIdx = 0;
    for( SizeType dstIdx = 0; dstIdx < dstLen; dstIdx++ )
    {
      int sum = 0;
      for( int k = 0; k < downsmpFactor; k++ )
      {
        sum += fullSrc[srcIdx++];
      }
      reducedDst[dstIdx] = (sum + roundingOffset) >> log2DownsmpFactor;
    }
  }
  else
  {
    // Copy boundary if no downsampling is needed 如果不需要下采样,则复制边界
    for (SizeType i = 0; i < dstLen; ++i)
    {
      reducedDst[i] = fullSrc[i];
    }
  }
}

ダウンサンプリングプロセスが終了した後、ダウンサンプリングされた上部参照ピクセルと左側の参照ピクセルは、mipTransposeFlagフラグに従ってベクトルpTempに配置されます。配置は、次のとおりです。

  • mipTransposeFlag = 0時間、pTemp = [redTop、redLeft]
  • mipTransposeFlag = 1時間、pTemp = [redLeft、redTop]

3.行列乗算の入力ベクトルを導出します

行列乗算入力ベクトルの導出方法は、mipSizeIdに関連しています。入力ベクトルpの構築プロセスを以下に示します。ここで、inSize = 2 * m_reducedBdrySize

 

おすすめ

転載: blog.csdn.net/BigDream123/article/details/107018446