class KeyFrameDatabase
{
public:
KeyFrameDatabase(const ORBVocabulary &voc);
void add(KeyFrame* pKF);
void erase(KeyFrame* pKF);
void clear();
// Loop Detection
//在KeyFrameDatabase,以及与pKF在covisibility graph连接的keyframe中找出与pKF可能形成闭环的候选帧
//与DetectRelocalizationCandidates的区别是,在最开始先搜索了在covisibility graph与其连接的关键帧
std::vector<KeyFrame *> DetectLoopCandidates(KeyFrame* pKF, float minScore);
// Relocalization
//在重定位时情形下,KeyFrameDatabase找出与当前帧相似F的候选关键帧,并返回
std::vector<KeyFrame*> DetectRelocalizationCandidates(Frame* F);
protected:
// Associated vocabulary
const ORBVocabulary* mpVoc;
// Inverted file
//< 倒排索引,mvInvertedFile[i]表示包含了第i个word id的所有关键帧
std::vector<list<KeyFrame*> > mvInvertedFile;
// Mutex
std::mutex mMutex;
};
此方法返回与当前帧相似F的候选关键帧。
1.搜索所有和和F有着相同单词的keyframe存储在lKFsSharingWords;
2.从lKFsSharingWords中筛选出,相同单词数量较多的keyframe,计算通过dbow计算相似度得分存入lScoreAndMatch;
3.lScoreAndMatch中的keyframe,考虑其共视关系最高的keyframe然后再进行一次筛选得到AccScoreAndMatch;
4.第四次筛选得到lAccScoreAndMatch中所有得分超过0.75*bestAccScore的keyframe集合
vector<KeyFrame*> KeyFrameDatabase::DetectRelocalizationCandidates(Frame *F)
{
//lKFsSharingWords存储着和F有着相同单词的keyframe
list<KeyFrame*> lKFsSharingWords;
// Search all keyframes that share a word with current frame
//搜索所有和和F有着相同单词的keyframe存储在lKFsSharingWords
//并且更新keyframe中mnRelocWords,表示和此F有多少共同的单词
{
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];
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*>();
// Only compare against those keyframes that share enough words
//在lKFsSharingWords中,寻找mnRelocWords的最大值存入maxCommonWords
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;
list<pair<float,KeyFrame*> > lScoreAndMatch;
int nscores=0;
// Compute similarity score.
//遍历lKFsSharingWords中的keyframe,当其中的keyframe的mRelocScore大于阈值minCommonWords则计算相似度后放入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);
pKFi->mRelocScore=si;
lScoreAndMatch.push_back(make_pair(si,pKFi));
}
}
if(lScoreAndMatch.empty())
return vector<KeyFrame*>();
list<pair<float,KeyFrame*> > lAccScoreAndMatch;
float bestAccScore = 0;
// Lets now accumulate score by covisibility
//遍历lScoreAndMatch中的keyframe,找出其共视图中与此keyframe连接的权值前N的节点,加上原keyframe总共11个keyframe
//累加这11个keyframe的相似度得分,然后在11个keyframe中选择相似度得分最高的那个放入lAccScoreAndMatch中
//在遍历过程中计算bestAccScore,也就是AccScore的最大值,后面的再次筛选有用
for(list<pair<float,KeyFrame*> >::iterator it=lScoreAndMatch.begin(), itend=lScoreAndMatch.end(); it!=itend; it++)
{
KeyFrame* pKFi = it->second;
//返回共视图中与此keyframe连接的权值前10的节点keyframe
vector<KeyFrame*> vpNeighs = pKFi->GetBestCovisibilityKeyFrames(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;
//说明pKF2与F没有共同的单词,就放弃此循环的关键帧
if(pKF2->mnRelocQuery!=F->mnId)
continue;
accScore+=pKF2->mRelocScore;
if(pKF2->mRelocScore>bestScore)
{
pBestKF=pKF2;
bestScore = pKF2->mRelocScore;
}
}
lAccScoreAndMatch.push_back(make_pair(accScore,pBestKF));
if(accScore>bestAccScore)
bestAccScore=accScore;
}
// Return all those keyframes with a score higher than 0.75*bestAccScore
//返回lAccScoreAndMatch中所有得分超过0.75*bestAccScore的keyframe集合
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;
}
//在KeyFrameDatabase,以及与pKF在covisibility graph连接的keyframe中找出与pKF可能形成闭环的候选帧
//与DetectRelocalizationCandidates的区别是,在最开始先搜索了在covisibility graph与其连接的关键帧
vector<KeyFrame*> KeyFrameDatabase::DetectLoopCandidates(KeyFrame* pKF, float minScore)
{
//返回此关键帧在Covisibility graph中与之相连接(有共视关系)的节点
set<KeyFrame*> spConnectedKeyFrames = pKF->GetConnectedKeyFrames();
//和pKF有相同单词且具有共视关系的关键帧将会放在lKFsSharingWords
list<KeyFrame*> lKFsSharingWords;
// Search all keyframes that share a word with current keyframes
// Discard keyframes connected to the query keyframe
//找出与pKF有相同单词的关键帧
{
unique_lock<mutex> lock(mMutex);
//遍历pKF中Bow里的每个单词
for(DBoW2::BowVector::const_iterator vit=pKF->mBowVec.begin(), vend=pKF->mBowVec.end(); vit != vend; vit++)
{
//通过单词id得到与之相有相同单词的关键帧
list<KeyFrame*> &lKFs = mvInvertedFile[vit->first];
//判断lKFs中关键帧是否复合要求
for(list<KeyFrame*>::iterator lit=lKFs.begin(), lend= lKFs.end(); lit!=lend; lit++)
{
KeyFrame* pKFi=*lit;
//如果pKFi被标记访问过
if(pKFi->mnLoopQuery!=pKF->mnId)
{
pKFi->mnLoopWords=0;
//如果pKFi和pKF有共视关系
if(!spConnectedKeyFrames.count(pKFi))
{
pKFi->mnLoopQuery=pKF->mnId;
lKFsSharingWords.push_back(pKFi);
}
}
//单词投票
pKFi->mnLoopWords++;
}
}
}
if(lKFsSharingWords.empty())
return vector<KeyFrame*>();
list<pair<float,KeyFrame*> > lScoreAndMatch;
// Only compare against those keyframes that share enough words
//在lKFsSharingWords找出nLoopWords的最大值,也就是单词投票最多的哪个关键帧
int maxCommonWords=0;
for(list<KeyFrame*>::iterator lit=lKFsSharingWords.begin(), lend= lKFsSharingWords.end(); lit!=lend; lit++)
{
if((*lit)->mnLoopWords>maxCommonWords)
maxCommonWords=(*lit)->mnLoopWords;
}
int minCommonWords = maxCommonWords*0.8f;
int nscores=0;
// Compute similarity score. Retain the matches whose score is higher than minScore
//遍历lKFsSharingWords中的keyframe,当其中的keyframe的mLoopScore大于阈值minScore则计算相似度后放入lScoreAndMatch中
for(list<KeyFrame*>::iterator lit=lKFsSharingWords.begin(), lend= lKFsSharingWords.end(); lit!=lend; lit++)
{
KeyFrame* pKFi = *lit;
if(pKFi->mnLoopWords>minCommonWords)
{
nscores++;
float si = mpVoc->score(pKF->mBowVec,pKFi->mBowVec);
pKFi->mLoopScore = si;
if(si>=minScore)
lScoreAndMatch.push_back(make_pair(si,pKFi));
}
}
if(lScoreAndMatch.empty())
return vector<KeyFrame*>();
list<pair<float,KeyFrame*> > lAccScoreAndMatch;
float bestAccScore = minScore;
// Lets now accumulate score by covisibility
//遍历lScoreAndMatch中的keyframe,找出其共视图中与此keyframe连接的权值前N的节点,加上原keyframe总共最多有11个keyframe
//累加这11个keyframe的相似度得分,然后在11个keyframe中选择相似度得分最高的那个放入lAccScoreAndMatch中
//在遍历过程中计算bestAccScore,也就是AccScore的最大值,后面的再次筛选有用
for(list<pair<float,KeyFrame*> >::iterator it=lScoreAndMatch.begin(), itend=lScoreAndMatch.end(); it!=itend; it++)
{
KeyFrame* pKFi = it->second;
//返回共视图中与此keyframe连接的权值前10的节点keyframe
vector<KeyFrame*> vpNeighs = pKFi->GetBestCovisibilityKeyFrames(10);
float bestScore = it->first;
float accScore = it->first;
KeyFrame* pBestKF = pKFi;
for(vector<KeyFrame*>::iterator vit=vpNeighs.begin(), vend=vpNeighs.end(); vit!=vend; vit++)
{
KeyFrame* pKF2 = *vit;
//如果pKF2与pKF有相同的单词,且在essentialgraph中连接,
//且pKF2的mLoopScore大于阈值minScore则将其相似度的值累加至accScore
if(pKF2->mnLoopQuery==pKF->mnId && pKF2->mnLoopWords>minCommonWords)
{
accScore+=pKF2->mLoopScore;
if(pKF2->mLoopScore>bestScore)
{
pBestKF=pKF2;
bestScore = pKF2->mLoopScore;
}
}
}
lAccScoreAndMatch.push_back(make_pair(accScore,pBestKF));
if(accScore>bestAccScore)
bestAccScore=accScore;
}
// Return all those keyframes with a score higher than 0.75*bestScore
float minScoreToRetain = 0.75f*bestAccScore;
set<KeyFrame*> spAlreadyAddedKF;
vector<KeyFrame*> vpLoopCandidates;
vpLoopCandidates.reserve(lAccScoreAndMatch.size());
//返回lAccScoreAndMatch中所有得分超过0.75*bestAccScore的keyframe集合
for(list<pair<float,KeyFrame*> >::iterator it=lAccScoreAndMatch.begin(), itend=lAccScoreAndMatch.end(); it!=itend; it++)
{
if(it->first>minScoreToRetain)
{
KeyFrame* pKFi = it->second;
if(!spAlreadyAddedKF.count(pKFi))
{
vpLoopCandidates.push_back(pKFi);
spAlreadyAddedKF.insert(pKFi);
}
}
}
return vpLoopCandidates;
}