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

news2024/11/17 1:52:24

目录

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-CNN
    DynaSLAM::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和mask
    if (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 COMPILEDWITHC11
        std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
#else
        std::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 复制到 maskRCNNdil
            cv::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 COMPILEDWITHC11
        std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now();
#else
        std::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.coloradmin.cn/o/734341.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Leetcode】707. 设计链表

单向链表 class ListNode:def __init__(self, val0, nextNone):self.val valself.next nextclass MyLinkedList:def __init__(self):self.dummy_head ListNode()self.size 0def get(self, index):if index < 0 or index > self.size:return -1current self.dummy_h…

【简单认识LVS+Keepalived负载均衡高可用群集】

文章目录 一、Keepalived高可用详解1、简介2、原理3、Keepalived体系主要模块及其作用&#xff1a; 二、LVSKeepalived 高可用群集部署实例1.配置NFS共享存储器2.配置节点web服务&#xff08;两台的配置相同&#xff09;&#xff08;1&#xff09;配置虚拟 IP 地址&#xff08;…

飞桨黑客松 OpenVINO™ 任务获奖者经验分享 | 基于OpenVINO™ 与PaddleOCR的结构化输出Pipeline...

点击蓝字 关注我们,让开发变得更有趣 作者 | 张一乔 排版 | 李擎 OpenVINO™ 1. 黑客松活动介绍 01 第四季飞桨黑客松(PaddlePaddle Hackathon Season 4)是由百度联合合作伙伴共同举办的开源深度学习框架类黑客松活动。本次活动旨在为全球开发者提供一个交流、合作和创新的机会…

Django_模型类详解(七)

目录 一、定义属性 字段类型 选项 二、查询集 两大特性 查询集的缓存 限制查询集 三、条件查询 条件运算符 1) 查询相等 2) 模糊查询 3) 空查询 4) 范围查询 5) 比较查询 6) 日期查询 F对象 Q对象 聚合函数 四、关联查询 通过对象执行关联查询 通过模型类执…

线程池介绍

1、什么是线程池 例子&#xff1a; 10年前单核CPU电脑&#xff0c;假的多线程&#xff0c;像马戏团小丑玩多个球&#xff0c;CPU需要来回切换。 现在是多核电脑&#xff0c;多个线程各自跑在独立的CPU上&#xff0c;不用切换效率高。 线程池的优势&#xff1a; 线程池做的工作…

七、VPN技术之密码学基础(密码体制、对称加密算法、非对称加密算法)

更多网络基础内容可见: 网络基础学习目录及各章节指引 7.1 密码学基础 7.1.1 基础概念 密码:对文本进行编码,使偷窥者无法识别的算法。是一套编码方案,一种特殊的报文编码和相应的解码方式的结合体。 加密之前的原始报文称为明文,使用密码之后的报文叫密文。一个简单的例…

elk高并发架构

1.前言 普通的elk架构只适合数据量小的情景&#xff0c;而且也不安全&#xff0c;在瞬时数据量大的情况下可能会导致logstash崩溃&#xff0c;从而导致数据的丢失&#xff0c;对于数据安全有较高要求&#xff0c;可以在架构中加入消息队列&#xff0c;既可以防止瞬时的大流量并…

有过JVM调优经验吗【面试题】

写作目的 JVM其实比较偏理论的&#xff0c;日常工作中很少遇到。但是面试他问&#xff0c;所以需要自己mock一下场景进行准备这个问题的回复。 本次分析的场景的元空间太小导致频繁FGC的问题。 源码&启动参数 gitee下载源码 启动-调优前 nohup java -XX:MetaspaceS…

【MySQL】SQL索引失效的几种场景及优化

MySQL中提高性能的一个最有效的方式是对数据表设计合理的索引。索引提供了高效访问数据的方法&#xff0c;并且加快查询的速度&#xff0c; 因此索引对查询的速度有着至关重要的影响。 使用索引可以快速地定位表中的某条记录&#xff0c;从而提高数据库查询的速度&#xff0c;…

