Dyna-SLAM代码解析:MaskNet.cc

文章详细解读了一段C++代码,涉及时间测量辅助函数、SegmentDynObject类的构造函数(导入MaskR-CNN设置,初始化Python环境和网络)、析构函数(释放资源)以及ImportSettings函数(从YAML文件加载设置)。
摘要由CSDN通过智能技术生成

1、

#define U_SEGSt(a)          \
    gettimeofday(&tvsv, 0); \
    a = tvsv.tv_sec + tvsv.tv_usec / 1000000.0
    struct timeval tvsv;
    double t1sv, t2sv, t0sv, t3sv;
    void tic_initsv() { U_SEGSt(t0sv); }
    void toc_finalsv(double &time)
    {
        U_SEGSt(t3sv);
        time = (t3sv - t0sv) / 1;
    }
    void ticsv() { U_SEGSt(t1sv); }
    void tocsv() { U_SEGSt(t2sv); }
    // std::cout << (t2sv - t1sv)/1 << std::endl;}

这段代码是一组用于测量时间间隔的辅助函数。以下是对代码的解释:

  1. #define U_SEGSt(a) ...:这是一个宏定义,用于简化时间测量的代码。在这个宏定义中,U_SEGSt(a)将被展开为多个语句。

  2. gettimeofday(&tvsv, 0);:这行代码使用gettimeofday函数获取当前时间,并将其保存在结构体tvsv中。gettimeofday是一个用于获取当前时间的系统调用函数,它返回自Unix纪元以来的秒数和微秒数。

  3. a = tvsv.tv_sec + tvsv.tv_usec / 1000000.0:这行代码计算时间戳a,将秒数和微秒数转换为秒,并将其赋值给变量atv_sec表示自Unix纪元以来的秒数,tv_usec表示微秒数。

  4. struct timeval tvsv;:这行代码声明了一个名为tvsvtimeval结构体变量。该结构体用于存储时间的秒数和微秒数。

  5. double t1sv, t2sv, t0sv, t3sv;:这行代码声明了四个double类型的变量t1svt2svt0svt3sv,用于记录时间戳。

  6. void tic_initsv() { U_SEGSt(t0sv); }:这是一个函数,用于初始化时间戳t0sv。调用U_SEGSt宏来获取当前时间,并将其赋值给t0sv

  7. void toc_finalsv(double &time):这是一个函数,用于计算时间间隔。它接受一个double类型的引用参数time,用于返回计算得到的时间。内部通过调用U_SEGSt宏获取当前时间戳,并计算时间间隔,并将结果保存在time变量中。

  8. void ticsv() { U_SEGSt(t1sv); }:这是一个函数,用于记录起始时间戳。调用U_SEGSt宏获取当前时间,并将其赋值给变量t1sv

  9. void tocsv() { U_SEGSt(t2sv); }:这是一个函数,用于记录结束时间戳。调用U_SEGSt宏获取当前时间,并将其赋值给变量t2sv

  10. std::cout << (t2sv - t1sv)/1 << std::endl;:这是一条输出语句,用于计算t2svt1sv之间的时间差,并将结果输出到标准输出流。(t2sv - t1sv)/1表示计算时间差的值,单位为秒。

总结来说,这段代码定义了一些用于测量时间的函数和宏。这些函数使用gettimeofday函数获取当前时间,并将其转换为秒数。通过记录起始时间戳和结束时间戳,可以计算时间间隔。

