Apprentissage du code H.266 / VVC: établissement de la liste MPM (fonction getIntraMPMs)

Le VVC a 67 modes d'angle. Si le mode de prédiction de chaque PU est codé séparément, 7 bits sont nécessaires pour coder les 67 modes. Dans le codage d'image et de vidéo, les blocs voisins ont généralement une forte corrélation, de sorte que les modes de prédiction intra des blocs voisins ont une probabilité plus élevée d'être identiques ou similaires. Par conséquent, la liste MPM est basée sur les images de la PU voisine gauche et de la PU voisine Dans VVC, la longueur de la liste MPM est de 6. Dans le codage intra-trame, la liste MPM est principalement dans les deux processus suivants

  1. Effectuer une sélection approximative SATD en mode ligne multi-référence (mrl_idx = 1, 2), et n'utiliser que les 6 modes de prédiction intra dans la liste MPM
  2. Une fois la sélection approximative du mode MIP terminée, vérifiez si le mode de prédiction dans la liste MPM se trouve dans la liste candidate de distorsion de débit

Les étapes de construction spécifiques sont les suivantes:

1. Obtenez les pixels de référence adjacents en bas à gauche et en haut à droite, désignés respectivement par A et B, comme illustré dans la figure ci-dessous.

Insérez la description de l'image ici

2. Obtenez le mode de prédiction intra du PU où se trouvent les pixels adjacents A et B, et la méthode d'obtention est la suivante:

  • Si l'une des conditions suivantes est vraie, le mode de prédiction intra de l'unité centrale adjacente est défini sur le mode planaire 
    • Son PU adjacent n'est pas disponible
    • Le mode de codage de la PU adjacente n'est pas le mode de codage intra
    • Le PU adjacent est le mode MIP
    • La PU adjacente et la PU actuelle ne sont pas dans la même CTU
  • Sinon, récupérez le mode de prédiction intra de son PU voisin

3. Marquez les modes de prédiction des PU où les pixels adjacents A et B sont situés respectivement comme A et B, et la liste MPM est construite comme suit:

(1) A = B 且 A> B

MPM [0] Planaire
MPM [1]

UNE

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> DC 且 B> DC

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

MPM [0] Planaire
MPM [1]

UNE

MPM [2] B

  ①Si maxAB-minAB = 1, alors

MPM [3]

2 + ((minAB + 61)% 64)

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

  ②Si maxAB-minAB> = 62, alors

MPM [3]

2 + ((minAB - 1)% 64)

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

 

   ③Si maxAB-minAB = 2, alors

MPM [3]

2 + ((minAB - 1)% 64)

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

  ④ Sinon

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] Planaire
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) Sinon,

MPM [0] Planaire
MPM [1]

DC

MPM [2] REGARDER
MPM [3] HOR
MPM [4] VOIR-4
MPM [5] VOIR + 4

L'implémentation du code spécifique et les commentaires sont les suivants:

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;
  }
}

La fonction getPURestricted consiste principalement à obtenir des PU en fonction de l'emplacement

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;
  }
}

 

Je suppose que tu aimes

Origine blog.csdn.net/BigDream123/article/details/106598707
conseillé
Classement