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时,就会真正去执行删除该帧的代码了。

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

原文地址:https://www.cnblogs.com/shang-slam/p/6410788.html