ORB-SLAM2学习笔记7之System主类和多线程

文章目录

  • 0 引言
  • 1 整体框架
    • 1.1 整体流程
  • 2 System主类
    • 2.1 成员函数
    • 2.2 成员变量
  • 3 多线程
    • 3.1 ORB-SLAM2中的多线程
    • 3.2 加锁

0 引言

ORB-SLAM2是一种基于特征的视觉SLAMSimultaneous Localization and Mapping)系统,它能够从单个、双目或RBGD相机的输入中实时地同时定位相机的位置,并构建环境的三维地图。ORB-SLAM2是在ORB-SLAM的基础上进行改进和扩展的版本。

本文主要对ORB-SLAM2的整体框架,System主类和多线程进行学习和总结,如有理解错误,欢迎指正交流。

1 整体框架

1.1 整体流程

ORB-SLAM2整体框架如下图,主要流程可以概括为以下几个步骤:

请添加图片描述

  1. 特征提取和匹配ORB-SLAM2首先对输入的图像进行特征提取,通常使用Oriented FAST and Rotated BRIEF (ORB)算法来检测和描述图像中的特征点。然后,它使用特征描述子进行特征匹配,以在连续帧之间建立对应关系。

  2. 初始化:初始化阶段是在初始帧上建立初始地图并估计相机的初始位姿。ORB-SLAM2使用基于单目、双目或RGB-D输入的不同方法来进行初始化。在单目或双目情况下,可以使用基于运动的方法或基于平面的方法来估计相机的初始位姿。在RGB-D情况下,可以通过三角测量来估计初始位姿。

  3. 跟踪:跟踪阶段是ORB-SLAM2的核心部分,它通过连续图像帧之间的特征匹配和运动估计来实时定位相机。通过追踪特征点的运动,ORB-SLAM2可以估计相机的位姿变化,并通过优化方法来减小累积误差。

  4. 局部地图更新ORB-SLAM2通过局部地图来表示环境的三维结构。在跟踪过程中,它会不断地更新和扩展局部地图,包括添加新的地图点和关键帧。同时,ORB-SLAM2还会执行一些优化步骤,如相机位姿优化、地图点优化等,以提高地图的一致性和准确性。

  5. 回环检测:回环检测是为了解决定位漂移和累积误差问题的关键步骤。ORB-SLAM2会在跟踪过程中检测可能的回环,并使用回环检测算法来识别和纠正回环。一旦回环被检测到,ORB-SLAM2会进行全局优化来提高整体的一致性。

  6. 闭环优化:闭环优化是在回环检测之后执行的步骤,通过全局优化来进一步提高地图的一致性和准确性。ORB-SLAM2会使用所有的关键帧和地图点进行非线性优化,以减小累积误差并提高整体的位姿和地图质量。

  7. 地图管理ORB-SLAM2会维护一个稠密的局部地图和一个稀疏的全局地图,用于表示环境的三维结构。地图管理模块负责管理和更新地图,包括删除冗余地图点、关键帧的选择和插入、地图点的筛选等。

以上是ORB-SLAM2的主要流程和步骤。通过不断的特征提取、跟踪、地图更新、回环检测和优化,ORB-SLAM2能够实现实时的定位和地图构建,并在大范围和长时间的场景中表现出较好的性能。

也有大佬绘制了更详细的流程图(以mono_tum.cc的运行流程为例,建议下载学习):
👉 https://www.jianguoyun.com/p/Dc1MEhMQ-9KLBxjM3uED

请添加图片描述
此外,还有大佬已经中文注释了ORB_SLAM2可以参考理解代码:
👉 https://github.com/electech6/ORB_SLAM2_detailed_comments/tree/master

但是在学习以上的核心的主要流程之前,需要先熟悉ORB-SLAM2中的System主类和多线程…

2 System主类

System类是ORB-SLAM2系统的主类,主要代码是头文件ORB_SLAM2/include/System.h和源文件ORB_SLAM2/src/System.cc,分析其主要的成员函数和成员变量。

2.1 成员函数

vscode打开System.cc文件,如下,可以看到成员函数的大纲:

请添加图片描述
具体成员函数的类型和定义如下:

