VTM3.0代码阅读:getTriangleMergeCandidates函数

getTriangleMergeCandidates函数在xCheckRDCostMergeTriangle2Nx2N函数中被调用,来构建三角预测的merge候选列表。
三角预测的单向列表构建:首先类似merge候选列表构建直到TMVP,再由candidate来构建三角预测的单向列表。

void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangleMrgCtx )
{
  const CodingStructure &cs  = *pu.cs;
  const Slice &slice         = *pu.cs->slice;
  const int32_t maxNumMergeCand = TRIANGLE_MAX_NUM_UNI_CANDS;	//三角预测候选列表长度为5
  triangleMrgCtx.numValidMergeCand = 0;

  for( int32_t i = 0; i < maxNumMergeCand; i++ )
  {
    triangleMrgCtx.interDirNeighbours[i] = 0;			//merge列表初始化
    triangleMrgCtx.mrgTypeNeighbours [i] = MRG_TYPE_DEFAULT_N;
    triangleMrgCtx.mvFieldNeighbours[(i << 1)    ].refIdx = NOT_VALID;
    triangleMrgCtx.mvFieldNeighbours[(i << 1) + 1].refIdx = NOT_VALID;
    triangleMrgCtx.mvFieldNeighbours[(i << 1)    ].mv = Mv();
    triangleMrgCtx.mvFieldNeighbours[(i << 1) + 1].mv = Mv();
  }

  MotionInfo candidate[TRIANGLE_MAX_NUM_CANDS_MEM];		//7
  int32_t candCount = 0;

  const Position posLT = pu.Y().topLeft();
  const Position posRT = pu.Y().topRight();
  const Position posLB = pu.Y().bottomLeft();

  MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;

  //left				//这里都和merge模式构建候选列表一样,直到TMVP候选部分
  const PredictionUnit* puLeft = cs.getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType );
  const bool isAvailableA1 = puLeft && isDiffMER( pu, *puLeft ) && pu.cu != puLeft->cu && CU::isInter( *puLeft->cu )
#if JVET_L0293_CPR
    && !puLeft->cu->cpr
#endif
    ;
  if( isAvailableA1 )
  {
    miLeft = puLeft->getMotionInfo( posLB.offset(-1, 0) );
    candidate[candCount].isInter   = true;
    candidate[candCount].interDir  = miLeft.interDir;
    candidate[candCount].mv[0]     = miLeft.mv[0];
    candidate[candCount].mv[1]     = miLeft.mv[1];
    candidate[candCount].refIdx[0] = miLeft.refIdx[0];
    candidate[candCount].refIdx[1] = miLeft.refIdx[1];
    candCount++;
  }

  // above
  const PredictionUnit *puAbove = cs.getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType );
  bool isAvailableB1 = puAbove && isDiffMER( pu, *puAbove ) && pu.cu != puAbove->cu && CU::isInter( *puAbove->cu )
#if JVET_L0293_CPR
    && !puAbove->cu->cpr
#endif
    ;
  if( isAvailableB1 )
  {
    miAbove = puAbove->getMotionInfo( posRT.offset( 0, -1 ) );
    
    if( !isAvailableA1 || ( miAbove != miLeft ) )
    {
      candidate[candCount].isInter   = true;
      candidate[candCount].interDir  = miAbove.interDir;
      candidate[candCount].mv[0]     = miAbove.mv[0];
      candidate[candCount].mv[1]     = miAbove.mv[1];
      candidate[candCount].refIdx[0] = miAbove.refIdx[0];
      candidate[candCount].refIdx[1] = miAbove.refIdx[1];
      candCount++;
    }
  }
  
  // above right
  const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
  bool isAvailableB0 = puAboveRight && isDiffMER( pu, *puAboveRight ) && CU::isInter( *puAboveRight->cu )
#if JVET_L0293_CPR
    && !puAboveRight->cu->cpr
#endif
    ;

  if( isAvailableB0 )
  {
    miAboveRight = puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) );

    if( ( !isAvailableB1 || ( miAbove != miAboveRight ) ) && ( !isAvailableA1 || ( miLeft != miAboveRight ) ) )
    {
      candidate[candCount].isInter   = true;
      candidate[candCount].interDir  = miAboveRight.interDir;
      candidate[candCount].mv[0]     = miAboveRight.mv[0];
      candidate[candCount].mv[1]     = miAboveRight.mv[1];
      candidate[candCount].refIdx[0] = miAboveRight.refIdx[0];
      candidate[candCount].refIdx[1] = miAboveRight.refIdx[1];
      candCount++;
    }
  }  

  //left bottom
  const PredictionUnit *puLeftBottom = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
  bool isAvailableA0 = puLeftBottom && isDiffMER( pu, *puLeftBottom ) && CU::isInter( *puLeftBottom->cu )
#if JVET_L0293_CPR
    && !puLeftBottom->cu->cpr
