自从入了ORB_SLAM的坑以来,深感,在室外使用VO导航的艰辛,ORB_SLAM代码前后看了有一个月了,现在逐渐把一些函数的代码注释记录在这里,希望能给后面入坑的同志们些借鉴吧,当然自己也还有很多不明白的地方,所以,如果注释有错的,还请指出。
代码块
/**
* 函数功能:从关键帧库中找出与当前帧匹配得最好的候选关键帧序列
* 函数输入:当前帧
* 函数输出:关键帧库中与当前帧匹配较好的候选关键帧序列
* 几个变量含义:(1)mBowVec:BoW向量,里面存储的是从BoW词袋中查询到的“单词”
* (2)mvInvertedFile:是一个向量,里面存放的是一个个单词,每个单词对应一个list链表,每个链表里存放的是拥有该单词的关键帧
* 即,每一个单词都对应着所有看到该单词的关键帧
* (3)pKFi->mnRelocWords:该关键帧与当前帧所共有的单词数
* */
vector<KeyFrame*> KeyFrameDatabase::DetectRelocalizationCandidates(Frame *F)
{
list<KeyFrame*> lKFsSharingWords;//与当前帧具有公共单词的所有关键帧
{
///遍历该帧看到的所有单词
unique_lock<mutex> lock(mMutex);
for(DBoW2::BowVector::const_iterator vit=F->mBowVec.begin(), vend=F->mBowVec.end(); vit != vend; vit++)
{
list<KeyFrame*> &lKFs = mvInvertedFile[vit->first];//找到这个单词所对应的所有关键帧
///遍历该单词的所有关键帧,并打上标签即:pKFi->mnRelocQuery=F->mnId,为了防止lKFsSharingWords中重复添加
for(list<KeyFrame*>::iterator lit=lKFs.begin(), lend= lKFs.end(); lit!=lend; lit++)
{
KeyFrame* pKFi=*lit;
if(pKFi->mnRelocQuery!=F->mnId)//为了不对同一个关键帧重复检测,这里打一个标签
{
pKFi->mnRelocWords=0;
pKFi->mnRelocQuery=F->mnId;
lKFsSharingWords.push_back(pKFi);
}
pKFi->mnRelocWords++;//如果当前帧与该帧每共有一个单词,则加一
}
}
}
///如果关键帧库里所有的关键帧与当前帧都没有公共单词,则返回空
if(lKFsSharingWords.empty())
return vector<KeyFrame*>();
int maxCommonWords=0;//最大共有单词数量
///遍历所有与当前帧具有公共单词的关键帧,并找与当前帧具有的最大公共单词数
for(list<KeyFrame*>::iterator lit=lKFsSharingWords.begin(), lend= lKFsSharingWords.end(); lit!=lend; lit++)
{
if((*lit)->mnRelocWords>maxCommonWords)
maxCommonWords=(*lit)->mnRelocWords;
}
int minCommonWords = maxCommonWords*0.8f;//最小共有单词数取最大共有单词数的0.8倍
list<pair<float,KeyFrame*> > lScoreAndMatch;
int nscores=0;
///找出共有单词数在minCommonWords与maxCommonWords之间的关键帧,作为“得分较高的关键帧”,
/// 并且计算当前帧与该关键帧的得分,将得分与该关键帧组成pair存到lScoreAndMatch中
for(list<KeyFrame*>::iterator lit=lKFsSharingWords.begin(), lend= lKFsSharingWords.end(); lit!=lend; lit++)
{
KeyFrame* pKFi = *lit;
if(pKFi->mnRelocWords>minCommonWords)
{
nscores++;
float si = mpVoc->score(F->mBowVec,pKFi->mBowVec);//比较两个vector向量的得分
pKFi->mRelocScore=si;
lScoreAndMatch.push_back(make_pair(si,pKFi));
}
}
///这一个应该是不会发生的,因为至少有一个关键帧与当前帧的共有单词数符合上边的阈值范围,就是共有单词数最多的那个关键帧
if(lScoreAndMatch.empty())
return vector<KeyFrame*>();
list<pair<float,KeyFrame*> > lAccScoreAndMatch;
float bestAccScore = 0;
///遍历得分较高的关键帧所对应的10个最佳共视关键帧,这样lScoreAndMatch序列中“被共视”的越多的关键帧将越有可能被选为候选关键帧
/// 注:这一块看的不是特别明白,如有错误请指出,谢谢
for(list<pair<float,KeyFrame*> >::iterator it=lScoreAndMatch.begin(), itend=lScoreAndMatch.end(); it!=itend; it++)
{
KeyFrame* pKFi = it->second;
vector<KeyFrame*> vpNeighs = pKFi->GetBestCovisibilityKeyFrames(10);//获取10个最佳共视关键帧
float bestScore = it->first;
float accScore = bestScore;
KeyFrame* pBestKF = pKFi;
///遍历该帧对应的共视关键帧
for(vector<KeyFrame*>::iterator vit=vpNeighs.begin(), vend=vpNeighs.end(); vit!=vend; vit++)
{
KeyFrame* pKF2 = *vit;
if(pKF2==NULL)//add by yuxi
continue;
if(pKF2->mnRelocQuery!=F->mnId)//如果该帧不在lKFsSharingWords中,则无须再处理
continue;
accScore+=pKF2->mRelocScore;//将pKFi的得分与它的共视关键帧得分累加
if(pKF2->mRelocScore>bestScore)//如果共视关键帧的得分超过pKFi,则将pKFi替换掉
{
pBestKF=pKF2;
bestScore = pKF2->mRelocScore;
}
}
lAccScoreAndMatch.push_back(make_pair(accScore,pBestKF));
if(accScore>bestAccScore)
bestAccScore=accScore;
}
///将lAccScoreAndMatch accScore中满足阈值的得分作为候选关键帧,返回
float minScoreToRetain = 0.75f*bestAccScore;
set<KeyFrame*> spAlreadyAddedKF;
vector<KeyFrame*> vpRelocCandidates;
vpRelocCandidates.reserve(lAccScoreAndMatch.size());
for(list<pair<float,KeyFrame*> >::iterator it=lAccScoreAndMatch.begin(), itend=lAccScoreAndMatch.end(); it!=itend; it++)
{
const float &si = it->first;
if(si>minScoreToRetain)
{
KeyFrame* pKFi = it->second;
if(!spAlreadyAddedKF.count(pKFi))
{
vpRelocCandidates.push_back(pKFi);
spAlreadyAddedKF.insert(pKFi);
}
}
}
return vpRelocCandidates;
}