目录
整体函数
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;
425

被折叠的 条评论
为什么被折叠?