#endif
    ;
  if( isAvailableA0 )
  {
    miBelowLeft = puLeftBottom->getMotionInfo( posLB.offset( -1, 1 ) );
    
    if( ( !isAvailableA1 || ( miBelowLeft != miLeft ) ) && ( !isAvailableB1 || ( miBelowLeft != miAbove ) ) && ( !isAvailableB0 || ( miBelowLeft != miAboveRight ) ) )
    {
      candidate[candCount].isInter   = true;
      candidate[candCount].interDir  = miBelowLeft.interDir;
      candidate[candCount].mv[0]     = miBelowLeft.mv[0];
      candidate[candCount].mv[1]     = miBelowLeft.mv[1];
      candidate[candCount].refIdx[0] = miBelowLeft.refIdx[0];
      candidate[candCount].refIdx[1] = miBelowLeft.refIdx[1];
      candCount++;
    }
  }

  // above left
  const PredictionUnit *puAboveLeft = cs.getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
  bool isAvailableB2 = puAboveLeft && isDiffMER( pu, *puAboveLeft ) && CU::isInter( *puAboveLeft->cu )
#if JVET_L0293_CPR
    && !puAboveLeft->cu->cpr
#endif
    ;

  if( isAvailableB2 )
  {
    miAboveLeft = puAboveLeft->getMotionInfo( posLT.offset( -1, -1 ) );

    if( ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ) && ( !isAvailableA0 || ( miBelowLeft != miAboveLeft ) ) && ( !isAvailableB0 || ( miAboveRight != miAboveLeft ) ) )
    {
      candidate[candCount].isInter   = true;
      candidate[candCount].interDir  = miAboveLeft.interDir;
      candidate[candCount].mv[0]     = miAboveLeft.mv[0];
      candidate[candCount].mv[1]     = miAboveLeft.mv[1];
      candidate[candCount].refIdx[0] = miAboveLeft.refIdx[0];
      candidate[candCount].refIdx[1] = miAboveLeft.refIdx[1];
      candCount++;
    }
  }
  
  if( slice.getEnableTMVPFlag() )			//tmvp
  {
    Position posRB = pu.Y().bottomRight().offset(-3, -3);

    const PreCalcValues& pcv = *cs.pcv;

    Position posC0;
    Position posC1 = pu.Y().center();
    bool isAvailableC0 = false;

    if (((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight))
    {
      Position posInCtu( posRB.x & pcv.maxCUWidthMask, posRB.y & pcv.maxCUHeightMask );

      if( ( posInCtu.x + 4 < pcv.maxCUWidth ) &&           // is not at the last column of CTU
          ( posInCtu.y + 4 < pcv.maxCUHeight ) )           // is not at the last row    of CTU
      {
        posC0 = posRB.offset( 4, 4 );
        isAvailableC0 = true;
      }
      else if( posInCtu.x + 4 < pcv.maxCUWidth )           // is not at the last column of CTU But is last row of CTU
      {
        posC0 = posRB.offset( 4, 4 );
        // in the reference the CTU address is not set - thus probably resulting in no using this C0 possibility
      }
      else if( posInCtu.y + 4 < pcv.maxCUHeight )          // is not at the last row of CTU But is last column of CTU
      {
        posC0 = posRB.offset( 4, 4 );
        isAvailableC0 = true;
      }
      else //is the right bottom corner of CTU
      {
        posC0 = posRB.offset( 4, 4 );
        // same as for last column but not last row
      }
    }

    // C0						//TMVP在C0和C1两个点的motioninfo
    Mv        cColMv;
    int32_t   refIdx     = 0;
    bool      existMV    = ( isAvailableC0 && getColocatedMVP( pu, REF_PIC_LIST_0, posC0, cColMv, refIdx ) );
    MotionInfo temporalMv;
    temporalMv.interDir  = 0;
    if( existMV )
    {
      temporalMv.isInter   = true;
      temporalMv.interDir |= 1;
      temporalMv.mv[0]     = cColMv;
      temporalMv.refIdx[0] = refIdx;
    }
    existMV = ( isAvailableC0 && getColocatedMVP( pu, REF_PIC_LIST_1, posC0, cColMv, refIdx ) );
    if( existMV )
    {
      temporalMv.interDir |= 2;
      temporalMv.mv[1]     = cColMv;
      temporalMv.refIdx[1] = refIdx;
    }

    if( temporalMv.interDir != 0 )
    {
      candidate[candCount].isInter   = true;
      candidate[candCount].interDir  = temporalMv.interDir;
      candidate[candCount].mv[0]     = temporalMv.mv[0];
      candidate[candCount].mv[1]     = temporalMv.mv[1];
      candidate[candCount].refIdx[0] = temporalMv.refIdx[0];
      candidate[candCount].refIdx[1] = temporalMv.refIdx[1];
      candCount++;
    }
   
    // C1
    temporalMv.interDir = 0;
    existMV    = getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv, refIdx );
    if( existMV )
    {
      temporalMv.isInter   = true;
      temporalMv.interDir |= 1;
      temporalMv.mv[0]     = cColMv;
      temporalMv.refIdx[0] = refIdx;
    }
    existMV    = getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv, refIdx );
    if( existMV )
    {
      temporalMv.interDir |= 2;
      temporalMv.mv[1]     = cColMv;
      temporalMv.refIdx[1] = refIdx;
    }

    if( temporalMv.interDir != 0 )
    {
      candidate[candCount].isInter   = true;
      candidate[candCount].interDir  = temporalMv.interDir;
      candidate[candCount].mv[0]     = temporalMv.mv[0];
      candidate[candCount].mv[1]     = temporalMv.mv[1];
      candidate[candCount].refIdx[0] = temporalMv.refIdx[0];
      candidate[candCount].refIdx[1] = temporalMv.refIdx[1];
      candCount++;
    }
  }
  //以上类似在构建merge候选列表,信息存储在candidate中。以下开始构建三角预测的单向列表
  // put uni-prediction candidate to the triangle candidate list
  for( int32_t i = 0; i < candCount; i++ )
  { 
    if( candidate[i].interDir != 3 )	//首先添加candidate中的单向mv
    {
      triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = candidate[i].interDir;
      triangleMrgCtx.mrgTypeNeighbours [triangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1)    ].mv = candidate[i].mv[0];
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].mv = candidate[i].mv[1];
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1)    ].refIdx = candidate[i].refIdx[0];
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = candidate[i].refIdx[1];
      triangleMrgCtx.numValidMergeCand += isUniqueTriangleCandidates(pu, triangleMrgCtx);
      if( triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS )
      {
        return;			//满5个直接return
      }	
    }
  }

  // put L0 mv of bi-prediction candidate to the triangle candidate list
  for( int32_t i = 0; i < candCount; i++ )
  {
    if( candidate[i].interDir == 3 )	//添加candidate中的双向mv的L0分量
    {
      triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 1;
      triangleMrgCtx.mrgTypeNeighbours [triangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1)    ].mv = candidate[i].mv[0];
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].mv = Mv(0, 0);
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1)    ].refIdx = candidate[i].refIdx[0];
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = -1;
      triangleMrgCtx.numValidMergeCand += isUniqueTriangleCandidates(pu, triangleMrgCtx);
      if( triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS )
      {
        return;			//满5个直接return
      }
    }
  }

  // put L1 mv of bi-prediction candidate to the triangle candidate list
  for( int32_t i = 0; i < candCount; i++ )
  {
    if( candidate[i].interDir == 3 )	//添加candidate中的双向mv的L1分量
    {
      triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 2;
      triangleMrgCtx.mrgTypeNeighbours [triangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1)    ].mv = Mv(0, 0);
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].mv = candidate[i].mv[1];
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1)    ].refIdx = -1;
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = candidate[i].refIdx[1];
      triangleMrgCtx.numValidMergeCand += isUniqueTriangleCandidates(pu, triangleMrgCtx);
      if( triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS )
      {
        return;			//满5个直接return
      }
    }
  }

  // put average of L0 and L1 mvs of bi-prediction candidate to the triangle candidate list
  for( int32_t i = 0; i < candCount; i++ )	//添加candidate中的双向mv的平均值,平均后方向为前向
  {
    if( candidate[i].interDir == 3 )
    {
      int32_t curPicPoc   = slice.getPOC();
      int32_t refPicPocL0 = slice.getRefPOC(REF_PIC_LIST_0, candidate[i].refIdx[0]);
      int32_t refPicPocL1 = slice.getRefPOC(REF_PIC_LIST_1, candidate[i].refIdx[1]);
      Mv aveMv = candidate[i].mv[1];				//将L1的mv scale到L0
      aveMv = aveMv.scaleMv( xGetDistScaleFactor( curPicPoc, refPicPocL0, curPicPoc, refPicPocL1 ) ); // scaling to L0
      aveMv.setHor( ( aveMv.getHor() + candidate[i].mv[0].getHor() + 1 ) >> 1 );
      aveMv.setVer( ( aveMv.getVer() + candidate[i].mv[0].getVer() + 1 ) >> 1 );	//取平均
      
      triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 1;
      triangleMrgCtx.mrgTypeNeighbours [triangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N;
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1)    ].mv = aveMv;
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].mv = Mv(0, 0);
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1)    ].refIdx = candidate[i].refIdx[0];
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = -1;
      triangleMrgCtx.numValidMergeCand += isUniqueTriangleCandidates(pu, triangleMrgCtx);
      if( triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS )
      {
        return;			//满5个直接return
      }
    }
  } 
    
  // fill with Mv(0, 0)				//补0
  int32_t numRefIdx = std::min( slice.getNumRefIdx(REF_PIC_LIST_0), slice.getNumRefIdx(REF_PIC_LIST_1) );
  int32_t cnt = 0;
  while( triangleMrgCtx.numValidMergeCand < TRIANGLE_MAX_NUM_UNI_CANDS )
  {
    if( cnt < numRefIdx )
    {
      triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 1;
      triangleMrgCtx.mvFieldNeighbours[triangleMrgCtx.numValidMergeCand << 1].setMvField(Mv(0, 0), cnt);
      triangleMrgCtx.numValidMergeCand++;
      
      if( triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS )
      {
        return;
      }
      
      triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 2;
      triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1 ].setMvField(Mv(0, 0), cnt);
      triangleMrgCtx.numValidMergeCand++;
      
      cnt = (cnt + 1) % numRefIdx;
    }
  }  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值