2、SegmentDynObject::SegmentDynObject() 是一个类构造函数,用于初始化 SegmentDynObject 类的对象。

    SegmentDynObject::SegmentDynObject()
    {
        std::cout << "Importing Mask R-CNN Settings..." << std::endl;
        ImportSettings();
        std::string x;
        setenv("PYTHONPATH", this->py_path.c_str(), 1);
        x = getenv("PYTHONPATH");
        Py_Initialize();
        this->cvt = new NDArrayConverter();
        this->py_module = PyImport_ImportModule(this->module_name.c_str());
        assert(this->py_module != NULL);
        this->py_class = PyObject_GetAttrString(this->py_module, this->class_name.c_str());
        assert(this->py_class != NULL);
        this->net = PyInstance_New(this->py_class, NULL, NULL);
        assert(this->net != NULL);
        std::cout << "Creating net instance..." << std::endl;
        cv::Mat image = cv::Mat::zeros(480, 640, CV_8UC3); // Be careful with size!!
        std::cout << "Loading net parameters..." << std::endl;
        GetSegmentation(image);
    }

下面是对代码的逐行解释:

  1. std::cout << "Importing Mask R-CNN Settings..." << std::endl;:这行代码将字符串 “Importing Mask R-CNN Settings…” 打印到标准输出流,用于显示正在导入 Mask R-CNN 的设置。

  2. ImportSettings();:这行代码调用 ImportSettings() 函数,用于导入设置。该函数可能会执行一些与设置相关的操作,但没有提供代码,无法具体解释其功能。

  3. std::string x;:这行代码声明了一个字符串变量 x,用于存储环境变量的值。

  4. setenv("PYTHONPATH", this->py_path.c_str(), 1);:这行代码设置名为 “PYTHONPATH” 的环境变量的值为 this->py_paththis->py_path 可能是一个存储 Python 模块路径的成员变量。

  5. x = getenv("PYTHONPATH");:这行代码将环境变量 “PYTHONPATH” 的值赋给变量 x

  6. Py_Initialize();:这行代码初始化 Python 解释器,在 C++ 程序中使用 Python。

  7. this->cvt = new NDArrayConverter();:这行代码创建 NDArrayConverter 类的对象,并将指针赋值给 this->cvtNDArrayConverter 是一个用于在 OpenCV 和 Python NumPy 数组之间进行转换的辅助类。

  8. this->py_module = PyImport_ImportModule(this->module_name.c_str());:这行代码导入名为 module_name 的 Python 模块,并将其赋值给 this->py_modulethis->module_name 可能是一个存储模块名称的成员变量。

  9. assert(this->py_module != NULL);:这行代码使用 assert 断言检查 this->py_module 是否为 NULL,如果为 NULL,则会引发断言错误。

  10. this->py_class = PyObject_GetAttrString(this->py_module, this->class_name.c_str());:这行代码获取 this->py_module 中名为 class_name 的属性,并将其赋值给 this->py_classthis->class_name 可能是一个存储类名的成员变量。

  11. assert(this->py_class != NULL);:这行代码使用 assert 断言检查 this->py_class 是否为 NULL,如果为 NULL,则会引发断言错误。

  12. this->net = PyInstance_New(this->py_class, NULL, NULL);:这行代码基于 this->py_class 创建一个 Python 实例对象,并将其赋值给 this->net。这里使用 PyInstance_New 函数来实例化一个 Python 类的对象。

  13. assert(this->net != NULL);:这行代码使用 assert 断言检查 this->net 是否为 NULL,如果为 NULL,则会引发断言错误。

  14. std::cout << "Creating net instance..." << std::endl;:这行代码将字符串 “Creating net instance…” 打印到标准输出流,用于显示正在创建网络实例。

  15. cv::Mat image = cv::Mat::zeros(480, 640, CV_8UC3);:这行代码创建一个大小为 480x640、类型为 CV_8UC3(8位无符号整数,通道数为3)的黑色图像,存储在名为 imagecv::Mat 对象中。这可能是为了后续的图像处理操作准备输入。

  16. std::cout << "Loading net parameters..." << std::endl;:这行代码将字符串 “Loading net parameters…” 打印到标准输出流,用于显示正在加载网络参数。

  17. GetSegmentation(image);:这行代码调用名为 GetSegmentation 的函数,将 image 作为参数传递。这个函数可能会对图像进行分割处理,但没有提供代码,无法具体解释其功能。

