DynaSLAM代码详解(1) — RGBD模式DynaSLAM运行流程

目录

1.1 DynaSLAM和ORB-SLAM2文件对比

1.2 RGBD模式运行流程


论文翻译地址:动态SLAM论文(2) — DynaSLAM: Tracking, Mapping and Inpainting in Dynamic Scenes_几度春风里的博客-CSDN博客

 

1.1 DynaSLAM和ORB-SLAM2文件对比

        DynaSLAM是一个建立在ORB-SLAM2基础上的视觉SLAM系统,它增加了动态物体检测和背景修复的能力。DynaSLAM在单目、立体和RGB-D配置下对动态场景非常稳健。能够通过多视角几何、深度学习或两者结合来检测移动物体。拥有场景的静态地图允许修复被这些动态物体遮挡的帧背景。

ORB-SLAM2和DynaSLAM的文件对比如下,红色为DynaSLAM相对于ORB-SLAM2多出的文件。

文件目录文件功能
​​​​​​​pythonMask-RCNN目标检测文件
Conversion.cc包含一些数据类型之间的转换函数,用于在不同类型之间进行数据转换
Converter.cc包含将动态点云数据转换为Dynaslam数据格式的函数
Frame.cc用于表示相机的一帧图像,其中包含了图像的各种属性和特征点
FrameDrawer.cc用于在图像上绘制特征点、相机轨迹等信息
Geometry.cc包含一些几何计算的函数,例如计算两条线段的交点等
Initializer.cc用于初始化相机的位置和姿态
KeyFramer.cc用于管理关键帧的生成和选取
KeyFrameDatabase.cc用于管理关键帧的数据库,用于地图匹配和回环检测
LocalMapping.cc用于局部地图建立和更新
loopClosing.cc用于检测并闭合回环
Map.cc用于管理地图的点云和关键帧
MapPoint.cc用于表示地图中的点云
MaskNet.cc用于进行目标检测和语义分割
MaskNetStereo.cc用于进行立体目标检测和语义分割
Optimizer.cc用于对地图中的点云进行优化
ORBextractor.cc用于提取图像的ORB特征点
ORBmatcher.cc用于进行ORB特征点的匹配
PnPsolver.cc用于求解相机的位置和姿态
RegionProps.cc用于提取图像中的目标区域
Sim3Solver.cc于求解相机的相似变换矩阵
System.cc是整个系统的入口,包含了主要的函数和流程
Tracking.cc用于跟踪相机的运动和定位
Viewer.cc用于可视化显示地图和相机的运动轨迹

1.2 RGBD模式运行流程

笔记将以RGBD模式运行为基础,讲解整个DynaSLAM的运行流程,RGBD模式的运行在 /Example/RGB-D/rgbd_tum.cc文件下。

检查和加载相关的配置文件,首先判断传入的参数数是否符合要求,然后进行变量的声明用于存放彩色图像、深度图像的路径,以及对应的时间戳的变量。

int main(int argc, char **argv)
{// 判断传入的参数数是否符合要求if(argc != 5 && argc != 6 && argc != 7){cerr << endl << "Usage: ./rgbd_tum path_to_vocabulary path_to_settings path_to_sequence path_to_association (path_to_masks) (path_to_output)" << endl;return 1;}// Retrieve paths to images//按顺序存放需要读取的彩色图像、深度图像的路径,以及对应的时间戳的变量vector<string> vstrImageFilenamesRGB;vector<string> vstrImageFilenamesD;vector<double> vTimestamps;...
}

然后加载关联文件,从文件中加载rgb图像路径、时间戳、深度图像路径。

/** 从关联文件中提取这些需要加载的图像的路径和时间戳 
*/
void LoadImages(const string &strAssociationFilename, vector<string> &vstrImageFilenamesRGB,vector<string> &vstrImageFilenamesD, vector<double> &vTimestamps)
{//输入文件流ifstream fAssociation;//打开关联文件fAssociation.open(strAssociationFilename.c_str());//一直读取,直到文件结束while(!fAssociation.eof()){string s;//读取一行的内容到字符串s中getline(fAssociation,s);//如果不是空行就可以分析数据了if(!s.empty()){stringstream ss;ss << s;//字符串格式:  时间戳rgb图像路径 时间戳 深度图像路径double t;string sRGB, sD;ss >> t;vTimestamps.push_back(t);ss >> sRGB;vstrImageFilenamesRGB.push_back(sRGB);ss >> t;ss >> sD;vstrImageFilenamesD.push_back(sD);}}
}

随后开始初始化MaskRCNN网络和ORB-SLAM2系统

    // Initialize Mask R-CNN// 初始化Mask R-CNNDynaSLAM::SegmentDynObject *MaskNet;if (argc==6 || argc==7){cout << "Loading Mask R-CNN. This could take a while..." << endl;MaskNet = new DynaSLAM::SegmentDynObject();cout << "Mask R-CNN loaded!" << endl;}//初始化ORB-SLAM2系统ORB_SLAM2::System SLAM(argv[1],argv[2],ORB_SLAM2::System::RGBD,true);