成员函数类型定义
System(const string &strVocFile, string &strSettingsFile, const eSensor sensor, const bool bUseViewer=true)public构造System函数
cv::Mat TrackStereo(const cv::Mat &imLeft, const cv::Mat &imRight, const double &timestamp)public跟踪双目相机,返回相机位姿
cv::Mat TrackRGBD(const cv::Mat &im, const cv::Mat &depthmap, const double &timestamp)public跟踪RGBD相机,返回相机位姿
cv::Mat TrackMonocular(const cv::Mat &im, const double &timestamp)public跟踪单目相机,返回相机位姿
void ActivateLocalizationMode()public开启纯定位模式
void DeactivateLocalizationMode()public关闭纯定位模式
bool System::MapChanged()public检测地图是否有较大变化
void System::Reset()public系统复位
void System::Shutdown()public系统关闭
void System::SaveTrajectoryTUM(const string &filename)publicTUM格式保存相机运动轨迹
void System::SaveKeyFrameTrajectoryTUM(const string &filename)publicTUM格式保存关键帧位姿
void System::SaveTrajectoryKITTI(const string &filename)publicKITTI格式保存相机运动轨迹
int System::GetTrackingState()public获取追踪器状态
vector<MapPoint*> System::GetTrackedMapPoints()public获取追踪到的地图点
vector<cv::KeyPoint> System::GetTrackedKeyPointsUn()public获取追踪到的关键帧的点

2.2 成员变量

主要的成员变量及其定义如下:

成员变量类型定义
eSensor mSensorprivate传感器类型单目相机MONOCULAR,双目相机STEREO,彩色深度相机RGBD
ORBVocabulary* mpVocabularyprivateORB字典,保存ORB描述子聚类结果
KeyFrameDatabase* mpKeyFrameDatabaseprivate关键帧数据库,保存ORB描述子倒排索引
Map* mpMapprivate地图
Tracking* mpTrackerprivate追踪器
LocalMapping* mpLocalMapperprivate局部建图器
std::thread* mptLocalMappingprivate局部建图线程
LoopClosing* mpLoopCloserprivate回环检测器
std::thread* mptLoopClosingprivate回环检测线程
Viewer* mpViewerprivate查看器
FrameDrawer* mpFrameDrawerprivate帧绘制器
MapDrawer* mpMapDrawerprivate地图绘制器
std::thread* mptViewerprivate查看器线程
int mTrackingStateprivate追踪状态
std::mutex mMutexStateprivate追踪状态加锁
bool mbActivateLocalizationModeprivate开启纯定位模式
bool mbDeactivateLocalizationModeprivate关闭纯定位模式
std::mutex mMutexModeprivate纯定位模式加锁
bool mbResetprivate系统复位
std::mutex mMutexResetprivate系统复位加锁

都说ORB-SLAM2有三大线程TrackingLocalMappingLoopClosing线程,可从成员变量中只定义了LocalMappingLoopClosing线程,其实Tracking线程就是Syetem类的主线程,构成三大线程,虽然Tracking线程在代码实现上是主线程,但三者的关系其实是并发的。

3 多线程

刚刚学习到ORB-SLAM2中主要有三大线程,其实SLAM项目中一般都会使用多线程,由于某个节点可能同时订阅多个消息,或多个线程函数共享数据,为了防止在多个消息被订阅时发生处理时间过长或阻塞,而导致其他回调函数无法正常使用,也为了防止共享数据时在存储或调用时发生错乱,一般都会使用std::mutex(互斥锁)std::thread(多线程管理)

3.1 ORB-SLAM2中的多线程

ORB-SLAM2中三大线程中的Tracking线程产生关键帧的频率和时机不是固定的,三个线程同时运行,方便LocalMappingLoopClosing线程查询Tracking线程是否产生关键帧。

// Tracking线程主函数
void Tracking::Track() {
	// 进行跟踪
    // ...
	
    // 若跟踪成功,根据条件判定是否产生关键帧
    if (NeedNewKeyFrame())
        // 产生关键帧并将关键帧传给LocalMapping线程
        KeyFrame *pKF = new KeyFrame(mCurrentFrame, mpMap, mpKeyFrameDB);
        mpLocalMapper->InsertKeyFrame(pKF);	
}

// LocalMapping线程主函数
void LocalMapping::Run() {
	// 死循环
    while (1) {
        // 判断是否接收到关键帧
        if (CheckNewKeyFrames()) {
            // 处理关键帧
            // ...
            
            // 将关键帧传给LoopClosing线程
            mpLoopCloser->InsertKeyFrame(mpCurrentKeyFrame);
        }
        
        // 线程暂停3毫秒,3毫秒结束后再从while(1)循环首部运行
        std::this_thread::sleep_for(std::chrono::milliseconds(3));
    }
}

