H.266 / VVCコード学習:MPMリストの確立(getIntraMPMs関数)

VVCには67の角度モードがあります。各PUの予測モードを個別にコーディングする場合、67のモードをコーディングするには7ビットが必要です。したがって、VVCでは最も可能性の高いモードリスト(MPM)の作成方法も使用されます。画像とビデオのコーディングでは、通常、隣接するブロックは強い相関関係があるため、隣接するブロックのイントラ予測モードは、同じまたは類似する可能性が高くなります。したがって、MPMリストは、左側の隣接するPUと上部のフレームに基づいています。隣接PUVVCでは、MPMリストの長さは6です。フレーム内コーディングでは、MPMリストは主に次の2つのプロセスにあります

  1. マルチリファレンスラインモード(mrl_idx = 1、2)でSATDラフ選択を実行し、MPMリストの6つのイントラ予測モードのみを使用します
  2. MIPモードの大まかな選択が終わったら、MPMリストの予測モードがレート歪み候補リストにあるかどうかをトラバースします。

具体的な構築手順は次のとおりです。

1.次の図に示すように、それぞれAおよびBで示される、左下および右上の隣接する参照ピクセルを取得します。

ここに画像の説明を挿入

2.隣接するピクセルAとBが配置されているPUのイントラ予測モードを取得します。取得方法は次のとおりです。

  • 次の条件のいずれかが当てはまる場合、隣接するPUのイントラ予測モードは平面モードに設定されます 
    • その隣接するPUは利用できません
    • 隣接するPUのコーディングモードはイントラコーディングモードではありません
    • 隣接するPUはMIPモードです
    • 隣接するPUと現在のPUが同じCTUにありません
  • それ以外の場合は、隣接するPUのイントラ予測モードを取得します

3.隣接するピクセルAとBがそれぞれAとBとして配置されているPUの予測モードをマークし、MPMリストを次のように作成します。

(1)A = BANDA> B

MPM [0] 平面
MPM [1]

A

MPM [2]

 2 +((A + 61)%64)

MPM [3] 2 +((A − 1)%64)
MPM [4] 2 +((A + 60)%64)
MPM [5] 2 +(A%64)

(2)A≠B、A> DCANDB> DC

记MinAB = Min(A、B)、MaxAB = max(A、B)

MPM [0] 平面
MPM [1]

A

MPM [2] B

  ①maxAB-minAB= 1の場合、

MPM [3]

2 +((minAB + 61)%64)

MPM [4] 2 +((maxAB-1)%64)
MPM [5] 2 +((minAB + 60)%64)

  ②maxAB-minAB> = 62の場合、

MPM [3]

2 +((minAB − 1)%64)

MPM [4] 2 +((maxAB + 61)%64)
MPM [5] 2 +(minAB%64)

 

   ③maxAB-minAB= 2の場合、

MPM [3]

2 +((minAB − 1)%64)

MPM [4] 2 +((minAB + 61)%64)
MPM [5] 2 +((maxAB-1)%64)

  ④それ以外の場合

MPM [3]

2 +((minAB + 61)%64)

MPM [4] 2 +((minAB-1)%64)
MPM [5] 2 +((maxAB + 61)%64)

 

(3)A≠B、A> DCまたはB> DC

MPM [0] 平面
MPM [1]

maxAB

MPM [2] 2 +((maxAB + 61)%64)
MPM [3] 2 +((maxAB-1)%64)
MPM [4] 2 +((maxAB + 60)%64)
MPM [5] 2+(maxAB%64)

(4)それ以外の場合。

MPM [0] 平面
MPM [1]

DC

MPM [2] 見る
MPM [3] HOR
MPM [4] SEE-4
MPM [5] 見る+4

具体的なコードの実装とコメントは次のとおりです。

