ORB-SLAM2 论文&代码学习 —— LocalMapping 线程
转载请注明出处,谢谢
原创作者:Mingrui
原创链接:https://www.cnblogs.com/MingruiYu/p/12360913.html
本文要点:
- ORB-SLAM2 LocalMapping 线程 论文内容介绍
- ORB-SLAM2 LocalMapping 线程 代码结构介绍
写在前面
之前的 ORB-SLAM2 系列文章中,我们已经对 Tracking 线程和其中的单目初始化部分进行了介绍。我们将在本文中,对 ORB-SLAM2 系统的 LocalMapping 线程进行介绍。
依旧祭出该图,方便查看:

也再次献上我绘制的程序导图全图:ORB-SLAM2 程序导图
老规矩,还是分两部分:以 ORB-SLAM 论文为参考 和 以 ORB-SLAM2 代码(程序导图)为参考。
以 ORB-SLAM 论文为参考
LocalMapping 线程的大致步骤如下:
- 接收从 Tracking 线程插入的 KF,并进行预处理
- 剔除质量较差的 MapPoints
- 通过三角化生成新的 MapPoints
- Current KF 未与现有 MapPoints 匹配的 FeaturePoints 与其 Covisible KFs 的 FeaturePoints 进行匹配,并三角化
- Local BA
- 剔除冗余的局部 KF
LocalMapping 线程的存在主要有这么几个意义:
- 筛选 KFs
- 进一步优化 Tracking 线程得到的 KFs 位姿以及 MapPoints 坐标,但这个优化还是相对轻量级的(与 LoopClosing 线程相比),且这里的优化不涉及回环
下面我们对每一个步骤进行详细的介绍。
插入 KF
当 Tracking 线程确定一个要插入的 KF 时,实际上它并没有真的完成将 KF 插入 Map 的动作。当我们将一个 KF 插入 Map 中时,我们需要同时做很多更新工作:
- 更新 Covisibility Graph(在 Covisibility Graph 中添加新的 KF node,根据共视关系添加新的 edge)
- 更新生成树
- 计算新 KF 的 BoW (便于后面通过特征匹配和三角化生成新的 MapPoints)
剔除质量较差的 MapPoints
存储在 Map 中的 MapPoints 需要有较高的质量(追踪良好,三角化正确),所以此处需要采取一些措施去掉质量较差的 MapPoints。判断 MapPoints 质量较差的标准为,在该 MapPoint 被创造后的3个 KFs 时间范围内:
- 实际看到该 MapPoints 的帧数 / 应该看到该 MapPoints 的帧数 < 25% (注意不只是 KFs)
- 应该看到该 MapPoints 的帧:当我们有了某 MapPoint,也有了某帧的位姿时,我们可以通过投影判断该 MapPoint 是否在该帧的视野内,这些帧就是应该看到该 MapPoints 的帧
- 实际看到该 MapPoints 的帧:通过各种匹配方式,该 MapPoints 与某帧的某个 FeaturePoint 匹配上了,这些帧就是实际看到该 MapPoints 的帧
- 该 MapPoints 在被创造后,未能被至少3个 KFs 观测到(此处论文表达似乎不太清楚)
注意:即使 MapPoints 在创造满足上述要求,得以保留,但不代表它们以后不可能被剔除。如果之后因为 KF 的剔除(下文会讲)导致观测到该 MapPoint 的 KF 数少于3个,或者在 local BA 中该观测被认为是 outlier,那么它依然会被剔除。
通过三角化生成生成新的 MapPoints
对于单目 ORB-SLAM 来说,整个系统中只有两处可以在 Map 中添加 MapPoints:一处是初始化的时候,另一处就是这里。
ORB-SLAM 将在 Current KF 的未能与已存在 MapPoints 匹配上的 FeaturePoints,与其 Covisible KFs 中同样未能与已存在 MapPoints 匹配上的 FeaturePoints 进行匹配。如果匹配上了,则可以通过三角化,生成一个新的 MapPoint(生成之后要检查其位置,视差,重投影误差,尺度一致性)。这个 FeaturePoint 与 FeaturePoint 之间的匹配是通过 BoW 搜索实现的。
通过两个 KFs 生成新的 MapPoint 后,还要检查它有没有在别的 KFs 中出现。所以要将该 MapPoint 投影至其他的 Covisible KFs,与它们的 FeaturePoints 进行匹配。匹配上的话就将该 MapPoint 与那个 KF 的那个 FeaturePoint 链接上。
局部 BA
对 Current KF 及其 Covisible KFs 及其它们所观察到的所有 MapPoints 进行 BA 优化。
注意,其他观测到这些 MapPoints,但是不再上述 KFs 之列的 KFs,也会作为约束参与该优化(其本身不会被优化)。
剔除冗余的局部 KF
在 Tracking 线程中,ORB-SLAM 以非常宽松的条件,向 Map 中插入了很多很多 KFs,但显然 Map 中是不能永久保留这么多 KFs 的,这会使 Map 过于庞大,且极大增加各种 BA 的运算量。所以要剔除一些信息冗余的。
如果 Current KF 及其 Covisible KFs 中,有哪个 KF 它所观测到的 90% 的 MapPoints 都能被其它至少3个(尺度相同或更好的)KFs 观测到,则这个 KF 的信息就算作是冗余的,就把它去掉。这样做的目的是让 Map 的 KF 数不要太多,且在规模一定的场景内,Map 中的 KF 数目不要无上限的增长。这样也有利于减轻 BA 优化的负担。
以 ORB-SLAM2 代码(程序导图)为参考