// LoopClosing线程主函数
void LoopClosing::Run() {
    // 死循环
    while (1) {
        // 判断是否接收到关键帧
        if (CheckNewKeyFrames()) {
            // 处理关键帧
            // ...
        }

        // 查看是否有外部线程请求复位当前线程
        ResetIfRequested();

        // 线程暂停5毫秒,5毫秒结束后再从while(1)循环首部运行
        std::this_thread::sleep_for(std::chrono::milliseconds(5));
    }
}

3.2 加锁

多线程一般都是和锁一起使用,ORB-SLAM2中多线程和互斥锁一起使用,而互斥锁是有范围的,锁的有效性仅限于大括号{}之内,程序运行出大括号之后就释放锁。另外,一把锁一般在某个时刻只有一个线程能够拿到,比如程序执行到某个需要锁的范围,但是锁正在另一个线程,那当前线程就会先停下来,直到其他线程释放这个锁,当前线程才能继续向下运行。

void KeyFrame::EraseConnection(KeyFrame *pKF) {
    // 以下大括号中的代码部分加锁
    {
        unique_lock<mutex> lock(mMutexConnections);
        if (mConnectedKeyFrameWeights.count(pKF)) {
            mConnectedKeyFrameWeights.erase(pKF);
            bUpdate = true;
        }
    }// 程序运行到这里就释放锁,比如下行代码未在加锁范围
	
    UpdateBestCovisibles();
}

至此,学习了ORB-SLAM2中的System主类的实现细节和ORB-SLAM2中的多线程。后续在此基础上继续学习ORB-SLAM2中的输入预处理部分的核心—特征点的提取、描述子的生成及特征点匹配等等。


Reference:

  • https://github.com/raulmur/ORB_SLAM2



须知少时凌云志,曾许人间第一流。



⭐️👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍🌔

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

8月16日上课内容 部署LVS-DR群集

本章结构&#xff1a; 数据包流向分析: 数据包流向分析&#xff1a; &#xff08;1&#xff09;客户端发送请求到 Director Server&#xff08;负载均衡器&#xff09;&#xff0c;请求的数据报文&#xff08;源 IP 是 CIP,目标 IP 是 VIP&#xff09;到达内核空间。 &#xf…

追踪工时和控制成本 如何选对工具

研发工作中的工时管理软件是一种用于追踪、记录和分析团队成员在项目中所花费的工作时间的工具。它有助于组织、监控和优化研发项目的进展&#xff0c;确保资源得到有效利用&#xff0c;项目按时完成&#xff0c;并提供数据支持用于决策制定和资源规划。 能够记录团队成员的工…

Visual Studio 2022 你必须知道的实用调试技巧

目录 1、什么是bug&#xff1f; 2.调试是什么&#xff1f;有多重要&#xff1f; 2.1我们是如何写代码的&#xff1f; 2.2又是如何排查出现的问题的呢&#xff1f; ​编辑 2.3 调试是什么&#xff1f; 2.4调试的基本步骤 2.5Debug和Release的介绍 3.Windows环境调试介绍…

[Vue]解决npm run dev报错node:internal/modules/cjs/loader:1031 throw err;

解决: 有2中方法&#xff0c;建议先尝试第一种&#xff0c;不行再第二种 第一种: 重新安装依赖环境 删除项目的node_modules文件夹&#xff0c;重新执行 # 安装依赖环境 npm install# 运行 npm run dev 我只用了第一种方法就可以了 &#xff0c;第二种方法从别的博主那看到…

QT中的按钮控件Buttons介绍

目录 Buttons 按钮控件 1、常用属性介绍 2、按钮介绍 2.1QPushButton 普通按钮 2.2QtoolButton 工具按钮 2.3Radio Button单选按钮 2.4CheckButton复选按钮 2.5Commam Link Button命令链接按钮 2.6Dialog Button Box命令链接按钮 Buttons 按钮控件 在Qt里&#xff0c;…

【JavaEE进阶】SpringMVC

文章目录 一. 简单认识SpringMVC1. 什么是SpringMVC?2. SpringMVC与MVC的关系 二. SpringMVC1. SpringMVC创建和连接2. SpringMVC的简单使用2.1 RequestMapping 注解介绍2.2 RequestMapping支持的请求类型2.3 GetMapping 和 PostMapping 3. 获取参数3.1 传递单个参数3.2 传递对…

【1-3章】Spark编程基础(Python版)

课程资源&#xff1a;&#xff08;林子雨&#xff09;Spark编程基础(Python版)_哔哩哔哩_bilibili 第1章 大数据技术概述&#xff08;8节&#xff09; 第三次信息化浪潮&#xff1a;以物联网、云计算、大数据为标志 &#xff08;一&#xff09;大数据 大数据时代到来的原因…

如何编写一个通用的函数?

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;&#x1f35f;&#x1f32f;C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 金句分享:…

