• ORB-SLAM(五)KeyFrame类-最小生成树


    KeyFrame中维护了一个map,保存了与当前帧共视的KeyFrame*与权重(共视MapPonits数量)。对关键帧之间关系是用加权有向图来完成的,那么理解其spanning tree生成树的原理就很有必要了。

    KeyFrame中比较难理解的是SetBagFlag()函数,真实删除当前关键帧之前,需要处理好父亲和儿子关键帧关系,不然会造成整个关键帧维护的图断裂,或者混乱,不能够为后端提供较好的初值。

    理解起来就是父亲挂了,儿子需要找新的父亲,在候选父亲里找,当前帧的父亲(mpParent)肯定在候选父亲中的;

    1. 首先将当前帧的父亲,放入候选父亲中

    sParentCandidates.insert(mpParent);

    2. 遍历当前帧的所有儿子,然后遍历儿子A的每个共视帧,如果其中有候选父亲,则将A的父亲更新为该候选父亲,并且将A放入候选父亲中(因为这时候A已经将整个图联系起来了);如果没有,break。如果遍历一圈下来,发现有的儿子还没有找到新父亲,例如儿子B的共视帧不是候选父亲里的任何一个。这种情况出现在,B和当前帧的父亲不存在共视关系(速度太快,旋转太急,匹配跟丢)。并且B与当前帧的儿子之间也没有共视关系:当前帧不是一个好的关键帧,本来就没有多少儿子;或者B本身是个例外,恩,反正B是个孤家寡人。。。那么直接将B的父亲设置为当前帧的父亲,交给爷爷去管。

    while(!mspChildrens.empty())
    {
      bool bContinue = false;
    
      int max = -1;
      KeyFrame* pC;
      KeyFrame* pP;
    
      for(set<KeyFrame*>::iterator sit=mspChildrens.begin(), send=mspChildrens.end(); sit!=send; sit++)
      {
        KeyFrame* pKF = *sit;
        if(pKF->isBad())
          continue;
    
        // Check if a parent candidate is connected to the keyframe
        vector<KeyFrame*> vpConnected = pKF->GetVectorCovisibleKeyFrames();
        for(size_t i=0, iend=vpConnected.size(); i<iend; i++)
        {
          for(set<KeyFrame*>::iterator spcit=sParentCandidates.begin(), spcend=sParentCandidates.end(); spcit!=spcend; spcit++)
          {
          if(vpConnected[i]->mnId == (*spcit)->mnId)
          {
            int w = pKF->GetWeight(vpConnected[i]);
            if(w>max)
            {
              pC = pKF;
              pP = vpConnected[i];
              max = w;
              bContinue = true;
            }
          }
          }
        }
      }
    }
    
    if(bContinue)
    {
      pC->ChangeParent(pP);
      sParentCandidates.insert(pC);
      mspChildrens.erase(pC);
    }
    else
      break;
    }
    
    if(!mspChildrens.empty())
      for(set<KeyFrame*>::iterator sit=mspChildrens.begin(); sit!=mspChildrens.end(); sit++)
      {
        (*sit)->ChangeParent(mpParent);
      }

     3. 具体删除一个关键帧的步骤是这样的:

      1) 初始mbNotErase状态是true,那么调用SetBadFlag后,将mbToBeErased状态置为true,然后return,并没有执行SetBadFlag()中后面的代码。

      2) 然后调用SetErase(),这时首先要检查mspLoopEdges是否是空的!因为如果当前帧维护了一个回环,删了该关键帧回环就没了。。。通常情况下是空的,那么把mbNotErase置为false,此时再在SetErase()中调用SetBagFlag时,就会真正去执行删除该帧的代码了。

    总结一下就是,首先设置为坏帧,如果该帧不是回环帧,则可以真的删掉;如果该帧是回环帧,怎么都删不掉的。。。

  • 相关阅读:
    BZOJ3997:[TJOI2015]组合数学(DP,Dilworth定理)
    BZOJ4807:車(组合数学,高精度)
    BZOJ4008:[HNOI2015]亚瑟王(DP,概率期望)
    BZOJ1499:[NOI2005]瑰丽华尔兹(DP,单调队列)
    洛谷1514 引水入城
    洛谷 1018 乘积最大
    八数码难题
    CODEVS 1069关押罪犯
    CODEVS 1067 机器翻译
    洛谷 P1417 烹调方案
  • 原文地址:https://www.cnblogs.com/shang-slam/p/6410788.html
Copyright © 2020-2023  润新知