学习C++:C++进阶(六)如何在C++代码中调用python类,实例化python中类的对象,如何将conda中的深度学习环境导入C++项目中

news2024/12/29 10:05:39

目录

1.应用场景

2.场景:利用maskrcnn深度学习网络实现语义分割

3.CMake配置python解释器

4.C++中实现实例化python中的类的对象并调用类内方法

4.1 初始化python环境

4.2  实例化python类的对象


1.应用场景

        我们在视觉SLAM以及目标检测和识别中,经常要将代码结合深度学习。但深度学习代码大多都是python的,SLAM代码大多都是C++的,如何建立C++和python的链接桥就显得极为重要,本篇文章将介绍如何配置CMake导入深度学习的python模块以及如何在C++代码中python中类的方法。

2.场景:利用maskrcnn深度学习网络实现语义分割

        在视觉SLAM中调用maskrcnn深度学习语义分割网络实现对动态物体的剔除。

        首先,我训练了一个各种树和人的数据集,确保我的深度学习网络maskrcnn可以运行起来,在pycharm中运行效果如下:

        原图片是一张人的图片,这里返回的是这个图像的掩膜。!!到这里我就想告诉大家,我的深度学习网络可以运行起来(也就是说你在进行C++调用python的时候要确定你的python代码可以运行起来)。

        这个代码里面我是定义了一个类ORBSLAM3_with_masknet

        这个类的初始化函数传入两个参数:输入的图片路径、输出的图片路径。

    def __init__(self, input_image_path, out_put_image):
        self.outImage = None
        self.input_image_path = input_image_path
        self.output_image_path = out_put_image

        这个类定义了第一个方法是saveImagetoORBSLAM3,没有传入参数(self),其功能就是对输入图片路径的图片进行检测并进行掩膜,并将掩膜信息保存到类内变量self.outImage中。

        这个类定义了第一个方法是showimage,没有传入参数(self),其功能是展示掩膜图片self.outImage。

        我们为了确保这个类中没有问题,我们在main函数中实例化这个类然后调用方法:

if __name__ == '__main__':
    my_object = ORBSLAM3_with_masknet("/home/xxxxx/Desktop/slam/mask_rcnn/333.JPG",
                                      "/home/xxxxx/Desktop/slam/mask_rcnn/")
    my_object.saveImagetoORBSLAM3()
    my_object.showimage()

        运行如下:可以运行。

3.CMake配置python解释器

        由于我们系统默认的python路径是环境变量下的python,而不是我们conda虚拟环境下的深度学习环境,因此我们需要设置CMake让我们的SLAM项目链接到我们conda虚拟环境下的深度学习环境:

        我的conda中的pytorch环境在torch虚拟环境中,即在目录/home/anaconda3/envs下面的torch中。

        如果我们不在代码中特意声明,我们看看系统引用的python路径是什么?

find_package(PythonLibs REQUIRED)
if (NOT PythonLibs_FOUND)
    message(FATAL_ERROR "PYTHON LIBS not found.")
else()
    message("PYTHON LIBS were found!")
    message("PYTHON LIBS DIRECTORY: " ${PYTHON_LIBRARY})
endif()

        我们配置一下项目:

        我们可以看到,引用的python环境是系统环境下

PYTHON LIBS DIRECTORY: /usr/lib/x86_64-linux-gnu/libpython3.6m.so的python3.6,这样就会让代码运行时出现python类无法初始化、段错误等令人十分头痛的错误,那要如何设置我们的conda虚拟环境作为我们的python环境变量呢,我们加入下面两行内容:

set(PYTHON_LIBRARY /home/liuhongwei/anaconda3/envs/torch/lib/libpython3.8.so)
set(PYTHON_INCLUDE_DIR /home/liuhongwei/anaconda3/envs/torch/include/python3.8)
find_package(PythonLibs REQUIRED)
if (NOT PythonLibs_FOUND)
    message(FATAL_ERROR "PYTHON LIBS not found.")
else()
    message("PYTHON LIBS were found!")
    message("PYTHON LIBS DIRECTORY: " ${PYTHON_LIBRARY})
endif()

        第一行是python的解释器的动态链接库的位置,他就在我们的conda虚拟环境中,每个机器都是一样的,如下图:

        第二行是python的库文件的位置。

        然后我们再去构建:我们成功链接到了我们的深度学习虚拟环境。

        此外,我们现在只是找到了python深度学习环境,但要将python深度环境加载到我们的项目中,这里用include_directories关键字,将项目所需的库都引入:

