Aprendizaje de código H.266 / VVC: establecimiento de lista MPM (función getIntraMPMs)

VVC tiene 67 modos de ángulo. Si el modo de predicción de cada PU se codifica por separado, se requieren 7 bits para codificar los 67 modos. Por lo tanto, el método de construir la lista de modo más probable (MPM) también se usa en VVC. En la codificación de imágenes y video, los bloques vecinos suelen tener una fuerte correlación, por lo que los modos de predicción intra de los bloques vecinos tienen una mayor probabilidad de ser iguales o similares. Por lo tanto, la lista de MPM se basa en los fotogramas de la PU vecina izquierda y la superior PU vecina En VVC, la longitud de la lista MPM es 6. En la codificación intracuadro, la lista MPM se encuentra principalmente en los dos procesos siguientes

  1. Realice una selección aproximada de SATD en modo de línea de referencia múltiple (mrl_idx = 1, 2) y solo use los 6 modos de predicción intra en la lista de MPM
  2. Una vez finalizada la selección aproximada del modo MIP, verifique si el modo de predicción en la lista MPM está en la lista de candidatos de distorsión de velocidad

Los pasos de construcción específicos son los siguientes:

1. Obtenga los píxeles de referencia adyacentes inferior izquierdo y superior derecho, indicados como A y B respectivamente, como se muestra en la figura siguiente

Inserte la descripción de la imagen aquí

2. Obtener el modo de intra predicción de la PU donde se encuentran los píxeles adyacentes A y B, y el método de obtención es el siguiente:

  • Si se cumple una de las siguientes condiciones, el modo de predicción interna de la PU adyacente se establece en modo Planar 
    • Su PU adyacente no está disponible
    • El modo de codificación de la PU adyacente no es el modo de codificación interna
    • La PU adyacente es el modo MIP
    • La PU adyacente y la PU actual no están en la misma CTU
  • De lo contrario, obtenga el modo de predicción intra de su PU vecina

3. Marque los modos de predicción de las PU donde los píxeles adyacentes A y B se ubican como A y B respectivamente, y la lista de MPM se construye de la siguiente manera:

(1) A = B 且 A> B

MPM [0] Planar
MPM [1]

UN

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] Planar
MPM [1]

UN

MPM [2] segundo

  ①Si maxAB-minAB = 1, entonces

MPM [3]

2 + ((minAB + 61)% 64)

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

  ②Si maxAB-minAB> = 62, entonces

MPM [3]

2 + ((minAB - 1)% 64)

MPM [4] 2 + ((maxAB + 61)% 64)
MPM [5] 2 + (mínimo AB% 64)

 

   ③Si maxAB-minAB = 2, entonces

MPM [3]

2 + ((minAB - 1)% 64)

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

  ④ De lo contrario

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] Planar
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) De lo contrario,

MPM [0] Planar
MPM [1]

corriente continua

MPM [2] VER
MPM [3] HOR
MPM [4] VER-4
MPM [5] VER+4

La implementación del código específico y los comentarios son los siguientes:

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 función getPURestricted es principalmente para obtener PU según la ubicación

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

 

Supongo que te gusta

Origin blog.csdn.net/BigDream123/article/details/106598707
Recomendado
Clasificación