与ORB-SLAM2的不同:因为有关于图像分割的操作,因此在设置了图像膨胀的相关参数,后面也创建了相关的的文件路径用于TrackRGB中的输出imRGBOut,imDOut,maskOut。

    // Dilation settings// 设置图像膨胀(dilation)的参数,并创建一个膨胀操作的核(kernel)int dilation_size = 15;     // 膨胀的大小为15// 使用getStructuringElement函数创建了一个膨胀操作的核cv::Mat kernel = getStructuringElement(cv::MORPH_ELLIPSE,   //表示椭圆形cv::Size( 2*dilation_size + 1, 2*dilation_size+1 ),  //表示核的大小cv::Point( dilation_size, dilation_size ) );     //表示核的锚点位置// 创建一系列的文件目录用于存放rgb、depth和maskif (argc==7){std::string dir = string(argv[6]);mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);dir = string(argv[6]) + "/rgb/";mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);dir = string(argv[6]) + "/depth/";mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);dir = string(argv[6]) + "/mask/";mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);}

随后开始正式的处理,对图像序列中的每张图像展开遍历,首先从文件中读取RGB、depth和时间戳并检查图像的合法性;随后开始进行图像分割,对分割的结果利用膨胀操作;最后根据不同的参数利用不同的TrackRGBD函数开启跟踪线程,并将跟踪线程输出的结果imRGBOut,imDOut, maskOut 保存到创建的文件路径中。

    //对图像序列中的每张图像展开遍历for(int ni=0; ni<nImages; ni++){// Read image and depthmap from file// 从文件中读取RGB、depth和时间戳imRGB = cv::imread(string(argv[3])+"/"+vstrImageFilenamesRGB[ni],CV_LOAD_IMAGE_UNCHANGED);imD = cv::imread(string(argv[3])+"/"+vstrImageFilenamesD[ni],CV_LOAD_IMAGE_UNCHANGED);double tframe = vTimestamps[ni];// 检查图像的合法性if(imRGB.empty()){cerr << endl << "Failed to load image at: "<< string(argv[3]) << "/" << vstrImageFilenamesRGB[ni] << endl;return 1;}#ifdef COMPILEDWITHC11std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
#elsestd::chrono::monotonic_clock::time_point t1 = std::chrono::monotonic_clock::now();
#endif// Segment out the images// 开始进行图像分割cv::Mat mask = cv::Mat::ones(480,640,CV_8U);if (argc == 6 || argc == 7){cv::Mat maskRCNN;// 利用GetSegmentation()函数进行图像分割maskRCNN = MaskNet->GetSegmentation(imRGB,string(argv[5]),vstrImageFilenamesRGB[ni].replace(0,4,""));// 将分割的结果 maskRCNN 复制到 maskRCNNdilcv::Mat maskRCNNdil = maskRCNN.clone();// 对 maskRCNN 应用膨胀操作,使用 kernel 作为内核cv::dilate(maskRCNN,maskRCNNdil, kernel);// 将 maskRCNNdil 从 mask 中减去,得到最终的mask结果mask = mask - maskRCNNdil;}// Pass the image to the SLAM system// 根据不同的参数利用不同的TrackRGBD函数开启跟踪线程if (argc == 7){SLAM.TrackRGBD(imRGB,imD,mask,tframe,imRGBOut,imDOut,maskOut);}else {SLAM.TrackRGBD(imRGB,imD,mask,tframe);}#ifdef COMPILEDWITHC11std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now();
#elsestd::chrono::monotonic_clock::time_point t2 = std::chrono::monotonic_clock::now();
#endif// 将跟踪线程输出的结果imRGBOut,imDOut,maskOut保存到创建的文件路径中if (argc == 7){cv::imwrite(string(argv[6]) + "/rgb/" + vstrImageFilenamesRGB[ni],imRGBOut);vstrImageFilenamesD[ni].replace(0,6,"");cv::imwrite(string(argv[6]) + "/depth/" + vstrImageFilenamesD[ni],imDOut);cv::imwrite(string(argv[6]) + "/mask/" + vstrImageFilenamesRGB[ni],maskOut);}

最后等待所有的图像处理完成后终止SLAM过程,统计分析追踪耗时和保存最终的相机轨迹。

    // Stop all threads//终止SLAM过程SLAM.Shutdown();// Tracking time statistics//统计分析追踪耗时sort(vTimesTrack.begin(),vTimesTrack.end());float totaltime = 0;for(int ni=0; ni<nImages; ni++){totaltime+=vTimesTrack[ni];}cout << "-------" << endl << endl;cout << "median tracking time: " << vTimesTrack[nImages/2] << endl;cout << "mean tracking time: " << totaltime/nImages << endl;// Save camera trajectory//保存最终的相机轨迹SLAM.SaveTrajectoryTUM("CameraTrajectory.txt");SLAM.SaveKeyFrameTrajectoryTUM("KeyFrameTrajectory.txt");

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据分析 - 基础入门之NumPy⑥】- NumPy案例巩固强化