综上所述,SegmentDynObject::SegmentDynObject() 构造函数主要进行了一系列初始化操作,包括导入设置,设置环境变量,初始化 Python 解释器,导入 Python 模块,并创建 Python 类的对象。最后,它创建一个黑色图像对象并调用 GetSegmentation 函数对图像进行分割处理。

3、SegmentDynObject::~SegmentDynObject() 是类的析构函数,用于释放类对象所使用的资源和内存,在对象销毁时被调用。

    SegmentDynObject::~SegmentDynObject()
    {
        delete this->py_module;
        delete this->py_class;
        delete this->net;
        delete this->cvt;
    }

下面是对代码的逐行解释:

  1. delete this->py_module;:这行代码用于释放 py_module 对象所占用的内存。py_module 是一个指向 Python 模块的指针,使用 delete 操作符释放指针指向的内存。

  2. delete this->py_class;:这行代码用于释放 py_class 对象所占用的内存。py_class 是一个指向 Python 类的指针,使用 delete 操作符释放指针指向的内存。

  3. delete this->net;:这行代码用于释放 net 对象所占用的内存。net 是一个指向 Python 实例对象的指针,使用 delete 操作符释放指针指向的内存。

  4. delete this->cvt;:这行代码用于释放 cvt 对象所占用的内存。cvt 是一个指向 NDArrayConverter 类的指针,使用 delete 操作符释放指针指向的内存。

通过在析构函数中使用 delete 操作符释放对象所占用的内存,可以确保在对象销毁时释放资源,防止内存泄漏和资源泄漏。

4、这段代码定义了 SegmentDynObject 类的一个成员函数 GetSegmentation(),用于获取图像的分割结果。

    cv::Mat SegmentDynObject::GetSegmentation(cv::Mat &image, std::string dir, std::string name)
    {
        cv::Mat seg = cv::imread(dir + "/" + name, CV_LOAD_IMAGE_UNCHANGED);
        if (seg.empty())
        {
            PyObject *py_image = cvt->toNDArray(image.clone());
            assert(py_image != NULL);
            PyObject *py_mask_image = PyObject_CallMethod(this->net, const_cast<char *>(this->get_dyn_seg.c_str()), "(O)", py_image);
            seg = cvt->toMat(py_mask_image).clone();
            seg.cv::Mat::convertTo(seg, CV_8U); // 0 background y 1 foreground
            if (dir.compare("no_save") != 0)
            {
                DIR *_dir = opendir(dir.c_str());
                if (_dir)
                {
                    closedir(_dir);
                }
                else if (ENOENT == errno)
                {
                    const int check = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
                    if (check == -1)
                    {
                        std::string str = dir;
                        str.replace(str.end() - 6, str.end(), "");
                        mkdir(str.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
                    }
                }
                cv::imwrite(dir + "/" + name, seg);
            }
        }
        return seg;
    }

下面是代码的逐行解释:

  1. cv::Mat seg = cv::imread(dir + "/" + name, CV_LOAD_IMAGE_UNCHANGED);:从指定目录中读取图像文件,保存到 seg 变量中。dir 是图像文件所在目录的路径,name 是图像文件的文件名。

  2. if (seg.empty()):检查是否成功读取了图像文件。如果 seg 是空的(即读取失败),则执行以下操作:

  3. PyObject *py_image = cvt->toNDArray(image.clone());:将图像 image 克隆并转换为 Python 的 NDArray 对象。cvt 是指向 NDArrayConverter 类的指针,toNDArray() 是该类的成员函数。

  4. PyObject *py_mask_image = PyObject_CallMethod(this->net, const_cast<char *>(this->get_dyn_seg.c_str()), "(O)", py_image);:调用 this->net 对象的名为 get_dyn_seg 的方法,并传递参数 py_image。返回的结果保存在 py_mask_image 中。

  5. seg = cvt->toMat(py_mask_image).clone();:将返回的结果转换为 OpenCV 的 cv::Mat 对象,并将其克隆到 seg 变量中。

  6. seg.cv::Mat::convertTo(seg, CV_8U);:将 seg 的数据类型转换为 CV_8U(即8位无符号整数类型)。这里假设 seg 的值为0表示背景,1表示前景。

  7. if (dir.compare("no_save") != 0):检查 dir 是否等于字符串 “no_save”。如果不等于,则执行以下操作:

  8. DIR *_dir = opendir(dir.c_str());:打开指定目录 dir

  9. if (_dir):检查是否成功打开目录。如果成功打开目录,则关闭目录。

  10. else if (ENOENT == errno):如果打开目录失败且错误代码为 ENOENT(表示目录不存在),则执行以下操作:

  11. const int check = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);:创建指定的目录 dir,设置相应的权限。

  12. if (check == -1):检查目录创建是否失败。如果失败,则执行以下操作:

  13. std::string str = dir;:将 dir 复制到新的字符串变量 str 中。

  14. str.replace(str.end() - 6, str.end(), "");:将 str 中的最后六个字符替换为空字符串。这可能是为了在目录名称中去除扩展名。

  15. mkdir(str.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);:使用更新后的目录名称 str 创建目录。

  16. cv::imwrite(dir + "/" + name, seg);:将 seg 保存为图像文件,文件路径为 dir + "/" + name

  17. return seg;:返回获取的分割结果 seg

