ORB-SLAM2 从理论到代码实现(十五):KeyFrameDatabase 类
1. 该类是关键帧的数据库构建关键帧数据库可以联系链表等常用数据结构的构建过程创建、增加元素、删除元素、清理。首先需要明确数据存储的数据类型以关键帧作为数据库的元素。这个地方需要理解两个概念单词词袋和关键帧。单词词袋预先构建好的离线词典 (ORBvoc.txt)它是DBoW2作者使用orb特征使用大量图片训练的结果。1.1. 成员变量std::vectorlistKeyFrame* mvInvertedFile;vector的索引是预先训练好的特征词汇词汇的值就是0到n所以可以当作索引来使用。vector对应的索引处存放包含该词汇的所有关键帧。1.2. 成员函数函数用途KeyFrameDatabase(const ORBVocabulary voc);构造函数void add(KeyFrame* pKF);根据关键帧的词汇把关键帧添加到数据库void erase(KeyFrame* pKF);从数据库中删除相应的关键帧void clear();清空关键帧数据库函数用途std::vectorKeyFrame DetectLoopCandidates(KeyFramepKF, float minScore);在闭环检测中找到与该关键帧可能闭环的关键帧std::vectorKeyFrame* DetectRelocalizationCandidates(Frame* F);在重定位中找到与该帧相似的关键帧2. DetectLoopCandidates// Loop Detection std::vectorKeyFrame * DetectLoopCandidates(KeyFrame* pKF, float minScore);这个函数的流程和DetectRelocalizationCandidates唯一的区别是忽略和自己已有共视关系的关键帧所以我们此处不复制全部的代码了只重点强调不同的地方for(DBoW2::BowVector::const_iterator vitpKF-mBowVec.begin(), vendpKF-mBowVec.end(); vit ! vend; vit) { listKeyFrame* lKFs mvInvertedFile[vit-first]; for(listKeyFrame*::iterator litlKFs.begin(), lend lKFs.end(); lit!lend; lit) { KeyFrame* pKFi*lit; if(pKFi-mnLoopQuery!pKF-mnId) { pKFi-mnLoopWords0; // 此处如果if条件成立代表没有共视关系此时才会进入执行语句 // 换言之如果有共视关系就直接忽略了这是它和DetectRelocalizationCandidates唯一的区别 if(!spConnectedKeyFrames.count(pKFi)) { pKFi-mnLoopQuerypKF-mnId; lKFsSharingWords.push_back(pKFi); } } pKFi-mnLoopWords; } }3. DetectRelocalizationCandidates// Relocalization std::vectorKeyFrame* DetectRelocalizationCandidates(Frame* F);检测的主要步骤如下(1) 找出与当前帧pKF有公共单词的所有关键帧pKFi不包括与当前帧相连的关键帧。(2) 统计所有闭环候选帧中与pKF具有共同单词最多的单词数只考虑共有单词数大于0.8*maxCommonWords以及匹配得分大于给定的minScore的关键帧存入lScoreAndMatch。(3) 对于第二步中筛选出来的pKFi每一个都要抽取出自身的共视共享地图点最多的前10帧关键帧分为一组计算该组整体得分与pKF比较的记为bestAccScore。所有组得分大于0.75*bestAccScore的均当作闭环候选帧。vectorKeyFrame* KeyFrameDatabase::DetectRelocalizationCandidates(Frame *F) { listKeyFrame* lKFsSharingWords; // Search all keyframes that share a word with current frame //搜索所有和和F有着相同单词的keyframe存储在lKFsSharingWords //并且更新keyframe中mnRelocWords表示和此F有多少共同的单词 { unique_lockmutex lock(mMutex); for(DBoW2::BowVector::const_iterator vitF-mBowVec.begin(), vendF-mBowVec.end(); vit ! vend; vit) { listKeyFrame* lKFs mvInvertedFile[vit-first]; for(listKeyFrame*::iterator litlKFs.begin(), lend lKFs.end(); lit!lend; lit) { KeyFrame* pKFi*lit; if(pKFi-mnRelocQuery!F-mnId) { pKFi-mnRelocWords0; pKFi-mnRelocQueryF-mnId; lKFsSharingWords.push_back(pKFi); } pKFi-mnRelocWords; } } } if(lKFsSharingWords.empty()) return vectorKeyFrame*(); // Only compare against those keyframes that share enough words //在lKFsSharingWords中寻找mnRelocWords的最大值存入maxCommonWords int maxCommonWords0; for(listKeyFrame*::iterator litlKFsSharingWords.begin(), lend lKFsSharingWords.end(); lit!lend; lit) { if((*lit)-mnRelocWordsmaxCommonWords) maxCommonWords(*lit)-mnRelocWords; } int minCommonWords maxCommonWords*0.8f; listpairfloat,KeyFrame* lScoreAndMatch; int nscores0; // Compute similarity score. //遍历lKFsSharingWords中的keyframe当其中的keyframe的mRelocScore大于阈值minCommonWords则计算相似度后放入lScoreAndMatch中 for(listKeyFrame*::iterator litlKFsSharingWords.begin(), lend lKFsSharingWords.end(); lit!lend; lit) { KeyFrame* pKFi *lit; if(pKFi-mnRelocWordsminCommonWords) { nscores; float si mpVoc-score(F-mBowVec,pKFi-mBowVec); pKFi-mRelocScoresi; lScoreAndMatch.push_back(make_pair(si,pKFi)); } } if(lScoreAndMatch.empty()) return vectorKeyFrame*(); listpairfloat,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(listpairfloat,KeyFrame* ::iterator itlScoreAndMatch.begin(), itendlScoreAndMatch.end(); it!itend; it) { KeyFrame* pKFi it-second; //返回共视图中与此keyframe连接的权值前10的节点keyframe vectorKeyFrame* vpNeighs pKFi-GetBestCovisibilityKeyFrames(10); float bestScore it-first; float accScore bestScore; KeyFrame* pBestKF pKFi; for(vectorKeyFrame*::iterator vitvpNeighs.begin(), vendvpNeighs.end(); vit!vend; vit) { KeyFrame* pKF2 *vit; //说明pKF2与F没有共同的单词就放弃此循环的关键帧 if(pKF2-mnRelocQuery!F-mnId) continue; accScorepKF2-mRelocScore; if(pKF2-mRelocScorebestScore) { pBestKFpKF2; bestScore pKF2-mRelocScore; } } lAccScoreAndMatch.push_back(make_pair(accScore,pBestKF)); if(accScorebestAccScore) bestAccScoreaccScore; } // Return all those keyframes with a score higher than 0.75*bestScore //返回lAccScoreAndMatch中所有得分超过0.75*bestAccScore的keyframe集合 float minScoreToRetain 0.75f*bestAccScore; setKeyFrame* spAlreadyAddedKF; vectorKeyFrame* vpRelocCandidates; vpRelocCandidates.reserve(lAccScoreAndMatch.size()); for(listpairfloat,KeyFrame* ::iterator itlAccScoreAndMatch.begin(), itendlAccScoreAndMatch.end(); it!itend; it) { const float si it-first; if(siminScoreToRetain) { KeyFrame* pKFi it-second; if(!spAlreadyAddedKF.count(pKFi)) { vpRelocCandidates.push_back(pKFi); spAlreadyAddedKF.insert(pKFi); } } } return vpRelocCandidates; }参考文献ORB-SLAM2之KeyFrameDataBase_菜菜的阿远的博客-CSDN博客ORB SLAM2源码解读(五)KeyFrame DataBase类 - 古月居【SLAM学习笔记】3-ORB_SLAM3关键源码分析① KeyFrameDatabase二_口哨糖youri的博客-CSDN博客
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2591386.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!