文章目录 前言一、NumPy基础训练1.1 创建一个长度为10的一维全为0的ndarray对象&#xff0c;并让第5个元素为11.2 创建一个元素为从10到49的ndarray对象1.3 将第2题的所有元素位置反转1.4 创建一个10*10的ndarray对象并打印最大最小元素1.5 创建一个10*10的ndarray对象&#xf…

Java web开发--springboot

Java web开发--springboot Java有很多web框架 但是有的框架不是很好用:比如Java Servlets(个人感觉)不好调试,WEB-INF文件关联来关联去很烦躁,启动后 crtlc还关闭不了(我一般习惯用ctrlc命令来关闭服务).导致后面我调试springboot时一直报错,原来是Java Servlets的服务没关(我习…

CUDA+CUDNN+torch+torchvision安装

弄了好久&#xff0c;终于弄好了&#xff01;&#xff01;&#xff01; 原因&#xff1a;其实之前我是已经配置好pytorch的相关环境的了。但是这段时间&#xff0c;在跑GNN相关论文中的代码时&#xff0c;发现代码中的某个函数要求torch必须得是1.8 而我之前安装的是torch1.1…

SQl排序与分页

1. 排序数据 1.1 排序规则 使用 ORDER BY 子句排序 ASC&#xff08;ascend&#xff09;: 升序DESC&#xff08;descend&#xff09;:降序 ORDER BY 子句在SELECT语句的结尾。 1.2 单列排序 SELECT last_name, job_id, department_id, hire_date FROM employees ORDER…

IDEA使用教程

1. 查看代码历史版本 若要查看特定 Java 类的代码历史版本&#xff0c;请执行以下操作&#xff1a; 鼠标右键点击所需查看的 Java 类。 在弹出菜单中选择 "Local History"&#xff08;本地历史&#xff09; >> "Show History"&#xff08;显示历史…

短视频seo矩阵+抖音小程序源码开源部署(二)

一、 开发思路&#xff1a; 通过短视频seo矩阵抖音小程序的形式&#xff0c;实现视频的批量制作&#xff0c;小程序内容批量挂载&#xff0c;客户线索批量收集&#xff0c;实现企业运营价值最大化。开发逻辑&#xff1a;通过短视频矩阵布局seo搜索关键词&#xff0c;接入小程序…

C/C++图形库EasyX保姆级使用教程(四) 图片的展示与缩放

C/C图形库EasyX保姆级使用教程 第一章 Microsoft Visual Studio 2022和EasyX的下载及安装使用 第二章 图形化窗口设置以及简单图形的绘制 第三章 图形颜色的填充及相关应用 第四章 图片的展示与缩放 文章目录 C/C图形库EasyX保姆级使用教程前言一、图片的展示1.变量存储图片2.…

OpenCV 入门教程:寻找和绘制轮廓

OpenCV 入门教程&#xff1a;寻找和绘制轮廓 导语一、寻找轮廓二、绘制轮廓三、示例应用3.1 目标检测和定位3.2 图像分割 总结 导语 寻找和绘制轮廓是图像处理中常用的技术之一&#xff0c;用于识别、定位和分析图像中的目标区域。在 OpenCV 中&#xff0c;寻找和绘制轮廓可以…

MySQL数据库 - 表的操作

目录 一、创建表 二、创建表案例 1、显示当前使用的数据库名 2、创建表 2.1 MyISAM存储引擎表 2.2 InnoDB存储引擎表 三、查看表结构 四、修改表 1、新增列 2、修改列类型 3、修改列名 4、修改表名 5、删除列 五、删除表 表的操作至少会涉及如下两类SQL语句&…

Linux--调试器:gdb

gcc与g默认动态链接形成的可执行程序&#xff08;比如a.out&#xff09;是release 版本&#xff0c;不可调试&#xff01;&#xff01;&#xff01; 如何搞成debug可调试版本&#xff1f; gcc 程序名 -o 可执行程序名 -g //添加了-g就表明该程序是debug方式发布的 查看可执行…

【Python】面向对象 - 封装 ② ( 访问私有成员 | 对象无法访问私有变量 / 方法 | 类内部访问私有成员 )

文章目录 一、访问私有成员1、对象无法访问私有变量2、对象无法访问私有方法3、类内部访问私有成员 一、访问私有成员 1、对象无法访问私有变量 在下面的 Python 类 Student 中 , 定义了私有的成员变量 , # 定义私有成员__address None该私有成员变量 , 只能在类内部进行访问 …

depot_tools问题记录 - 执行fetch/gclient命令无响应

文章目录 前言开发环境问题描述问题分析解决方案最后 前言 在研究将Dart dill文件序列化为可读文本时遇到的问题。 开发环境 macOS: 13.4 问题描述 之前使用depot_tools中的fetch/gclient命令还是正常的&#xff0c;今天想实测--no-history参数时突然遇到命令无响应的情况…