ORB_SLAM3 闭环检测

news2024/10/7 15:26:57
  • ORB SLAM3系统初始化
  • ORB SLAM3 构建Frame
  • ORB_SLAM3 单目初始化
  • ORB_SLAM3 双目匹配
  • ORB_SLAM3_IMU预积分理论推导(预积分项)
  • ORB_SLAM3_IMU预积分理论推导(噪声分析)
  • ORB_SLAM3_IMU预积分理论推导(更新)
  • ORB_SLAM3_IMU预积分理论推导(残差)
  • ORB_SLAM3_优化方法 Pose优化
  • ORB_SLAM3 闭环检测

在这里插入图片描述

DetectNBestCandidates

DetectNBestCandidates主要是用来闭环检测得到候选关键帧,和闭环有关的变量如下:

  • mnPlaceRecognitionQuery:与其有公共单词的关键帧
  • mnPlaceRecognitionWords:与其有多少公共单词数
  • mPlaceRecognitionScore:与其的词袋相似度

1.闭环检测示意图

在这里插入图片描述

2.步骤

在这里插入图片描述

  1. 通过词袋的BowVec找出与当前关键帧具有相同单词的所有关键帧,并统计对应的相同单词数量,但不包括对应的共视关键帧spConnectedKF,得到lKFsSharingWords
    // Step 1统计与当前关键帧有相同单词的关键帧
    list<KeyFrame *> lKFsSharingWords;
    // set<KeyFrame*> spInsertedKFsSharing;
    //  当前关键帧的共视关键帧(避免将当前关键帧的共视关键帧加入回环检测)
    set<KeyFrame *> spConnectedKF;

    // Search all keyframes that share a word with current frame
    {
        unique_lock<mutex> lock(mMutex);
        // 拿到当前关键帧的共视关键帧
        spConnectedKF = pKF->GetConnectedKeyFrames();

        // 遍历当前关键帧bow向量的每个单词
        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(spConnectedKF.find(pKFi) != spConnectedKF.end())
                {
                    continue;
                }*/
                // 如果此关键帧没有被当前关键帧访问过(防止重复添加)
                if (pKFi->mnPlaceRecognitionQuery != pKF->mnId)
                {
                    // 初始化公共单词数为0
                    pKFi->mnPlaceRecognitionWords = 0;
                    // 如果该关键帧不是当前关键帧的共视关键帧
                    if (!spConnectedKF.count(pKFi))
                    {
                        // 标记该关键帧被当前关键帧访问到(也就是有公共单词)
                        pKFi->mnPlaceRecognitionQuery = pKF->mnId;
                        // 把当前关键帧添加到有公共单词的关键帧列表中
                        lKFsSharingWords.push_back(pKFi);
                    }
                }
                // 递增该关键帧与当前关键帧的公共单词数
                pKFi->mnPlaceRecognitionWords++;
                /*if(spInsertedKFsSharing.find(pKFi) == spInsertedKFsSharing.end())
                {
                    lKFsSharingWords.push_back(pKFi);
                    spInsertedKFsSharing.insert(pKFi);
                }*/
            }
        }
    }
  1. 计算当前关键帧与具有一定公共单词数的关键帧BowVec的分数,得到lScoreAndMatch
    • 最大公共单词数maxCommonWords0.8(minCommonWords)动态过滤掉那些公共单词数少的
      在这里插入图片描述
    for (list<KeyFrame *>::iterator lit = lKFsSharingWords.begin(), lend = lKFsSharingWords.end(); lit != lend; lit++)
    {
        KeyFrame *pKFi = *lit;
        // 如果当前帧的公共单词数大于minCommonWords
        if (pKFi->mnPlaceRecognitionWords > minCommonWords)
        {
            nscores++; //未使用
            // 计算相似度
            float si = mpVoc->score(pKF->mBowVec, pKFi->mBowVec);
            // 记录该候选帧与当前帧的相似度
            pKFi->mPlaceRecognitionScore = si;
            // 记录到容器里, 每个元素是<相似度,候选帧的指针>
            lScoreAndMatch.push_back(make_pair(si, pKFi));
        }
    }
  1. 单个关键帧相似可能不太准确,那么就组队,对lScoreAndMatch中的关键帧,将候选关键帧周围的共视关键帧(需要和当前关键帧有公共的单词,且单词数超过minCommonWords)拉入,统计每一组的分数,并用每一组分数最大的那帧代表该组,选为候选关键帧
    在这里插入图片描述
    list<pair<float, KeyFrame *>> lAccScoreAndMatch;
    float bestAccScore = 0;

    // Lets now accumulate score by covisibility
    // 变量所有被lScoreAndMatch记录的pair <相似度,候选关键帧>
    for (list<pair<float, KeyFrame *>>::iterator it = lScoreAndMatch.begin(), itend = lScoreAndMatch.end(); it != itend; it++)
    {
        // 候选关键帧
        KeyFrame *pKFi = it->second;
        // 与候选关键帧共视关系最好的10个关键帧
        vector<KeyFrame *> vpNeighs = pKFi->GetBestCovisibilityKeyFrames(10);
        // 初始化最大相似度为该候选关键帧自己的相似度
        float bestScore = it->first;
        // 初始化小组累计得分为改候选关键帧自己的相似度
        float accScore = bestScore;
        // 初始化组内相似度最高的帧为该候选关键帧本身
        KeyFrame *pBestKF = pKFi;
        // 遍历与当前关键帧共视关系最好的10帧
        for (vector<KeyFrame *>::iterator vit = vpNeighs.begin(), vend = vpNeighs.end(); vit != vend; vit++)
        {
            KeyFrame *pKF2 = *vit;
            // 如果该关键帧没有被当前关键帧访问过(也就是没有公共单词)则跳过
            if (pKF2->mnPlaceRecognitionQuery != pKF->mnId)
                continue;
            // 累加小组总分
            accScore += pKF2->mPlaceRecognitionScore;
            // 如果大于组内最高分,则更新当前最高分记录
            if (pKF2->mPlaceRecognitionScore > bestScore)
            {
                pBestKF = pKF2;
                bestScore = pKF2->mPlaceRecognitionScore;
            }
        }
        // 统计以组为单位的累计相似度和组内相似度最高的关键帧, 每个pair为<小组总相似度,组内相似度最高的关键帧指针>
        lAccScoreAndMatch.push_back(make_pair(accScore, pBestKF));
        // 统计最高得分, 这个bestAccSocre没有用到
        if (accScore > bestAccScore)
            bestAccScore = accScore;
    }
  1. lScoreAndMatch安装分数排序
    • 如果和当前关键帧是同一张地图,就添加到闭环候选帧vpLoopBowCand
    • 如果和当前关键帧是不同张地图,就添加到合并候选帧vpMergeBowCand
    //  按相似度从大到小排序
    lAccScoreAndMatch.sort(compFirst);
    // 最后返回的变量, 记录回环的候选帧
    vpLoopCand.reserve(nNumCandidates);
    // 最后返回的变量, 记录融合候选帧
    vpMergeCand.reserve(nNumCandidates);
    // 避免重复添加
    set<KeyFrame *> spAlreadyAddedKF;
    // cout << "Candidates in score order " << endl;
    // for(list<pair<float,KeyFrame*> >::iterator it=lAccScoreAndMatch.begin(), itend=lAccScoreAndMatch.end(); it!=itend; it++)
    int i = 0;
    list<pair<float, KeyFrame *>>::iterator it = lAccScoreAndMatch.begin();
    // 遍历lAccScoreAndMatch中所有的pair, 每个pair为<小组总相似度,组内相似度最高的关键帧指针>,nNumCandidates默认为3
    while (i < lAccScoreAndMatch.size() && (vpLoopCand.size() < nNumCandidates || vpMergeCand.size() < nNumCandidates))
    {
        // cout << "Accum score: " << it->first << endl;
        //  拿到候选关键帧的指针
        KeyFrame *pKFi = it->second;
        if (pKFi->isBad())
            continue;

        // 如果没有被重复添加
        if (!spAlreadyAddedKF.count(pKFi))
        {
            // 如果候选帧与当前关键帧在同一个地图里,且候选者数量还不足够
            if (pKF->GetMap() == pKFi->GetMap() && vpLoopCand.size() < nNumCandidates)
            {
                // 添加到回环候选帧里
                vpLoopCand.push_back(pKFi);
            }
            // 如果候选者与当前关键帧不再同一个地图里, 且候选者数量还不足够, 且候选者所在地图不是bad
            else if (pKF->GetMap() != pKFi->GetMap() && vpMergeCand.size() < nNumCandidates && !pKFi->GetMap()->IsBad())
            {
                // 添加到融合候选帧里
                vpMergeCand.push_back(pKFi);
            }
            // 防止重复添加
            spAlreadyAddedKF.insert(pKFi);
        }
        i++;
        it++;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/635225.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【量化交易笔记】8.基于深度学习(LSTM)预测股票价格

前言 前一章节&#xff0c;已作随机森林来预测股票价格&#xff0c;也是一种比较常见的方法&#xff0c;本章基于深度学习算法来处理时间序列&#xff0c;来预测股票未来的价格。LSTM是一种特殊类型的循环神经网络&#xff08;RNN&#xff09;&#xff0c;在自然语言处理和时间…

【C语言之函数栈帧】(动态图—巨细)一文带你了解局部变量随机值及栈区上的函数调用

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;C语言 局部变量为什么是随机值?函数是如何调用的&#xff1f; ✉️ 该篇将使用该编译器&#xff0c;通过介绍栈帧的创建和销毁来深入了解局…

计算机网络开荒3-传输层

文章目录 一、传输层概述1.1 网络层 vs 传输层 二、多路复用 多路分用三、UDP3.1 RDT3.1.1 Rdt3.1.1.1 Rdt1.03.1.1.2 Rdt2.03.1.1.3 Rdt2.13.1.1.4 Rdt2.23.11.5 Rdt 3.0 四、滑动窗口协议4.1 流水线机制4.1.2 滑动窗口协议GBNSR 五、TCP5.1 可靠数据传输5.1.1 RTT和超时 5.2 …

Vue中如何进行图表绘制

Vue中如何进行图表绘制 数据可视化是Web应用中非常重要的一部分&#xff0c;其中图表绘制是其中的重要环节。Vue作为一款流行的前端框架&#xff0c;提供了很多优秀的图表库&#xff0c;以满足不同业务场景下的需求。本文将介绍如何在Vue中进行图表绘制&#xff0c;包括使用Vu…

MM32F3273G8P火龙果开发板MindSDK开发教程4 - 滴嗒定时器Systick的配置

MM32F3273G8P火龙果开发板MindSDK开发教程4 - 滴嗒定时器Systick的配置 1、Systick寄存器 Systick是ARM内核的一个外设&#xff0c;所以在不同芯片的代码上移植比较方便&#xff0c;他总共有4个寄存器&#xff0c; 从Systick定义中可以看到&#xff1a; typedef struct {__I…

一文看懂Java中的锁

阅读本文你可以获得 Synchronized、ReentrantLock、ReentrantReadWriteLock、StampedLock、Condition、Semaphore、CountDownLatch、CyclicBarrier、JMM、Volatile、Happens-Before。 全文共16000字左右&#xff08;包含示例代码&#xff09;、欢迎收藏、在看、转发分批食用 一…

基于粒子群优化算法的配电网光伏储能双层优化配置模型[IEEE33节点](选址定容)(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【MySQL 数据库】11、学习 MySQL 中的【锁】

目录 一、锁的概述与分类二、全局锁&#xff08;全库数据备份&#xff09;三、表级锁(1) 表锁(2) 元数据锁&#xff08;Meta Data Lock&#xff09;(3) 意向锁 四、行级锁(1) 行锁(2) 间隙锁&临键锁 一、锁的概述与分类 锁是计算机协调多个进程或线程并发访问某一资源的机…

Whistle(基于 Node 实现的跨平台抓包调试工具)的使用

Whistle(基于 Node 实现的跨平台抓包调试工具)的使用 基于Node实现的跨平台抓包调试工具 可以劫持网络请求&#xff0c;并进行请求和响应的修改&#xff0c;来提高我们的开发调试效率 1.一键安装(装包/证书) npm i -g whistle && w2 start --init 证书的问题 安装…

[论文阅读] (31)李沐老师视频学习——4.研究的艺术·理由、论据和担保

《娜璋带你读论文》系列主要是督促自己阅读优秀论文及听取学术讲座&#xff0c;并分享给大家&#xff0c;希望您喜欢。由于作者的英文水平和学术能力不高&#xff0c;需要不断提升&#xff0c;所以还请大家批评指正&#xff0c;非常欢迎大家给我留言评论&#xff0c;学术路上期…

5.2 清洗数据

5.2 清洗数据 5.2.1 检测与处理重复值1、记录重复 drop_duplicates()2、特征重复 equals() 5.2.2 检测与处理缺失值 isnull()、notnull()1、 删除法 dropna()2、替换法 fillna()3、 插值法 5.2.3 检测与处理异常值1、3σ原则2、箱线图 5.2.4 任务实现&#xff08;wei&#xff0…

学习HCIP的day.12

目录 MPLS&#xff1a;多协议标签交换 一、协议的解释和意义 二、工作过程 1、控制层面&#xff1a; 2、数据层面&#xff1a; 三、标签号 四、MPLS的次末跳 五、MPLS的配置 六、使用mpls解决BGP的路由黑洞 七、MPLS VPN 八、配置&#xff1a; 1、ISP部分 MPLS&am…

python+pyqt制作的可最小化到托盘的桌面图形应用代码实例

本篇文章主要讲解使用python、pyqt制作的可以最小化到托盘的桌面图形应用实例。 日期:2023年6月11日 作者:任聪聪 效果演示 说明:实现桌面应用显示窗口,关闭窗口缩小到托盘,点击托盘显示窗口,邮件图标显示退出按钮,点击退出按钮即可关闭应用。 动态演示: 实际情况:…

postgresql 服务的启动操作,不再是DBA的专属

专栏内容&#xff1a;postgresql个人主页&#xff1a;我的主页座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物&#xff0e; 目录 前言 服务架构概述 服务启动流程 前提 流程 集群创建 集群介绍 数据库服务配置 数据…

202317读书笔记|《心寂犹似远山火:斋藤茂吉短歌300》——茫茫心海里,孤帆与谁同

202317读书笔记&#xff5c;《心寂犹似远山火&#xff1a;斋藤茂吉短歌300》——茫茫心海里&#xff0c;孤帆与谁同 很高兴周五这一天&#xff0c;之前很粉俳句的时候订阅的书都在今天都上架了&#xff0c;可以一饱眼福了。短歌是日本和歌一种诗体&#xff0c;是由三十一音节组…

YOLOv5/v7 添加注意力机制,30多种模块分析③,GCN模块,DAN模块

目录 一、注意力机制介绍1、什么是注意力机制&#xff1f;2、注意力机制的分类3、注意力机制的核心 二、GCN 模块1、GCN 模块的原理2、实验结果3、应用示例 三、DAN模块1、DAN模块的原理2、实验结果3、应用示例 大家好&#xff0c;我是哪吒。 &#x1f3c6;本文收录于&#xf…

扫雷——C语言实现

扫雷 文章目录 扫雷实现代码什么是扫雷基本功能实现显示选择菜单定义几个二维数组&#xff1f;确定数组大小初始化数组布置地雷打印展示数组排查地雷记录指定区域周围地雷的个数判断排雷成功排查地雷实现代码 基本功能的实现代码和效果展示 拓展功能简化游戏界面改变字体颜色实…

[创业之路-73] :如何判断一个公司或团队是熵减:凝聚力强、上下一心,还是,熵增:一盘散沙、乌合之众?

目录 前言&#xff1a; 一盘散沙、乌合之众&#xff1a; 凝聚力强、上下一心&#xff1a; 一、股权结构与利益分配 一盘散沙、乌合之众 凝聚力强、上下一心 二、组织架构与岗位职责 一盘散沙、乌合之众 凝聚力强、上下一心 三、战略目标 一盘散沙、乌合之众 凝聚力…

碳排放预测模型 | Python实现基于MLP多层感知机的碳排放预测模型(预测未来发展趋势)

文章目录 效果一览文章概述研究内容环境准备源码设计学习总结参考资料效果一览 ![1](https://img-blog.csdnimg.cn/34c113bde2 文章概述 碳排放预测模型 | Python实现基于MLP多层感知机的碳排放预测模型(预测未来发展趋势) 研究内容 这是数据集的链接:https://github.com/…

【伏羲八卦图】(PythonMatlab实现)

目录 1 与达尔文对话 2 与老子对话 2.1 Python实现 2.2 Matlab实现 1 与达尔文对话 140年前&#xff0c;1858年7月1日&#xff0c;达尔文在英伦岛发表了自己有关自然选择的杰出论文。他提出&#xff0c;生物的发展规律是物竞天择。经过物竞&#xff0c;自然界选择并存留最具…