总体而言,GetSegmentation() 函数的作用是读取指定的图像文件,然后使用存储在 this->net 对象中的算法对图像进行分割,并返回分割的结果。如果指定的目录不存在,则会尝试创建目录,并将分割结果保存为图像文件。

5、这段代码定义了 SegmentDynObject 类的一个成员函数 ImportSettings(),用于从一个 YAML 文件中导入一些设置参数。

    void SegmentDynObject::ImportSettings()
    {
        std::string strSettingsFile = "./Examples/RGB-D/MaskSettings.yaml";
        cv::FileStorage fs(strSettingsFile.c_str(), cv::FileStorage::READ);
        fs["py_path"] >> this->py_path;
        fs["module_name"] >> this->module_name;
        fs["class_name"] >> this->class_name;
        fs["get_dyn_seg"] >> this->get_dyn_seg;

        // std::cout << "    py_path: "<< this->py_path << std::endl;
        // std::cout << "    module_name: "<< this->module_name << std::endl;
        // std::cout << "    class_name: "<< this->class_name << std::endl;
        // std::cout << "    get_dyn_seg: "<< this->get_dyn_seg << std::endl;
    }

下面是代码的逐行解释:

  1. std::string strSettingsFile = "./Examples/RGB-D/MaskSettings.yaml";:指定 YAML 文件的路径和文件名。

  2. cv::FileStorage fs(strSettingsFile.c_str(), cv::FileStorage::READ);:创建一个 FileStorage 对象 fs,用于读取 YAML 文件。

  3. fs["py_path"] >> this->py_path;:从 YAML 文件中读取键名为 “py_path” 的值,并将其赋值给 this->py_path 变量。这里假设该值是一个字符串。

  4. fs["module_name"] >> this->module_name;:从 YAML 文件中读取键名为 “module_name” 的值,并将其赋值给 this->module_name 变量。

  5. fs["class_name"] >> this->class_name;:从 YAML 文件中读取键名为 “class_name” 的值,并将其赋值给 this->class_name 变量。

  6. fs["get_dyn_seg"] >> this->get_dyn_seg;:从 YAML 文件中读取键名为 “get_dyn_seg” 的值,并将其赋值给 this->get_dyn_seg 变量。

  7. 可选地,您可以取消注释代码中的 std::cout 部分,以打印读取的设置参数的值。

总体而言,ImportSettings() 函数的作用是打开指定的 YAML 文件,读取其中的设置参数,并将它们分别赋值给 SegmentDynObject 类的成员变量 py_pathmodule_nameclass_nameget_dyn_seg

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值