int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/ )
{
  const int numMPMs = NUM_MOST_PROBABLE_MODES;
  {
    CHECK(channelType != CHANNEL_TYPE_LUMA, "Not harmonized yet");
    int numCand      = -1;
    int leftIntraDir = PLANAR_IDX, aboveIntraDir = PLANAR_IDX;//将左相邻块和上相邻块预测模式设置为Planar模式

    const CompArea &area = pu.block(getFirstComponentOfChannel(channelType));
    const Position posRT = area.topRight();//当前块的左上角
    const Position posLB = area.bottomLeft();//当前块的右下角

    // Get intra direction of left PU
    // 获得左相邻PU
    const PredictionUnit *puLeft = pu.cs->getPURestricted(posLB.offset(-1, 0), pu, channelType);
    if (puLeft && CU::isIntra(*puLeft->cu))
    {
      leftIntraDir = PU::getIntraDirLuma( *puLeft );//获得左相邻PU的预测模式
    }

    // Get intra direction of above PU
    // 获得上相邻PU
    const PredictionUnit *puAbove = pu.cs->getPURestricted(posRT.offset(0, -1), pu, channelType);
    if (puAbove && CU::isIntra(*puAbove->cu) && CU::isSameCtu(*pu.cu, *puAbove->cu))
    {
      aboveIntraDir = PU::getIntraDirLuma( *puAbove );//获得左相邻PU的预测模式
    }

    CHECK(2 >= numMPMs, "Invalid number of most probable modes");

    const int offset = (int)NUM_LUMA_MODE - 6;//61
    const int mod = offset + 3;//64

    {
      mpm[0] = PLANAR_IDX;//Planar
      mpm[1] = DC_IDX;//DC
      mpm[2] = VER_IDX;//50
      mpm[3] = HOR_IDX;//18
      mpm[4] = VER_IDX - 4;//46
      mpm[5] = VER_IDX + 4;//54

      if (leftIntraDir == aboveIntraDir)
      {
        numCand = 1;
        if (leftIntraDir > DC_IDX)
        {
          mpm[0] = PLANAR_IDX;
          mpm[1] = leftIntraDir;
          mpm[2] = ((leftIntraDir + offset) % mod) + 2;
          mpm[3] = ((leftIntraDir - 1) % mod) + 2;
          mpm[4] = ((leftIntraDir + offset - 1) % mod) + 2;
          mpm[5] = ( leftIntraDir               % mod) + 2;
        }
      }
      else //L!=A
      {
        numCand = 2;
        int  maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;

        if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX))
        {
          mpm[0] = PLANAR_IDX;
          mpm[1] = leftIntraDir;
          mpm[2] = aboveIntraDir;
          maxCandModeIdx = mpm[1] > mpm[2] ? 1 : 2;
          int minCandModeIdx = mpm[1] > mpm[2] ? 2 : 1;
          if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 1)
          {
            mpm[3] = ((mpm[minCandModeIdx] + offset)     % mod) + 2;
            mpm[4] = ((mpm[maxCandModeIdx] - 1)          % mod) + 2;
            mpm[5] = ((mpm[minCandModeIdx] + offset - 1) % mod) + 2;
          }
          else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] >= 62)
          {
            mpm[3] = ((mpm[minCandModeIdx] - 1)      % mod) + 2;
            mpm[4] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
            mpm[5] = ( mpm[minCandModeIdx]           % mod) + 2;
          }
          else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 2)
          {
            mpm[3] = ((mpm[minCandModeIdx] - 1)      % mod) + 2;
            mpm[4] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
            mpm[5] = ((mpm[maxCandModeIdx] - 1)      % mod) + 2;
          }
          else
          {
            mpm[3] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
            mpm[4] = ((mpm[minCandModeIdx] - 1)      % mod) + 2;
            mpm[5] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
          }
        }
        else if (leftIntraDir + aboveIntraDir >= 2)
        {
          mpm[0] = PLANAR_IDX;
          mpm[1] = (leftIntraDir < aboveIntraDir) ? aboveIntraDir : leftIntraDir;
          maxCandModeIdx = 1;
          mpm[2] = ((mpm[maxCandModeIdx] + offset)     % mod) + 2;
          mpm[3] = ((mpm[maxCandModeIdx] - 1)          % mod) + 2;
          mpm[4] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
          mpm[5] = ( mpm[maxCandModeIdx]               % mod) + 2;
        }
      }
    }
    for (int i = 0; i < numMPMs; i++)
    {
      CHECK(mpm[i] >= NUM_LUMA_MODE, "Invalid MPM");
    }
    CHECK(numCand == 0, "No candidates found");
    return numCand;
  }
}

getPURestricted関数は、主に場所に応じてPUを取得するためのものです

const PredictionUnit* CodingStructure::getPURestricted( const Position &pos, const PredictionUnit& curPu, const ChannelType _chType ) const
{
  const PredictionUnit* pu = getPU( pos, _chType );
  // exists       same slice and tile                  pu precedes curPu in encoding order
  //                                                  (thus, is either from parent CS in RD-search or its index is lower)
  //存在 相同slice和Tile    PU在编码顺序中先于当前PU
  //(因此,在RD搜索中是来自父CS的,或者其索引较低)
  const bool wavefrontsEnabled = curPu.cu->slice->getSPS()->getEntropyCodingSyncEnabledFlag();
  int ctuSizeBit = floorLog2(curPu.cs->sps->getMaxCUWidth());
  int xNbY  = pos.x << getChannelTypeScaleX( _chType, curPu.chromaFormat );//相邻PU的左上角位置x
  int xCurr = curPu.blocks[_chType].x << getChannelTypeScaleX( _chType, curPu.chromaFormat );//当前PU的左上角位置x
  //判断相邻PU和当前PU是否在同一CTU中
  bool addCheck = (wavefrontsEnabled && (xNbY >> ctuSizeBit) >= (xCurr >> ctuSizeBit) + 1 ) ? false : true;
  if( pu && CU::isSameSliceAndTile( *pu->cu, *curPu.cu ) && ( pu->cs != curPu.cs || pu->idx <= curPu.idx ) && addCheck )
  {
    return pu;
  }
  else
  {
    return nullptr;
  }
}

 

おすすめ

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