目录
整体函数
System::System(const string &strVocFile, const string &strSettingsFile, const eSensor sensor, const bool bUseViewer) :
mSensor(sensor), mpViewer(static_cast<Viewer *>(NULL)), mbReset(false), mbActivateLocalizationMode(false), mbDeactivateLocalizationMode(false) {
// step1. 初始化各成员变量
// step1.1. 读取配置文件信息
cv::FileStorage fsSettings(strSettingsFile.c_str(), cv::FileStorage::READ);
// step1.2. 创建ORB词袋
mpVocabulary = new ORBVocabulary();
// step1.3. 创建关键帧数据库,主要保存ORB描述子倒排索引(即根据描述子查找拥有该描述子的关键帧)
mpKeyFrameDatabase = new KeyFrameDatabase(*mpVocabulary);
// step1.4. 创建地图
mpMap = new Map();
// step2. 创建3大线程: Tracking、LocalMapping和LoopClosing
// step2.1. 主线程就是Tracking线程,只需创建Tracking对象即可
mpTracker = new Tracking(this, mpVocabulary, mpFrameDrawer, mpMapDrawer, mpMap, mpKeyFrameDatabase, strSettingsFile, mSensor);
// step2.2. 创建LocalMapping线程及mpLocalMapper
mpLocalMapper = new LocalMapping(mpMap, mSensor==MONOCULAR);
mptLocalMapping = new thread(&ORB_SLAM2::LocalMapping::Run, mpLocalMapper);
// step2.3. 创建LoopClosing线程及mpLoopCloser
mpLoopCloser = new LoopClosing(mpMap, mpKeyFrameDatabase, mpVocabulary, mSensor!=MONOCULAR);
mptLoopClosing = new thread(&ORB_SLAM2::LoopClosing::Run, mpLoopCloser);
// step3. 设置线程间通信
mpTracker->SetLocalMapper(mpLocalMapper);
mpTracker->SetLoopClosing(mpLoopCloser);
mpLocalMapper->SetTracker(mpTracker);
mpLocalMapper->SetLoopCloser(mpLoopCloser);
mpLoopCloser->SetTracker(mpTracker);
mpLoopCloser->SetLocalMapper(mpLocalMapper);
}
该构造函数负责初始化视觉里程计系统
各部分以及作用
构造函数声明
System::System(const string &strVocFile, const string &strSettingsFile, const eSensor sensor, const bool bUseViewer)
: mSensor(sensor), mpViewer(static_cast<Viewer *>(NULL)), mbReset(false), mbActivateLocalizationMode(false), mbDeactivateLocalizationMode(false) {
初始化列表
mSensor(sensor)
:将传入的传感器类型sensor
赋值给成员变量mSensor
。mpViewer(static_cast<Viewer *>(NULL))
:将成员变量mpViewer
初始化为nullptr
。mbReset(false)
:将成员变量mbReset
初始化为false
。mbActivateLocalizationMode(false)
:将成员变量mbActivateLocalizationMode
初始化为false
。mbDeactivateLocalizationMode(false)
:将成员变量mbDeactivateLocalizationMode
初始化为false
。
构造函数体
Step 1: 初始化各成员变量
-
读取配置文件信息:
cv::FileStorage fsSettings(strSettingsFile.c_str(), cv::FileStorage::READ);
cv::FileStorage
:OpenCV 提供的一个类,用于读取和写入 XML 或 YAML 文件。- 参数:
strSettingsFile.c_str()
:配置文件的路径,转换为 C 风格字符串。cv::FileStorage::READ
:表示以读取模式打开文件。 - 作用:读取配置文件
strSettingsFile
,并将文件内容加载到fsSettings
对象中
-
创建 ORB 词袋:
mpVocabulary = new ORBVocabulary();
ORBVocabulary
:一个类,用于创建和管理 ORB 词袋。- 作用:创建一个新的
ORBVocabulary
对象,并将其指针赋值给mpVocabulary
-
创建关键帧数据库:
mpKeyFrameDatabase = new KeyFrameDatabase(*mpVocabulary);
KeyFrameDatabase
:一个类,用于管理关键帧和它们的描述子。- 参数:
*mpVocabulary
:传递已创建的 ORB 词袋对象。 - 作用:创建一个新的
KeyFrameDatabase
对象,并将其指针赋给mpKeyFrameDatabase
。关键帧数据库用于保存 ORB 描述子的倒排索引,以便快速查找关键帧。
-
创建地图:
mpMap = new Map();
Map
:一个类,用于管理地图中的关键帧和路标点。- 作用:创建一个新的
Map
对象,并将其指针赋值给mpMap
。
Step 2: 创建三大线程
-
创建 Tracking 线程:
mpTracker = new Tracking(this, mpVocabulary, mpFrameDrawer, mpMapDrawer, mpMap, mpKeyFrameDatabase, strSettingsFile, mSensor);
Tracking
:一个类,负责相机的跟踪任务。- 参数:
this
:当前System
对象的指针。mpVocabulary
:ORB 词袋对象的指针。mpFrameDrawer
:帧绘制对象的指针。mpMapDrawer
:地图绘制对象的指针。mpMap
:地图对象的指针。mpKeyFrameDatabase
:关键帧数据库对象的指针。strSettingsFile
:配置文件的路径。mSensor
:传感器类型。
- 作用:创建一个新的
Tracking
对象,并将其指针赋值给mpTracker
。Tracking
线程负责跟踪相机的位置和姿态。
-
创建 LocalMapping 线程:
mpLocalMapper = new LocalMapping(mpMap, mSensor == MONOCULAR); mptLocalMapping = new thread(&ORB_SLAM2::LocalMapping::Run, mpLocalMapper);
LocalMapping
:一个类,负责局部地图的构建和优化。- 参数:
mpMap
:地图对象的指针。mSensor == MONOCULAR
:一个布尔值,表示传感器类型是否为单目。
- 作用:创建一个新的
LocalMapping
对象,并将其指针赋值给mpLocalMapper
。 std::thread
:创建一个新的线程,调用LocalMapping
对象的Run
方法。- 参数:
&ORB_SLAM2::LocalMapping::Run
:指向LocalMapping
类的Run
方法的指针。mpLocalMapper
:传递LocalMapping
对象的指针。
- 作用:启动
LocalMapping
线程,开始局部地图的构建和优化
-
创建 LoopClosing 线程:
mpLoopCloser = new LoopClosing(mpMap, mpKeyFrameDatabase, mpVocabulary, mSensor != MONOCULAR); mptLoopClosing = new thread(&ORB_SLAM2::LoopClosing::Run, mpLoopCloser);
LoopClosing
:一个类,负责检测和修正闭环。- 参数:
mpMap
:地图对象的指针。mpKeyFrameDatabase
:关键帧数据库对象的指针。mpVocabulary
:ORB 词袋对象的指针。mSensor != MONOCULAR
:一个布尔值,表示传感器类型是否为非单目。
- 作用:创建一个新的
LoopClosing
对象,并将其指针赋值给mpLoopCloser
。 std::thread
:创建一个新的线程,调用LoopClosing
对象的Run
方法。- 参数:
&ORB_SLAM2::LoopClosing::Run
:指向LoopClosing
类的Run
方法的指针。mpLoopCloser
:传递LoopClosing
对象的指针。
- 作用:启动
LoopClosing
线程,开始闭环检测和修正。
Step 3: 设置线程间通信
-
设置 Tracker 和 LocalMapper 之间的通信:
mpTracker->SetLocalMapper(mpLocalMapper);
- 将
LocalMapping
对象的指针传递给Tracking
对象,以便Tracking
可以与LocalMapping
通信。
- 将
-
设置 Tracker 和 LoopClosing 之间的通信:
mpTracker->SetLoopClosing(mpLoopCloser);
- 将
LoopClosing
对象的指针传递给Tracking
对象,以便Tracking
可以与LoopClosing
通信。
- 将
-
设置 LocalMapper 和 Tracker 之间的通信:
mpLocalMapper->SetTracker(mpTracker);
- 将
Tracking
对象的指针传递给LocalMapping
对象,以便LocalMapping
可以与Tracking
通信。
- 将
-
设置 LocalMapper 和 LoopClosing 之间的通信:
mpLocalMapper->SetLoopClosing(mpLoopCloser);
- 将
LoopClosing
对象的指针传递给LocalMapping
对象,以便LocalMapping
可以与LoopClosing
通信。
- 将
-
设置 LoopClosing 和 Tracker 之间的通信:
mpLoopCloser->SetTracker(mpTracker);
- 将
Tracking
对象的指针传递给LoopClosing
对象,以便LoopClosing
可以与Tracking
通信。
- 将
-
设置 LoopClosing 和 LocalMapper 之间的通信:
mpLoopCloser->SetLocalMapper(mpLocalMapper);
- 将
LocalMapping
对象的指针传递给LoopClosing
对象,以便LoopClosing
可以与LocalMapping
通信。
- 将
相关C++基础知识
new
操作符
new
操作符在 C++ 中用于动态分配内存。与静态分配(在栈上分配内存)不同,new
在堆上分配内存,并返回指向该内存的指针。这意味着通过 new
分配的内存不会在函数结束时自动释放,需要手动使用 delete
操作符来释放内存。
基本用法
1. 分配单个对象
int *ptr = new int; // 分配一个 int 类型的内存,并返回指向该内存的指针
*ptr = 10; // 给分配的内存赋值
2. 分配数组
int *array = new int[5]; // 分配一个包含 5 个 int 类型元素的数组
for (int i = 0; i < 5; ++i) {
array[i] = i; // 给数组元素赋值
}
释放内存
1. 释放单个对象
delete ptr; // 释放通过 new 分配的单个对象的内存
2. 释放数组
delete[] array; // 释放通过 new[] 分配的数组的内存
构造函数和析构函数
当使用 new
分配对象时,会调用该对象的构造函数。同样,当使用 delete
释放对象时,会调用该对象的析构函数。
class MyClass {
public:
MyClass() {
std::cout << "Constructor called" << std::endl;
}
~MyClass() {
std::cout << "Destructor called" << std::endl;
}
};
int main() {
MyClass *obj = new MyClass(); // 调用 MyClass 的构造函数
delete obj; // 调用 MyClass 的析构函数
return 0;
}
动态分配和智能指针
为了避免内存泄漏, C++ 推荐使用智能指针(如 std::unique_ptr
和 std::shared_ptr
)来管理动态分配的内存。
使用 std::unique_ptr
#include <memory>
int main() {
std::unique_ptr<int> ptr(new int); // 使用 unique_ptr 管理动态分配的内存
*ptr = 10;
return 0;
} // 当 ptr 离开作用域时,内存会自动释放
使用 std::shared_ptr
#include <memory>
int main() {
std::shared_ptr<int> ptr(new int); // 使用 shared_ptr 管理动态分配的内存
*ptr = 10;
return 0;
} // 当最后一个 shared_ptr 离开作用域时,内存会自动释放
常见用途
- 动态数组:当数组大小在编译时未知时,可以使用
new
动态分配数组。 - 对象池:在需要频繁创建和销毁对象的场景中,可以使用对象池来提高性能。
- 多态对象:当需要创建多态对象时,可以使用
new
分配基类指针指向派生类对象。
MyClass
类
class MyClass {
public:
// 构造函数
MyClass() {
std::cout << "Constructor called" << std::endl;
}
// 析构函数
~MyClass() {
std::cout << "Destructor called" << std::endl;
}
// 成员方法
void display() {
std::cout << "Displaying MyClass object" << std::endl;
}
};
示例代码
让我们通过一个完整的示例来展示 MyClass
类的使用:
#include <iostream>
class MyClass {
public:
// 构造函数
MyClass() {
std::cout << "Constructor called" << std::endl;
}
// 析构函数
~MyClass() {
std::cout << "Destructor called" << std::endl;
}
// 成员方法
void display() {
std::cout << "Displaying MyClass object" << std::endl;
}
};
int main() {
// 动态分配单个对象
MyClass *obj = new MyClass();
// 通过指针调用对象的方法
obj->display(); // 等价于 (*obj).display();
// 释放内存
delete obj;
return 0;
}
输出结果
运行这段代码后,控制台的输出可能是:
Constructor called
Displaying MyClass object
Destructor called
解释
-
构造函数调用:
MyClass *obj = new MyClass();
:创建一个MyClass
对象,并将其指针赋值给obj
。此时会调用MyClass
的构造函数,输出Constructor called
。
-
调用
display
方法:obj->display();
:通过指针obj
调用MyClass
对象的display
方法,输出Displaying MyClass object
。- 等价形式:
(*obj).display();
,先通过指针obj
获取指向的对象,然后调用该对象的display
方法。
-
析构函数调用:
delete obj;
:释放通过new
分配的MyClass
对象的内存。此时会调用MyClass
的析构函数,输出Destructor called
。
总结
MyClass
类:定义了一个简单的类,包含构造函数、析构函数和一个成员方法display
。display
方法:用于显示MyClass
对象的信息。- 指针调用方法:通过指针
obj
调用对象的方法display
,使用->
运算符。
->
运算符
->
运算符在 C++ 中用于通过指针访问对象的成员(方法或属性)。它结合了指针解引用和成员访问两个操作。
基本用法
1. 访问对象的成员方法
class MyClass {
public:
void display() {
std::cout << "Displaying MyClass object" << std::endl;
}
};
int main() {
MyClass *obj = new MyClass(); // 动态分配 MyClass 对象
obj->display(); // 通过指针调用 display 方法
delete obj; // 释放内存
return 0;
}
2. 访问对象的数据成员
class MyClass {
public:
int value;
};
int main() {
MyClass *obj = new MyClass(); // 动态分配 MyClass 对象
obj->value = 10; // 通过指针访问并设置 value 成员
std::cout << "Value: " << obj->value << std::endl; // 通过指针访问 value 成员
delete obj; // 释放内存
return 0;
}
工作原理
->
运算符的工作原理可以分解为两个步骤:
- 指针解引用:将指针转换为对象。
- 成员访问:访问对象的成员。
例如,obj->display();
等价于 (*obj).display();
。
*obj
:解引用指针obj
,得到它所指向的对象。.display()
:访问对象的display
方法。
等价形式
(*obj).display(); // 等价于 obj->display();
(*obj).value = 10; // 等价于 obj->value = 10;