include_directories(
        ${EIGEN3_INCLUDE_DIR}
        ${Pangolin_INCLUDE_DIRS}
        /home/xxx/anaconda3/envs/torch/include/python3.8/
        /home/xxx/anaconda3/envs/torch/lib/python3.8/site-packages/numpy/core/include/numpy
        ${Boost_INCLUDE_DIRS}
)

        最后,我们将这些库链接到我们的程序中:

add_executable(ExtractDynamic main.cpp)
target_link_libraries(ExtractDynamic ${PYTHON_LIBRARY})

        所有的代码如下:

cmake_minimum_required(VERSION 3.25)
project(ExtractDynamic)

set(CMAKE_CXX_STANDARD 17)

set(PYTHON_LIBRARY /home/xxx/anaconda3/envs/torch/lib/libpython3.8.so)
set(PYTHON_INCLUDE_DIR /home/xxx/anaconda3/envs/torch/include/python3.8)
find_package(PythonLibs REQUIRED)
if (NOT PythonLibs_FOUND)
    message(FATAL_ERROR "PYTHON LIBS not found.")
else()
    message("PYTHON LIBS were found!")
    message("PYTHON LIBS DIRECTORY: " ${PYTHON_LIBRARY})
endif()

find_package(Eigen3 3.1.0 REQUIRED)
find_package(Pangolin REQUIRED)
find_package(Boost REQUIRED COMPONENTS thread)
if(Boost_FOUND)
    message("Boost was found!")
    message("Boost Headers DIRECTORY: " ${Boost_INCLUDE_DIRS})
    message("Boost LIBS DIRECTORY: " ${Boost_LIBRARY_DIRS})
    message("Found Libraries: " ${Boost_LIBRARIES})
endif()

include_directories(
        #${PROJECT_SOURCE_DIR}
        ${EIGEN3_INCLUDE_DIR}
        ${Pangolin_INCLUDE_DIRS}
        /home/xxx/anaconda3/envs/torch/include/python3.8/
        /home/xxx/anaconda3/envs/torch/lib/python3.8/site-packages/numpy/core/include/numpy
        ${Boost_INCLUDE_DIRS}
)

