news 2026/5/7 11:56:25

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ORB-SLAM2 从理论到代码实现(十五):KeyFrameDatabase 类

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

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

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

这个地方需要理解两个概念:单词(词袋)和关键帧。

单词(词袋):预先构建好的,离线词典 (ORBvoc.txt):它是DBoW2作者使用orb特征,使用大量图片训练的结果。

1.1. 成员变量

std::vector<list<KeyFrame*>> mvInvertedFile;

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

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

1.2. 成员函数

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

2. DetectLoopCandidates

// Loop Detection std::vector<KeyFrame *> DetectLoopCandidates(KeyFrame* pKF, float minScore);

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

for(DBoW2::BowVector::const_iterator vit=pKF->mBowVec.begin(), vend=pKF->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->mnLoopQuery!=pKF->mnId) { pKFi->mnLoopWords=0; // 此处如果if条件成立,代表没有共视关系,此时才会进入执行语句 // 换言之,如果有共视关系,就直接忽略了,这是它和DetectRelocalizationCandidates唯一的区别 if(!spConnectedKeyFrames.count(pKFi)) { pKFi->mnLoopQuery=pKF->mnId; lKFsSharingWords.push_back(pKFi); } } pKFi->mnLoopWords++; } }

3. DetectRelocalizationCandidates

// Relocalization std::vector<KeyFrame*> DetectRelocalizationCandidates(Frame* F);

检测的主要步骤如下:

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

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

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

vector<KeyFrame*> KeyFrameDatabase::DetectRelocalizationCandidates(Frame *F) { 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*bestScore //返回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; }

参考文献

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

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

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/7 11:53:30

Go语言轻量级Web框架Mie:极简设计、高性能与实战指南

1. 项目概述&#xff1a;一个为现代Web应用量身定制的轻量级后端框架如果你和我一样&#xff0c;在过去几年里频繁地构建中小型Web应用、API服务或者微服务&#xff0c;那你一定经历过框架选择的纠结。是选择功能全面但略显笨重的“巨无霸”&#xff0c;还是选择极致轻量但需要…

作者头像 李华
网站建设 2026/5/7 11:52:57

AI 编码助手高效协作指南:规范驱动开发与 dev-kit 实战

1. 项目概述&#xff1a;一个为AI编码伙伴量身定制的“开发工具箱”如果你和我一样&#xff0c;日常开发已经离不开像 Cursor、Claude Code、GitHub Copilot 这样的 AI 编码助手&#xff0c;那你肯定也遇到过类似的困扰&#xff1a;有时候&#xff0c;你希望 AI 能帮你完成一个…

作者头像 李华
网站建设 2026/5/7 11:51:51

母婴护理技能库构建:从知识管理到科学育儿的实践指南

1. 项目概述&#xff1a;母婴护理技能库的构建与价值最近在整理个人知识库时&#xff0c;我意识到一个长期被忽视但至关重要的领域&#xff1a;母婴护理。无论是新手父母、即将迎来新生命的家庭&#xff0c;还是从事相关行业的护理人员&#xff0c;面对海量、碎片化且质量参差不…

作者头像 李华
网站建设 2026/5/7 11:50:12

3步搞定OBS浏览器插件:从零到精通的完整指南

3步搞定OBS浏览器插件&#xff1a;从零到精通的完整指南 【免费下载链接】obs-browser CEF-based OBS Studio browser plugin 项目地址: https://gitcode.com/gh_mirrors/ob/obs-browser 你是否想在OBS Studio中嵌入动态网页内容&#xff0c;实现更丰富的直播效果&#…

作者头像 李华