• ORB-SLAM2从理论到代码实现(十五):KeyFrameDatabase类


    1. 该类是关键帧的数据库

    构建关键帧数据库,可以联系链表等常用数据结构的构建过程:创建、增加元素、删除元素、清理。

    首先需要明确数据存储的数据类型:以关键帧作为数据库的元素。

    这个地方需要理解两个概念:单词(词袋)和关键帧。
    单词(词袋):预先构建好的,离线词典(ORBvoc.txt):它是DBoW2作者使用orb特征,使用大量图片训练的结果。

    1.1. 成员变量

    std::vector> mvInvertedFile;

    vector的索引是预先训练好的特征词汇,词汇的值就是0到n,所以可以当作索引来使用。

    vector对应的索引处存放包含该词汇的所有关键帧。

    1.2. 成员函数

    函数用途
    KeyFrameDatabase(const ORBVocabulary &voc);构造函数
    void add(KeyFrame* pKF);根据关键帧的词汇,把关键帧添加到数据库
    void erase(KeyFrame* pKF);从数据库中删除相应的关键帧
    void clear();清空关键帧数据库
    函数用途
    std::vector> DetectLoopCandidates(KeyFrame pKF, float minScore);在闭环检测中找到与该关键帧可能闭环的关键帧
    std::vector DetectRelocalizationCandidates(Frame* F);在重定位中找到与该帧相似的关键帧

    2. DetectLoopCandidates

    1. // Loop Detection
    2. std::vector DetectLoopCandidates(KeyFrame* pKF, float minScore);

    这个函数的流程和DetectRelocalizationCandidates唯一的区别是忽略和自己已有共视关系的关键帧,所以我们此处不复制全部的代码了,只重点强调不同的地方 

    1. for(DBoW2::BowVector::const_iterator vit=pKF->mBowVec.begin(), vend=pKF->mBowVec.end(); vit != vend; vit++)
    2. {
    3. list &lKFs = mvInvertedFile[vit->first];
    4. for(list::iterator lit=lKFs.begin(), lend= lKFs.end(); lit!=lend; lit++)
    5. {
    6. KeyFrame* pKFi=*lit;
    7. if(pKFi->mnLoopQuery!=pKF->mnId)
    8. {
    9. pKFi->mnLoopWords=0;
    10. // 此处如果if条件成立,代表没有共视关系,此时才会进入执行语句
    11. // 换言之,如果有共视关系,就直接忽略了,这是它和DetectRelocalizationCandidates唯一的区别
    12. if(!spConnectedKeyFrames.count(pKFi))
    13. {
    14. pKFi->mnLoopQuery=pKF->mnId;
    15. lKFsSharingWords.push_back(pKFi);
    16. }
    17. }
    18. pKFi->mnLoopWords++;
    19. }
    20. }

    3. DetectRelocalizationCandidates

    1. // Relocalization
    2. std::vector DetectRelocalizationCandidates(Frame* F);

     检测的主要步骤如下:

    1)找出与当前帧pKF有公共单词的所有关键帧pKFi,不包括与当前帧相连的关键帧。

    2)统计所有闭环候选帧中与pKF具有共同单词最多的单词数,只考虑共有单词数大于0.8*maxCommonWords以及匹配得分大于给定的minScore的关键帧,存入lScoreAndMatch。

    3)对于第二步中筛选出来的pKFi,每一个都要抽取出自身的共视(共享地图点最多的前10帧)关键帧分为一组,计算该组整体得分(与pKF比较的),记为bestAccScore。所有组得分大于0.75*bestAccScore的,均当作闭环候选帧。

    1. vector KeyFrameDatabase::DetectRelocalizationCandidates(Frame *F)
    2. {
    3. list lKFsSharingWords;
    4. // Search all keyframes that share a word with current frame
    5. //搜索所有和和F有着相同单词的keyframe存储在lKFsSharingWords
    6. //并且更新keyframe中mnRelocWords,表示和此F有多少共同的单词
    7. {
    8. unique_lock lock(mMutex);
    9. for(DBoW2::BowVector::const_iterator vit=F->mBowVec.begin(), vend=F->mBowVec.end(); vit != vend; vit++)
    10. {
    11. list &lKFs = mvInvertedFile[vit->first];
    12. for(list::iterator lit=lKFs.begin(), lend= lKFs.end(); lit!=lend; lit++)
    13. {
    14. KeyFrame* pKFi=*lit;
    15. if(pKFi->mnRelocQuery!=F->mnId)
    16. {
    17. pKFi->mnRelocWords=0;
    18. pKFi->mnRelocQuery=F->mnId;
    19. lKFsSharingWords.push_back(pKFi);
    20. }
    21. pKFi->mnRelocWords++;
    22. }
    23. }
    24. }
    25. if(lKFsSharingWords.empty())
    26. return vector();
    27. // Only compare against those keyframes that share enough words
    28. //在lKFsSharingWords中,寻找mnRelocWords的最大值存入maxCommonWords
    29. int maxCommonWords=0;
    30. for(list::iterator lit=lKFsSharingWords.begin(), lend= lKFsSharingWords.end(); lit!=lend; lit++)
    31. {
    32. if((*lit)->mnRelocWords>maxCommonWords)
    33. maxCommonWords=(*lit)->mnRelocWords;
    34. }
    35. int minCommonWords = maxCommonWords*0.8f;
    36. listfloat,KeyFrame*> > lScoreAndMatch;
    37. int nscores=0;
    38. // Compute similarity score.
    39. //遍历lKFsSharingWords中的keyframe,当其中的keyframe的mRelocScore大于阈值minCommonWords则计算相似度后放入lScoreAndMatch中
    40. for(list::iterator lit=lKFsSharingWords.begin(), lend= lKFsSharingWords.end(); lit!=lend; lit++)
    41. {
    42. KeyFrame* pKFi = *lit;
    43. if(pKFi->mnRelocWords>minCommonWords)
    44. {
    45. nscores++;
    46. float si = mpVoc->score(F->mBowVec,pKFi->mBowVec);
    47. pKFi->mRelocScore=si;
    48. lScoreAndMatch.push_back(make_pair(si,pKFi));
    49. }
    50. }
    51. if(lScoreAndMatch.empty())
    52. return vector();
    53. listfloat,KeyFrame*> > lAccScoreAndMatch;
    54. float bestAccScore = 0;
    55. // Lets now accumulate score by covisibility
    56. //遍历lScoreAndMatch中的keyframe,找出其共视图中与此keyframe连接的权值前N的节点,加上原keyframe总共11个keyframe
    57. //累加这11个keyframe的相似度得分,然后在11个keyframe中选择相似度得分最高的那个放入lAccScoreAndMatch中
    58. //在遍历过程中计算bestAccScore,也就是AccScore的最大值,后面的再次筛选有用
    59. for(listfloat,KeyFrame*> >::iterator it=lScoreAndMatch.begin(), itend=lScoreAndMatch.end(); it!=itend; it++)
    60. {
    61. KeyFrame* pKFi = it->second;
    62. //返回共视图中与此keyframe连接的权值前10的节点keyframe
    63. vector vpNeighs = pKFi->GetBestCovisibilityKeyFrames(10);
    64. float bestScore = it->first;
    65. float accScore = bestScore;
    66. KeyFrame* pBestKF = pKFi;
    67. for(vector::iterator vit=vpNeighs.begin(), vend=vpNeighs.end(); vit!=vend; vit++)
    68. {
    69. KeyFrame* pKF2 = *vit;
    70. //说明pKF2与F没有共同的单词,就放弃此循环的关键帧
    71. if(pKF2->mnRelocQuery!=F->mnId)
    72. continue;
    73. accScore+=pKF2->mRelocScore;
    74. if(pKF2->mRelocScore>bestScore)
    75. {
    76. pBestKF=pKF2;
    77. bestScore = pKF2->mRelocScore;
    78. }
    79. }
    80. lAccScoreAndMatch.push_back(make_pair(accScore,pBestKF));
    81. if(accScore>bestAccScore)
    82. bestAccScore=accScore;
    83. }
    84. // Return all those keyframes with a score higher than 0.75*bestScore
    85. //返回lAccScoreAndMatch中所有得分超过0.75*bestAccScore的keyframe集合
    86. float minScoreToRetain = 0.75f*bestAccScore;
    87. set spAlreadyAddedKF;
    88. vector vpRelocCandidates;
    89. vpRelocCandidates.reserve(lAccScoreAndMatch.size());
    90. for(listfloat,KeyFrame*> >::iterator it=lAccScoreAndMatch.begin(), itend=lAccScoreAndMatch.end(); it!=itend; it++)
    91. {
    92. const float &si = it->first;
    93. if(si>minScoreToRetain)
    94. {
    95. KeyFrame* pKFi = it->second;
    96. if(!spAlreadyAddedKF.count(pKFi))
    97. {
    98. vpRelocCandidates.push_back(pKFi);
    99. spAlreadyAddedKF.insert(pKFi);
    100. }
    101. }
    102. }
    103. return vpRelocCandidates;
    104. }

    参考文献

    ORB-SLAM2之KeyFrameDataBase_菜菜的阿远的博客-CSDN博客

    ORB SLAM2源码解读(五):KeyFrame DataBase类 - 古月居

    【SLAM学习笔记】3-ORB_SLAM3关键源码分析① KeyFrameDatabase(二)_口哨糖youri的博客-CSDN博客

  • 相关阅读:
    Vue实现多个按钮切换样式
    安全性算法
    数据库课件= =
    【21天学习挑战赛】算法——选择排序
    探索现代办公应用系统架构:构建高效、可扩展的工作平台
    【超详细】Fastjson 1.2.24 命令执行漏洞复现-JNDI简单实现反弹shell(CVE-2017-18349)
    多径信道下通过LMS均衡算法提高通信质量——详细版
    【密评】商用密码应用安全性评估从业人员考核题库(四)
    操作系统的接口
    Arthas(2):使用Web Console
  • 原文地址:https://blog.csdn.net/xhtchina/article/details/125847914