message("PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR})

add_executable(ExtractDynamic main.cpp)
target_link_libraries(ExtractDynamic ${PYTHON_LIBRARY})

        这样,我们CMake环境就配置好啦!

4.C++中实现实例化python中的类的对象并调用类内方法

4.1 初始化python环境

    std::cout << "Initializing the OutDynamicNet..." << std::endl;

    // 转换字符串
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    std::wstring pythonHome = converter.from_bytes("/home/liuhongwei/anaconda3/envs/torch");

    // 设置 深度学习网络目录
    std::string masknet;
    setenv("PYTHONPATH","/home/liuhongwei/Desktop/slam/mask_rcnn",1);
    masknet = getenv("PYTHONPATH");


    // 设置python的解释器的目录,初始化python环境
    Py_SetPythonHome(pythonHome.c_str());
    Py_Initialize();
    if(Py_IsInitialized())
    {
        std::cout << "Python Inititalize Succeess" << std::endl;
    }

        我们引入头文件完成python环境的初始化:

#include <Python.h>
#include <locale>
#include <codecvt>

        pythonHome保存的是虚拟环境的目录,注意,这个转换字符串的工作是必须做的!!!!否则会报错.....我在这块卡了一个星期,翻越各种博客和参考书才知道的.....

        我们通过if语句判断python环境是否初始化成功!!注意:这个python环境必须和CMake中设置的python环境一样,不然不会初始化成功。

        我们执行:

4.2  实例化python类的对象

    PyObject * pModule = NULL;
    PyObject * pDict = NULL;
    PyObject * pInstance = NULL;
    PyObject * pClass = NULL;
    PyObject * deal = NULL;

    // 引入python文件 /xxxx/predict.py
    pModule = PyImport_ImportModule("predict");
    if(pModule != NULL)
    {
        std::cout << "Module imported successfully" << std::endl;
    }
    else
    {
        std::cout << "Failed to import module" << std::endl;
    }
    assert(pModule != NULL);


    // 获取predict可以引用的类
    pDict = PyModule_GetDict(pModule);
    assert(pDict != NULL);

    // 获取ORBSLAM3_with_masknet类,并判断类是否可引用
    pClass = PyDict_GetItemString(pDict,"ORBSLAM3_with_masknet");
    if(pClass != NULL && PyCallable_Check(pClass))
    {
        std::cout << "Class imported successfully" << std::endl;
    }
    else
    {
        std::cout << "Failed to import class" << std::endl;
    }

        我们引入这个文件夹下的predict.py文件,这个文件里面有saveImagetoORBSLAM3类,类内有方法帮助我们实现语义分割。

        由于我们先前设置了pythonHome变量,因此pModule就获取了python文件,判断一下是否打开成功(失败是环境问题或者代码问题或者路径问题....)。        

        我们再通过PyModule_GetDict方法获取我们在这个python文件中可以引用的类。

        通过PyDict_GetItemString方法获取我们需要使用的类,参数为可以引用的类的对象以及我们要导入类的名称,判断这个类是否可用。

    pInstance = PyObject_CallFunction(pClass,"ss","/home/xxx/Desktop/slam/mask_rcnn/333.JPG","/home/xxx/Desktop/slam/mask_rcnn/");
    assert(pInstance != NULL);

    PyObject * pFunc = PyObject_GetAttrString(pInstance,"saveImagetoORBSLAM3");
    assert(pFunc!=NULL);

    PyObject * pResult1 = PyObject_CallMethod(pInstance,"__init__","ss","/home/xxx/Desktop/slam/mask_rcnn/333.JPG","/home/xxx/Desktop/slam/mask_rcnn/");
    assert(pResult1!=NULL);

        我们通过PyObject_CallFunction方法实例化pClass所指向的类(ORBSLAM3_with_masknet)。这里由于初始化要传入两个路径,因此数据类型是ss,传入两个地址字符串。

    def __init__(self, input_image_path, out_put_image):
        self.outImage = None
        self.input_image_path = input_image_path
        self.output_image_path = out_put_image

        我们再通过PyObject_GetAttrString执行ORBSLAM3_with_masknet类的方法。

        完成!!!完整代码如下:

#include <iostream>
#include <Python.h>
#include <locale>
#include <codecvt>
int main()
{

    std::cout << "Initializing the OutDynamicNet..." << std::endl;

    // 转换字符串
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    std::wstring pythonHome = converter.from_bytes("/home/xxx/anaconda3/envs/torch");

    // 设置 深度学习网络目录
    std::string masknet;
    setenv("PYTHONPATH","/home/xxx/Desktop/slam/mask_rcnn",1);
    masknet = getenv("PYTHONPATH");


    // 设置python的解释器的目录,初始化python环境
    Py_SetPythonHome(pythonHome.c_str());
    Py_Initialize();
    if(Py_IsInitialized())
    {
        std::cout << "Python Inititalize Succeess" << std::endl;
    }

    PyObject * pModule = NULL;
    PyObject * pDict = NULL;
    PyObject * pInstance = NULL;
    PyObject * pClass = NULL;
    PyObject * deal = NULL;

    // 引入python文件 /home/xxx/Desktop/slam/mask_rcnn/predict.py
    pModule = PyImport_ImportModule("predict");
    if(pModule != NULL)
    {
        std::cout << "Module imported successfully" << std::endl;
    }
    else
    {
        std::cout << "Failed to import module" << std::endl;
    }
    assert(pModule != NULL);


    // 获取predict可以引用的类
    pDict = PyModule_GetDict(pModule);
    assert(pDict != NULL);

    // 获取ORBSLAM3_with_masknet类,并判断类是否可引用
    pClass = PyDict_GetItemString(pDict,"ORBSLAM3_with_masknet");
    if(pClass != NULL && PyCallable_Check(pClass))
    {
        std::cout << "Class imported successfully" << std::endl;
    }
    else
    {
        std::cout << "Failed to import class" << std::endl;
    }

    // 初始化类
//    const char * ImagePath = ;
//    const char * OutPutPath = ;
    pInstance = PyObject_CallFunction(pClass,"ss","/home/xxx/Desktop/slam/mask_rcnn/333.JPG","/home/liuhongwei/Desktop/slam/mask_rcnn/");
    assert(pInstance != NULL);



    PyObject * pFunc = PyObject_GetAttrString(pInstance,"saveImagetoORBSLAM3");
    assert(pFunc!=NULL);

    PyObject * pResult1 = PyObject_CallMethod(pInstance,"__init__","ss","/home/xxx/Desktop/slam/mask_rcnn/333.JPG","/home/xxx/Desktop/slam/mask_rcnn/");
    assert(pResult1!=NULL);
    PyObject * pResult2 = PyObject_CallMethod(pInstance,"saveImagetoORBSLAM3",NULL);
    assert(pResult2!=NULL);


//    deal = PyObject_CallMethod(pInstance, "saveImagetoORBSLAM3",NULL);
//    if(deal != NULL)
//    {
//        std::cout << "Class imported successfully" << std::endl;
//    }
//    else
//    {
//        std::cout << "Failed to import class" << std::endl;
//    }
//    assert(deal!=NULL);

    std::cout << "Creating net instance..." << std::endl;
    return 0;
}

        我们看下结果:

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

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

相关文章

AMD GPU安装运行stable diffusion

本文操作环境为Windows10/11AMD AI绘画是一种利用人工智能技术进行绘画的方法。它可以通过机器学习算法来学习艺术家的风格&#xff0c;并生成类似于艺术家的作品。最近&#xff0c;AI绘画技术得到了很大的发展&#xff0c;许多公司和研究机构都在进行相关的研究和开发。例如&…

华为电脑录屏功能在哪?这样做,您可以快速找到

案例&#xff1a;如何在华为电脑上找到电脑录屏功能&#xff1f; “听说电脑有录屏功能&#xff0c;但我在我的华为电脑上找了很久&#xff0c;都没有找到。难道华为电脑没有录屏功能吗&#xff1f;有没有小伙伴可以告诉我华为电脑录屏功能在哪&#xff1f;孩子已经快绝望了&a…

第六章 法律体系

目录 第一节 法律体系与法律部门的概念 一、法律体系的概念 &#xff08;一&#xff09;法律体系的含义和特征 &#xff08;二&#xff09;法律体系与相关概念的区别&#xff08;法律体系与国家&#xff0c;现行有关&#xff09; &#xff08;三&#xff09;法律体系的形成和…

本地存储、自定义事件、全局事件总线、消息订阅与发布【Vue】

Vue 1.1 浏览器的本地存储 存储内容大小一般支持5MB左右&#xff08;不同浏览器可能还不一样&#xff09;浏览器通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制相关API: &#xff08;1&#xff09;xxxxStorage.setItem(key, value); 该方法接受一…

CT前瞻(三):Adobe系列XD软件绘制简单的原型图与交互设计

文章目录&#x1f4cb;前言&#x1f3af;关于原型图绘制&#x1f3af;XD绘制原型图与交互设计&#x1f3af;关于XD软件其他功能&#x1f4dd;最后&#x1f4cb;前言 Adobe XD是一个协作式易用平台&#xff0c;可帮助团队为网站、移动应用程序、语音界面、游戏等创建设计。还可…

每个 Android 开发者都应该知道的有用资源

每个 Android 开发者都应该知道的有用资源 在本文中&#xff0c;我将提到 7 个资源&#xff0c;这些资源对于 Android 开发人员来说非常有益。我亲自使用过其中的每一个几次。他们无数次派上用场。确保您不要忘记为这些资源添加书签/收藏&#xff0c;以便您可以在需要使用它们时…

医院体检PEIS系统源码

一、医院体检系统概述 1. 医院体检系统概述 目前&#xff0c;大多数的体检还停留在手工操作上&#xff0c;如单位体检时手工书写体检人员信息、医生手工书写体检结果、检验报告打印后进行手工粘贴等&#xff0c;这样造成极大的工作量&#xff0c;效率低下&#xff0c;而且极易…

【三十天精通Vue 3】第九天 Vue 3 路由详解

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录引言一、Vue 3 路由概述1.1 路由的简介1.2 路由的分类1.3 路由的语…

暗讽友商 昆仑万维大模型预告刺激股价

搭上AI风口&#xff0c;上市公司昆仑万维年内股价大涨217.56%&#xff0c;一时名声大噪。火了以后&#xff0c;昆仑万维的野心越来越大&#xff0c;喊出“All in AGI&#xff08;通用人工智能&#xff09;与AIGC”的豪言壮语。 在近期预告旗下大模型“天工”邀测的公告中&…

STL :双端队列容器 Deque

Deque #include<deque> using namesace std; 双端队列容器 &#xff1a;双向开口的连续线性空间&#xff1b; 擅长尾部和头部添加或删除元素&#xff1a;常数阶&#xff1b; 存储元素并不能保证所有元素都存储到连续的内存空间中&#xff1b; deque 是动态的以分段…

TiDB实战篇-TiDB配置

简介 熟系TiDB的配置相关。 TiDB的大体参数 系统配置对应的是TiDB-Server,PD和TiKV和TiDB-Server基本在集群配置里面配置。 系统配置 系统变量 | PingCAP 文档中心 集群配置 PD 配置文件描述 | PingCAP 文档中心 配置的存储位置 系统配置存储在TiKV中的&#xff0c;集…

如何免费恢复电脑上误删除的视频

虽然我们现在可以在单个硬盘驱动器上存储无数大型视频文件是件好事&#xff0c;但这也意味着单个用户错误或硬件/软件故障可能会立即抹去数小时的记忆&#xff0c;而没有任何明显的方法可以恢复它们。在本文中&#xff0c;我们提供了一个快速的分步视频恢复指南&#xff0c;以帮…

【音视频】利用ffmpeg实现:音视频的提取,rtmp推流等

目录 可列出电脑的设备 音频桌面视频&#xff0c;存mp4 录声音 推流到服务器 音频桌面视频&#xff0c;推流到服务器 音频笔记本摄像头&#xff0c;推流到服务器 参考资料 可列出电脑的设备 输入下面的语句即可列出电脑的设备 ffmpeg -list_devices true -f dshow -i dum…

(链表)相交链表(双指针法)

文章目录前言&#xff1a;问题描述&#xff1a;问题解析&#xff1a;代码实现&#xff1a;总结&#xff1a;前言&#xff1a; 此篇是关于链表的经典练习题。 问题描述&#xff1a; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节…

【测试开发篇9】Junit框架

目录 一、认识Junit框架 Junit和Selenium的关系是什么 导入Junit框架common-io包 二、Junit框架的使用 2.1Junit有哪些常用注解 2.1.1Test注解 2.1.2BeforeEach 2.1.3BeforeAll 2.1.4AfterAll 2.1.5AfterEach 2.2Junit的断言 Assertions.assertEquals(期待值&#…

小白推荐|使用git建立自己的代码仓库

1 git 1.1 什么是git 版本控制工具&#xff0c;用于团队协作与项目管理 1.2 git 安装教程 step1&#xff1a;进入git下载官网Git for Windows step2&#xff1a;点击Download step3&#xff1a;打开下载好的文件&#xff0c;按照下面图片一步一步安装 剩下的一直点Next就完…

ansible-playbook task 指定位置执行

文章目录执行顺序指定执行--tags–start-at--skip-tags--step混合执行顺序 1.检查play中是否存在pre_tasks定义&#xff0c;存在的话则顺序执行pre_tasks中定义的所有tasks 2.如果存在pre_tasks定义&#xff0c;则检查是否存在触发handler&#xff0c;如存在则顺序执行相关触发…

Java中的锁是什么意思,有哪些分类?

Java锁&#xff08;Java Locks&#xff09;是Java编程语言中用于实现多线程同步和互斥的机制。在并发编程中&#xff0c;多线程同时访问共享资源可能导致竞态条件&#xff08;Race Condition&#xff09;和其他并发问题&#xff0c;Java锁提供了一种控制多线程并发访问的方式&a…

FluxMQ—物联网高性能MQTT网关

FluxMQ—物联网高性能MQTT网关 随着物联网技术的快速发展&#xff0c;人们越来越意识到实时、可靠、安全的数据传输对于智能化的生产与生活的重要性。因此&#xff0c;市场对于高性能的物联网数据传输解决方案有着强烈的需求。FluxMQ正是为满足这一需求而诞生的一款高性能、可…

Adobe 观察 |最低工资标准来了,学会这几招,让加薪更简单

最新调整后的全国各地区最低工资标准情况来了&#xff01; 人力资源和社会保障部新发布的数据显示&#xff0c;截至今年4月1日&#xff0c;共有15个地区第一档月最低工资标准在2000元及以上&#xff0c;分别是上海&#xff08;2590元&#xff09;、深圳&#xff08;2360元&…