上图就是 LocalMapping 线程的程序导图,从中可以很清晰地看出 LocalMapping 线程的逻辑,并且和论文中的步骤进行对应。
如果嫌这张图不够清晰的话,可以点击 ORB-SLAM2 程序导图链接(文首)查看清晰全图
插入 KF
在插入 KF 后,会通过 LocalMapping::SetAcceptKeyFrames(false) 通知 Tracking 线程,LocalMapping 线程正忙。记得在 Tracking 线程中最后一步决定是否插入关键帧时,有一个条件就是:
- LocalMapping 线程正闲置,但如果已经有连续20帧内没有插入过 KF 了,那么 LocalMapping 线程不管忙不忙,都要插入 KF 了
另外,LocalMapping 线程通过维护一个队列来存储 Tracking 线程送入,但还未被 LocalMapping 处理的 KFs。LocalMapping::CheckNewKeyFrames() 用来检查该队列里有没有 KF。
从上述队列中取出队首 KF,使用 LocalMapping::ProcessNewKeyFrame() 对其进行处理,包括计算该 KF 的 BoW,以及更新 Covisibility Graph。最后,经过上述处理的 KF 才可以真正插入 Map 之中。
剔除质量较差的 MapPoints
LocalMapping::MapPointCulling()
通过三角化生成新的 MapPoints
LocalMapping::CreateNewMapPoints()
MapPoints 融合
当队列中所有的 KFs 都经过上述处理了(队列空了),那么才会开始接下来的步骤。
MapPoints 融合,这部分其实是属于通过三角化生成新的 MapPoints 里的,论文中说过:“通过两个 KFs 生成新的 MapPoint 后,还要检查它有没有在别的 KFs 中出现。所以要将该 MapPoint 投影至其他的 Covisible KFs,与它们的 FeaturePoints 进行匹配。匹配上的话就将该 MapPoint 与那个 KF 的那个 FeaturePoint 链接上”,这一步的目的就在与完成这项工作。
但是,这里需要注意,在上述表述中,“匹配上的话就将该 MapPoint 与那个 KF 的那个 FeaturePoint 链接上”,但如果这些条件都么满足,但那个 FeaturePoint 已经链接上了某个 MapPoint 怎么办?ORB-SLAM 采取的策略很简单,用新的 MapPoint 替换掉原来链接的 MapPoint。
举一个可能出现这种情况的情景:同时有4个刚送入 LocalMapping 线程的 KFs 观测到了 MapPoint_1 (MapPoint_1 此前未在 Map 中创建)。在上文三角化的过程中,假设 KF_1 和 KF_2 三角化生成了 MapPoint_1,但同时 KF_3 和 KF_4 也三角化生成了 MapPoint_1。队列中所有 KFs 处理完毕后,此时,我在将 KF_1 的 MapPoint 投影至 KF_3 时,就会发现 KF_3 的匹配 FeaturePoint 已经链接了 MapPoint了。此时需要一个融合策略(ORB-SLAM 简单的采用了替换的方法)。
Local BA
当队列中所有的 KFs 都经过上述处理了(队列空),且 其他线程没有让 LocalMapping 线程暂停(后面会提到 LoopClosing 线程中有地方会让 LocalMapping 线程中的 Local BA 先暂停),则进行 Optimizer::LocalBundleAdjustment()。
剔除冗余的 KFs
LocalMapping::KeyFrameCulling()
最后通过 LocalMapping::SetAcceptKeyFrames(true) 通知 Tracking 线程,LocalMapping 线程闲下来了,可以有条件的接收 KFs 了。
ORB-SLAM2 系列博文
ORB-SLAM2 论文&代码学习 —— Tracking 线程
ORB-SLAM2 论文&代码学习 —— LocalMapping 线程
ORB-SLAM2 论文&代码学习 —— LocalMapping 线程的更多相关文章
- ORB-SLAM2 论文&代码学习 ——Tracking 线程
本文要点: ORB-SLAM2 Tracking 线程 论文内容介绍 ORB-SLAM2 Tracking 线程 代码结构介绍 写在前面 上一篇文章中我们已经对 ORB-SLAM2 系统有了一个概览性 ...
- ORB-SLAM2 论文&代码学习 —— LoopClosing 线程
转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12369339.html 本文要点: ORB-SLAM2 LoopC ...
- ORB-SLAM2 论文&代码学习 —— 单目初始化
转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12358458.html 本文要点: ORB-SLAM2 单目初始化 ...
- ORB-SLAM2 论文&代码学习 —— 概览
转载请注明出处,谢谢 原创作者:MingruiYU 原创链接:https://www.cnblogs.com/MingruiYu/p/12347171.html *** 本文要点: ORB-SLAM2 ...
- ORB SLAM2在Ubuntu 16.04上的运行配置
http://www.mamicode.com/info-detail-1773781.html 安装依赖 安装OpenGL 1. 安装opengl Library$sudo apt-get inst ...
- python自动化开发学习 进程, 线程, 协程
python自动化开发学习 进程, 线程, 协程 前言 在过去单核CPU也可以执行多任务,操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换任务2,任务2执行0.01秒,在切换到任务3,这 ...
- 手写一个线程池,带你学习ThreadPoolExecutor线程池实现原理
摘要:从手写线程池开始,逐步的分析这些代码在Java的线程池中是如何实现的. 本文分享自华为云社区<手写线程池,对照学习ThreadPoolExecutor线程池实现原理!>,作者:小傅哥 ...
- luogg_java学习_12_线程
本文为博主辛苦总结,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 谢谢配合! 线程 程序.进程.线程的概念 程序:我们用程序设计语言 ...
- Java并发包源码学习之线程池(一)ThreadPoolExecutor源码分析
Java中使用线程池技术一般都是使用Executors这个工厂类,它提供了非常简单方法来创建各种类型的线程池: public static ExecutorService newFixedThread ...
随机推荐
- ubuntu系统搭建(jdk1.8+mysql5.7.28+Hadoop2.7.7+hive3.1.2)
一不小心电脑没电关机之后虚拟机就挂了,然后下定决心重新搭一个虚拟机. 以下是几天安装过程的记录以及一些小提示,包括在ubuntu中安装jdk1.8+mysql5.7.28+Hadoop2.7.7+hi ...
- 投影方式- Unity3D游戏开发培训
投影方式- Unity3D游戏开发培训 作者:Jesai 2018-02-12 20:33:13 摘 要 透视投影是3D渲染的基本概念,也是3D程序设计的基础.掌握透视投影的原理对于深入理解其他 ...
- 'NoneType' object has no attribute shape
使用cv2读取图片时,输出图片形状大小时出现报错“ 'NoneType' object has no attribute shape”,后来排查发现读取图片的返回值image为None, 这就说明图片 ...
- tomcat梳理
tomcat梳理 Tomcat的缺省端口是多少,怎么修改? 默认接口是8080 修改 1)找到Tomcat目录下的conf文件夹 2)进入conf文件夹里面找到server.xml文件 3)打开ser ...
- Docker三剑客之swarm
简介 swarm是一种docker集群管理工具,跟三剑客前两者不同的是:compose是一种统一编排的工具,machine是一种远程控制工具,swarm则是将多个docker主机映射成一个docker ...
- UNIX 版本
一般UNIX系统都来源于AT&T公司的System V UNIX系统,BSD UNIX或其他类UNIX系统. System V UNIX:当今市场上大多数主要的商业UNIX系统都是基于AT&a ...
- 使用Allure+testNG自动生成漂亮强大的测试用例报告
最近领导让我找一个可以每次打包自动生成测试用例的东西,jenkins或者idea都可以, 最后找到了这个allure,也踩了很多坑,废话不多说!,总结一下: 1 使用原生allure 添加依赖: &l ...
- springboot中使用自定义注解实现策略模式,去除工厂模式的switch或ifelse,实现新增策略代码零修改
前言 思路与模拟业务 源码地址 https://gitee.com/houzheng1216/springboot 整体思路就是通过注解在策略类上指定约定好的type,项目启动之后将所有有注解的typ ...
- Dockers 部署 MongoDB + mongo-express
1. 拉取 Mongo 镜像 docker pull mongo: 2. 运行镜像 docker run -d --name mongodb --volume /usr/local/mongodat ...
- es学习(三):分词器介绍以及中文分词器ik的安装与使用
什么是分词 把文本转换为一个个的单词,分词称之为analysis.es默认只对英文语句做分词,中文不支持,每个中文字都会被拆分为独立的个体. 示例 POST http://192.168.247.8: ...