VVC 帧内预测 —— MIP代码学习

主要流程

MIP预测函数调用流程如下:

参考像素获取及下采样

参考像素获取由initIntraMip()调用prepareInputForPred()完成,prepareInputForPred()调用 deriveBoundaryData()进行参考图像获取,并进行下采样,下面来看一下deriveBoundaryData()这个函数,三个步骤:

  1. 参数初始化
  2. 参考像素获取
  3. 下采样(Haar-downsampling)
void PredictorMIP::deriveBoundaryData(const CPelBuf& src, const Area& block, const int bitDepth, const AvailableInfo &availInfo)
  {
    // Step 1: Save block size and calculate dependent values
    /* 参数初始化包括以下数据:m_blockSize和m_numModes
    * 1. 预测块尺寸 及 尺寸对应MIP预测模式数量:
    * 2. reduced bdry size (参考像素下采样目标尺寸):m_reducedBoundarySize
    * 3. 仿射变换后的尺寸:m_reducedPredictionSize
    * 4. 上采样使用的边界尺寸:m_boundarySizeForUpsampling
    * 5. 两个方向的上采样因子m_upsmpFactorHor,m_upsmpFactorVer
    */
    initPredBlockParams(block);

 	/************************* 获取重建参考 *******************************/
 	// 先将左上边界的参考值存下
    // Step 2: Get the input data (left and top reference samples)
    const int defaultPad = int(1 << (bitDepth - 1)); //默认填充值

    // TOP (save top boundary since we might need it for upsampling)
    m_boundaryForUpsamplingTop.resize( block.width );
    const int availPosTop = availInfo.maxPosTop;
    CHECKD(availPosTop > block.width, "Error: availPosTop out of range");

    if (availPosTop > 0) //上边界参考有效
    {
      // top available
      const Position posT0(block.x, block.y - 1); // offset(0,-1)
      for (int x = 0; x < availPosTop; x++) // 对参考填充有效的availPosTop个值
      {
        m_boundaryForUpsamplingTop[ x ] = src.at( posT0.offset( x, 0 ) ); 
      }
      // top unavailable 余下填充默认值
      const int padVal = m_boundaryForUpsamplingTop[ availPosTop - 1 ];
      for( int x = availPosTop; x < m_boundaryForUpsamplingTop.size(); x++ )
      {
        m_boundaryForUpsamplingTop[ x ] = padVal;
      }
    }
    else //参考填充默认值
    {
      std::fill( m_boundaryForUpsamplingTop.begin(), m_boundaryForUpsamplingTop.end(), defaultPad );
    }

    // LEFT (save left boundary since we might need it for upsampling)
    m_boundaryForUpsamplingLeft.resize( block.height );
    const int availPosLeft = availInfo.maxPosLeft;
    CHECKD(availPosLeft > block.height, "Error: availPosLeft out of range");

	// 左边界处理同上边界
    if (availPosLeft > 0)
    {
      // left available
      const Position posL0(block.x - 1, block.y);
      for (int y = 0; y < availPosLeft; y++)
      {
        m_boundaryForUpsamplingLeft[ y ] = src.at( posL0.offset( 0, y ) );
      }
      // left unavailable
      const int padVal = m_boundaryForUpsamplingLeft[ availPosLeft - 1 ];
      for( int y = availPosLeft; y < m_boundaryForUpsamplingLeft.size(); y++ )
      {
        m_boundaryForUpsamplingLeft[ y ] = padVal;
      }
    }
    else
    {
      std::fill( m_boundaryForUpsamplingLeft.begin(), m_boundaryForUpsamplingLeft.end(), defaultPad );
    }

	/************************* 对上述参考进行下采样 *******************************/
    // Step 3: Compute the reduced boundary via Haar-downsampling (input for the prediction and intermediate boundary for upsampling)
    m_reducedBoundary          .resize( m_reducedBoundarySize.width + m_reducedBoundarySize.height ); // concat [bdry_top bdry_left]
    m_reducedBoundaryTransposed.resize( m_reducedBoundarySize.width + m_reducedBoundarySize.height ); // concat [bdry_left bdry_top]

    const bool needVerticalUpsampling = ( m_upsmpFactorVer > 1 ); // 垂直方向之后是否要进行上采样
    int* const topReduced = m_reducedBoundary.data(); //下采样信号首地址
    boundaryDownsampling1D( topReduced, m_boundaryForUpsamplingTop.data(), block.width, m_reducedBoundarySize.width, needVerticalUpsampling, m_boundarySizeForUpsampling.width ); // 进行下采样,不再详细说,详情见上一博文
    m_boundaryForUpsamplingTop.resize( needVerticalUpsampling ? m_boundarySizeForUpsampling.width : 0 );

    const bool needHorizontalUpsampling = ( m_upsmpFactorHor > 1 ); //水平方向之后是否要进行上采样
    int* const leftReduced = m_reducedBoundary.data() + m_reducedBoundarySize.width; // 左侧参考首地址,相对原始参考偏移width
    boundaryDownsampling1D( leftReduced, m_boundaryForUpsamplingLeft.data(), block.height, m_reducedBoundarySize.height, needHorizontalUpsampling, m_boundarySizeForUpsampling.height ); // 下采样
    m_boundaryForUpsamplingLeft.resize( needHorizontalUpsampling ? m_boundarySizeForUpsampling.height : 0 );

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

MIP 预测

estIntraPredLumaQT()中会调用predIntraMip()获取MIP预测信号,predIntraMip()通过调用MatrixIntraPrediction类中函数 predBlock()predBlock()最终调用PredictorMIP类中函数 getPrediction()得到预测值。看一下这个函数,主要以下步骤

  1. 获取Matrix
  2. 获取bais
  3. 计算reduced prediction
  4. reduced prediction上采样
void PredictorMIP::getPrediction(int* const result, const int modeIdx, const int bitDepth)
  {
    const bool transpose = isTransposed( modeIdx ); // 判断参考像素concat方式
    const bool needUpsampling = ( m_upsmpFactorHor > 1 ) || ( m_upsmpFactorVer > 1 );
    
    // pred = matrix * reduce_ref + bais
    const short* matrix; // 系数矩阵
    const short* bias;   // 偏执
    getMatrixBias( matrix, bias, modeIdx );  // 根据angular mode和MIP mode的映射表,查表获得

    int shiftMatrix = 0;
    int shiftBias = 0;
    getShifts(shiftMatrix, shiftBias, modeIdx, bitDepth );

    bool leaveHorOut = ( m_blockSize.width == 4 && m_blockSize.height >= 16 );
    bool leaveVerOut = ( m_blockSize.height == 4 && m_blockSize.width >= 16 );
    if (transpose)
    {
      std::swap(leaveHorOut, leaveVerOut);
    }
    static_vector<int, MIP_MAX_REDUCED_OUTPUT_SAMPLES> bufReducedPred( m_reducedPredictionSize.area() );
    int* const       reducedPred     = needUpsampling ? bufReducedPred.data() : result;
    const int* const reducedBoundary = transpose ? m_reducedBoundaryTransposed.data() : m_reducedBoundary.data();
    xComputeMatrixTimesRedBndryPlusBias( reducedPred, reducedBoundary, matrix, bias,
                                         leaveHorOut, leaveVerOut,
                                         shiftMatrix, shiftBias,
                                         transpose, needUpsampling );
    // Reduced prediction is transposed if ( transpose && needUpsampling ).

    if( needUpsampling )
    {
      predictionUpsampling( result, reducedPred, transpose );
    }
  }

class PredictorMIP

  class PredictorMIP
  {
  public:
    PredictorMIP();
    void             deriveBoundaryData(const CPelBuf& src, const Area& block, const int bitDepth, const AvailableInfo &availInfo);
    void             getPrediction     (int* const result, const int modeIdx, const int bitDepth);

  private:
    static_vector<int, MIP_MAX_INPUT_SIZE> m_reducedBoundary;           // downsampled             boundary of a block
    static_vector<int, MIP_MAX_INPUT_SIZE> m_reducedBoundaryTransposed; // downsampled, transposed boundary of a block
    static_vector<int, MIP_MAX_WIDTH>      m_boundaryForUpsamplingTop;  // top  boundary samples for upsampling
    static_vector<int, MIP_MAX_HEIGHT>     m_boundaryForUpsamplingLeft; // left boundary samples for upsampling

    Size m_blockSize;
    int  m_numModes;
    Size m_reducedBoundarySize;
    Size m_reducedPredictionSize;
    Size m_boundarySizeForUpsampling;
    unsigned int m_upsmpFactorHor;
    unsigned int m_upsmpFactorVer;

    void initPredBlockParams(const Size& block);

    static void boundaryDownsampling1D( int* reducedDst, int* fullSrcAndIntermediateDst, const SizeType srcLen, const SizeType dstLen, const bool saveIntermediate, const SizeType intermediateLen );
    static void doDownsampling( int* dst, const int* src, const SizeType srcLen, const SizeType dstLen );

    void predictionUpsampling( int* const dst, const int* const src, const bool transpose ) const;
    static void predictionUpsampling1D( int* const dst, const int* const src, const int* const bndry,
                                        const SizeType srcSizeUpsmpDim, const SizeType srcSizeOrthDim,
                                        const SizeType srcStep, const SizeType srcStride,
                                        const SizeType dstStep, const SizeType dstStride,
                                        const unsigned int upsmpFactor );

    void getMatrixBias( const short*& matrix, const short*& bias, const int modeIdx ) const;
    void getShifts( int &shiftMatrix, int &shiftBias, const int modeIdx, const int bitDepth ) const;

    bool isTransposed( const int modeIdx ) const;
    int  getWeightIdx( const int modeIdx ) const;

    void xComputeMatrixTimesRedBndryPlusBias( int*const result, const int* const input,
                                              const short*matrix, const short*bias,
                                              const bool leaveHorOut, const bool leaveVerOut, 
                                              const int shiftMatrix, const int shiftBias,
                                              const bool transpose, const bool needUpsampling );
  };
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值