Java 项目日志实例:Log4j2

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ Apache Log4j 2 是对 Log4j 的升级&#xff0c;与其前身 Log4j 1.x 相比有了显着的改进&#xff0c;并提供了许多 Logback 可用的改进&#xff0c;同时支持 JCL 以及 SLF4J…

Git:本地仓库创建和远程绑定

创建远程仓库 登录git网站&#xff0c;创建一个远程仓库 创建时可以选择仓库属性&#xff0c;公共/私有。仓库命名之类。创建完毕后可以在网站上看到仓库所在网址。 创建本地仓库 打开一个文件夹&#xff0c;鼠标右键Git Bash Here&#xff0c;打开git的命令行 git init//…

AWS security 培训笔记

云计算的好处 Amazon S3 (Storage) Amazon EC2 (Compute) 上图aws 的几个支柱&#xff1a;安全是其中一个啦 其中安全有几个方面 IAMdetection基础架构保护数据保护应急响应 关于云供应商的责任 data center 原来长这样 &#xff0c;据说非常之隐蔽的 如果有天退役了&#xf…

wustojc2010两小时学完C语言

#include <stdio.h> int main() {int a,b,c;scanf("%d%d%d",&a,&b,&c);printf("%d",a-b*c);return 0;}

selenium语法进阶+常用API

目录 浏览器操作 浏览器回退&#xff0c;前进 与刷新 浏览器窗口设置大小 浏览器设置宽高 浏览器窗口最大化 浏览器控制滚动条 信息打印 打印页面的标题和当前页面的URL 定位一组元素 鼠标和键盘事件 键盘 鼠标 下拉框操作 通过索引定位&#xff08;se…

Ubuntu20 ctrl+alt+T无法打开终端

事情是这样的&#xff0c;某天改了下python版本&#xff0c;发现linux默认打开终端的快捷键ctrlaltT寄了&#xff0c;网上给出的都是修改快捷键不出意外肯定没用 但是幸好我们是会分析的&#xff0c;我看到&#xff0c;很多回答说新增一个快捷键运行的命令是gnome-terminal&…

【ROS】话题通信--从理论介绍到模型实现(C++)

1.简单介绍 话题通信是ROS中使用频率最高的一种通信模式&#xff0c;话题通信是基于发布订阅模式的&#xff0c;也即:一个节点发布消息&#xff0c;另一个节点订阅该消息。像雷达、摄像头、GPS… 等等一些传感器数据的采集&#xff0c;也都是使用了话题通信&#xff0c;换言之…

Android开发基础知识总结(一)初识安卓Android Studio

一.基础理论知识 1.Linux相当于是地基。 MIUI&#xff0c;EMUI等操作系统&#xff0c;是基于安卓的改版——且裁掉了一部分Google的服务。 &#xff08;鸿蒙虽然是改版&#xff0c;但和安卓的架构基本上一致&#xff09; 2.Kotlin和Java都是JVM语言&#xff0c;必须先复习好…

6.RocketMQ之消费索引文件ConsumeQueue

功能&#xff1a;作为CommitLog文件的索引文件。 本文着重分析为consumequeue/topic/queueId目录下的索引文件。 1.ConsumeQueueStore public class ConsumeQueueStore {protected final ConcurrentMap<String>, ConcurrentMap<Integer>, ConsumeQueueInterface…

使用 Node.js 生成优化的图像格式

使用 Node.js 生成优化的图像格式 图像是任何 Web 应用程序的重要组成部分&#xff0c;但如果优化不当&#xff0c;它们也可能成为性能问题的主要根源。在本文中&#xff0c;我们将介绍如何使用 Node.js 自动生成优化的图像格式&#xff0c;并以最适合用户浏览器的格式显示它们…

Spring Clould 网关 - Gateway

视频地址&#xff1a;微服务&#xff08;SpringCloudRabbitMQDockerRedis搜索分布式&#xff09; Gateway网关-网关作用介绍&#xff08;P35&#xff09; Spring Cloud Gateway 是 Spring Cloud 的一个全新项目&#xff0c;该项目是基于 Spring 5.0&#xff0c;Spring Boot 2…

【数据挖掘】使用 Python 分析公共数据【01/10】

一、说明 本文讨论了如何使用 Python 使用 Pandas 库分析官方 COVID-19 病例数据。您将看到如何从实际数据集中收集见解&#xff0c;发现乍一看可能不那么明显的信息。特别是&#xff0c;本文中提供的示例说明了如何获取有关疾病在不同国家/地区传播速度的信息。 二、准备您的…