C++之函数模板高级用法(一百五十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

两个好用到爆的Python模块,建议收藏!

在日常开发工作中&#xff0c;经常会遇到这样的一个问题&#xff1a;要对数据中的某个字段进行匹配&#xff0c;但这个字段有可能会有微小的差异。比如同样是招聘岗位的数据&#xff0c;里面省份一栏有的写“广西”&#xff0c;有的写“广西壮族自治区”&#xff0c;甚至还有写…

基于单片机的智能鞋柜的设计与实现

功能介绍 以51单片机作为主控系统&#xff1b;通过DHT11温湿度采集&#xff1b;通过按键设置逻辑处理&#xff1b;通过LED紫外线消毒&#xff1b;通过继电器控制风扇进行换气除湿&#xff1b;通过继电器控制加热片进行加热&#xff1b;整个电路以5v供电; 电路图 PCB 源代码 #i…

nodejs 读取xlsx 文件转json 格式(包含表格时间类型)

需求概要&#xff1a;从xlsx 文件中读取内容转化成想要的json 格式&#xff0c;用于web 读取数据 newDoc.xlsx文档内容大概&#xff1a; 本内容主要是更新前端公告内容&#xff0c; const xlsx require(node-xlsx) const fs require(fs) const moment require(moment)//转换…

双非本大二上岸大厂——念念不忘,必有回响

⭐️前言⭐️ 博主就读于一所普通的学校&#xff08;双非本&#xff09;&#xff0c;在大二下学期3月份开始网上投递简历&#xff0c;历时近百余天&#xff0c;投递简历500&#xff0c;面试近40余场&#xff0c;最终在6月份学期末&#xff0c;斩获了两个大厂offer&#xff08;北…

最小栈——力扣155

方法&#xff1a;辅助栈 这些函数中只有求最小值函数需要借助辅助栈 代码如下&#xff1a; class MinStack {stack<int> x_stack;stack<int> min_stack; public:MinStack() {min_stack.push(INT_MAX);}void push(int val) {x_stack.push(val);min_stack.push(…

使用Java计算课程绩点、课程学分绩点、总绩点

1、定义实体类 实体类中包括属性表 名称释义xuefen该课程学分chengji该课程取得的成绩xuefenjidian该课程取得的学分绩点xuefen该课程取得的学分 其中有式子&#xff1a; j i d i a n ( c h e n g j i − 50 ) 10.0 jidian \frac{(chengji-50)}{10.0} jidian10.0(chengji−…

【Azure】解析 Microsoft Defender for Cloud:云安全的保护与管理

你在使用自己的电脑的时候&#xff0c;作为安全防护你可能直接装个杀毒软件&#xff0c;或者什么xx管家之类的&#xff0c;那么你是否有想过&#xff0c;如果我有一套云服务之后&#xff0c;我应该如何进行安全防护呢&#xff1f;本文带你了解在 Azure 云中的安全防护体系&…

同余最短路

同余最短路就是把每一个同余类当成一个结点&#xff0c;在同余类之间建边&#xff0c;然后跑最短路 答案统计的时候对每个同余类单独计算贡献 题意&#xff1a; 思路&#xff1a; 答案可以对模X的所有同余类计算贡献 设dis[i]为在模X意义下&#xff0c;Y和Z之后%X余数为i的…

数据库练习

数据库练习 建立三张表&#xff0c;以及表中的联系 由于学生表中存在外键&#xff0c;所以我们需要先创建课程表和班级表 课程表 mysql> create table course(-> course_id int primary key auto_increment comment 课程编号,-> course_name varchar(10) not null…

【C++初阶】C++入门——引用

文章目录 一、引用的概念二、共用同一块空间验证三、引用的特性3.1 引用在定义时必须初始化3.2 一个变量可以有多个引用3.3 引用不能改变 四、引用的使用场景4.1 做参数4.2 做返回值 五、传值、传引用效率比较六、常引用6.1 权限放大——不被允许6.2 权限平移6.3 权限缩小6.4 赋…