QT(6.5) cmake构建C++编程,调用python (已更新:2024.3.23晚)

news2024/11/17 3:29:18

一、注意事项

  1. explicit
    c++中,一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数),承担了两个角色,构造器、类型转换操作符,
    c++提供关键字explicit,阻止转换构造函数进行的隐式转换的发生,声明explicit的构造函数不能在隐式转换中使用。
  2. c++ 函数前面和后面 使用const 的作用
    前面使用const 表示返回值为const;
    后面加 const表示函数不可以修改class的成员;
    const成员函数可以被非const对象和const对象调用;
    非const成员函数只能被非const对象调用;
  3. 类外补充函数的定义要加作用域限定符::

二、重要知识:cmake
在QT中选择cmake方式构建c++项目,最好提前了解cmake相关知识,以方便理解如何导入外部库,推荐学习视频链接:B站:爱编程的大丙
重要细节:静态库的链接要放在add_executable之前

三、c++代码调用python步骤

  1. 设置python配置
    CMakeList.txt文件中输入python文件的相关信息:头文件夹路径、库文件夹路径、需要连接的库文件名称(有没有.lib后缀都可)
include_directories(C:/programming/anaconda3/envs/pytorch/include)
link_directories(C:/programming/anaconda3/envs/pytorch/libs)
link_libraries(python3)
link_libraries(python38)

在这里插入图片描述
2. c++代码(.cpp)中调用python(注:下面代码中功函数invokePython的调用只可执行一次,再次调用程序会崩溃

#include "My_Functions.h"
#include <QDir>
#include <Python.h>

My_Functions::My_Functions(QObject *parent) : QObject(parent){}
My_Functions:: ~My_Functions(){}

bool My_Functions :: invokePython(){
    QDir dir;
    const char* pythonFilePath = (dir.currentPath().append("/").append(dir.currentPath().split("/").last().split("-")[1])).toUtf8();
    Py_SetPythonHome(L"C:/programming/anaconda3/envs/pytorch");
    //调用前必须初始化python解释器
    Py_Initialize();
    if(!Py_IsInitialized()){qDebug()<<"初始化失败"; return 0;}

    // 将路径转换为Python对象
    PyObject *py_path_str = PyUnicode_FromWideChar(Py_DecodeLocale(pythonFilePath, NULL), -1);
    // 加载 python 脚本
    // 获取sys模块以进行项目.py文件的搜索
    PyObject *sys_module = PyImport_ImportModule("sys");

    // 获取sys.path
    PyObject *sys_path = PyObject_GetAttrString(sys_module, "path");
    if (!PyList_Check(sys_path)) {
        // sys.path不是列表,错误处理
        qDebug()<<"获取py搜索路径失败" ;

        // 释放python所用内存
        Py_Finalize();
        return 0;
    } else {
        // 将自定义路径添加到sys.path
        int appended = PyList_Append(sys_path, py_path_str);
        if (appended == -1) {
            // 错误处理
            qDebug()<<"添加py搜索路径失败" ;

            // 释放python所用内存
            Py_Finalize();
            return 0;
        }
    }


    PyObject *pModule = PyImport_ImportModule("onnxUse");
    if (pModule == NULL) {
        // 模块导入失败,处理错误
        qDebug() << "脚本加载失败";

        // 释放python所用内存
        Py_Finalize();
        return 0;
    } else {
        qDebug() << "脚本加载成功";
    }
    // 创建函数指针
    PyObject* pFunc = PyObject_GetAttrString(pModule, "detect_images");  // 方法名称
    if (pFunc == NULL) {
        // 函数导入失败,处理错误
        qDebug() << "函数创建失败";

        // 释放python所用内存
        Py_Finalize();
        return 0;
    }else {
        qDebug() << "函数创建成功";
    }

    // 调用有参函数
    // 创建函数参数
    // s 将C字符串转换成Python对象,如果C字符串为空,返回NONE
    // z: 类似于 s,但允许转换为 NULL(Python 的 None)
    // c 将C类型的char转换成长度为1的Python字符串对象
    // b: C unsigned char,将布尔值转换为 0 或 1
    // i 将一个C类型的int转换成Python int对象
    // k: C unsigned long,转换为无符号长整数
    // l 将C类型的long转换成Pyhon中的int对象
    // f 将C类型的float转换成python中的浮点型对象
    // d 将C类型的double转换成python中的浮点型对象
    // O 通用对象引用,接收任意 Python 对象而不转换
    // O!: 类型对象和转换标志,用于接收特定类型的 Python 对象
    // O&: 自定义回调函数,用于自定义对象转换
    // (ii):两个 C 整型变量构成的元组或列表
    // [ii]:两个 C 整型变量构成的列表
    // {ss}:键值对都是 C 字符串的字典
    // #:s, #i, #d 等:带有长度指示的字符串、整数或浮点数
    // n: 接收 None,检查参数是否为 None

    // PyObject* args = Py_BuildValue("(i,s)", 110, "hello");  // 参数为整数 110 和字符串 "hello"
    // PyObject *result  = PyObject_CallObject(pFunc, args);

    // 调用无参函数
    PyObject *result  = PyObject_CallObject(pFunc, NULL);

    // 检查并处理有参函数调用的返回结果
    if (result  == NULL) {
        // 处理错误
        qDebug() << "函数调用失败";

        // 释放python所用内存
        Py_Finalize();
        return 0;
    } else {
        // 使用返回值
        qDebug() << "函数调用成功";

        // const char *result_str;
        // if (!PyArg_Parse(result, "s", &result_str)) {
        //     // 错误处理:无法将Python对象转换为字符串
        //     qDebug() << "函数返回值处理失败";

        //     // 释放python所用内存
        //     Py_Finalize();
        //     return 0;
        // } else {
        //     // 使用result_str
        // }
    }

    // 释放引用计数
    Py_DECREF(result);
    // // 释放参数元组
    // Py_DECREF(args);
    // 释放函数指针
    Py_DECREF(pFunc);
    // 不再需要模块时,减少引用计数
    Py_DECREF(pModule);
    // 释放python所用内存
    Py_Finalize();
    qDebug()<<"调用完成";
    return false;
}
  1. 局部多次调用python脚本
    改造 invokePython 函数
bool My_Functions :: invokePython(){
    PyGILState_STATE gil_state;  // 用以保存获取的Global Interpreter Lock (GIL)
    gil_state = PyGILState_Ensure();  // 获取GIL,只有拥有GIL的线程才可以执行python代码
    PyObject *pModule = PyImport_ImportModule("onnxUse");
    if (pModule == NULL) {
        // 模块导入失败,处理错误
        qDebug() << "脚本加载失败";
        return 0;
    } else {
        qDebug() << "脚本加载成功";
    }
    // 创建函数指针
    PyObject* pFunc = PyObject_GetAttrString(pModule, "detect_images");  // 方法名称
    if (pFunc == NULL) {
        // 函数导入失败,处理错误
        qDebug() << "函数创建失败";
        PyErr_Print();
        return 0;
    }else {
        qDebug() << "函数创建成功";
    }

    // 调用无参函数
    PyObject *result  = PyObject_CallObject(pFunc, NULL);

    // 检查并处理有参函数调用的返回结果
    if (result  == NULL) {
        // 处理错误
        qDebug() << "函数调用失败";

        return 0;
    } else {
        // 使用返回值
        qDebug() << "函数调用成功";

        // const char *result_str;
        // if (!PyArg_Parse(result, "s", &result_str)) {
        //     // 错误处理:无法将Python对象转换为字符串
        //     qDebug() << "函数返回值处理失败";

        //     // 释放python所用内存
        //     Py_Finalize();
        //     return 0;
        // } else {
        //     // 使用result_str
        // }
    }
    // 释放引用计数
    Py_DECREF(result);
    // // 释放参数元组
    // Py_DECREF(args);
    // 释放函数指针
    Py_DECREF(pFunc);
    // 不再需要模块时,减少引用计数
    Py_DECREF(pModule);
    PyGILState_Release(gil_state);  // 释放GIL,释放前确保获取到了GIL,同时最好主动释放各计数,以防发生内存泄漏
    return false;
}

同时不要忘记初始化python解释器(注:整个程序只可初始化一次,结束程序前再释放,否则再次初始化程序会崩溃),下面是改造后的初始化函数
头文件:

#ifndef INVOKE_PYTHON_INIT_H
#define INVOKE_PYTHON_INIT_H
#include <QObject>
#include <Python.h>

class Invoke_Python_Init
{
public:
    Invoke_Python_Init();
    ~Invoke_Python_Init();
private:
    QString pythonDirectoryPath;
    bool init();
    void initPythonDirectoryPath();
    bool pythonDirectoryIsInit = false;
    bool pythonIsInited = false;
};

#endif // INVOKE_PYTHON_INIT_H

源码文件:

#include "invoke_python_init.h"
#include <qDebug>
#include <QDir>

Invoke_Python_Init :: Invoke_Python_Init() {init();}
Invoke_Python_Init :: ~Invoke_Python_Init() {
    // 释放python所用内存
    Py_Finalize();
    qDebug()<<"释放python解释器完成";
}

bool Invoke_Python_Init :: init() {
    initPythonDirectoryPath();
    if (!pythonDirectoryIsInit) {qDebug()<<"路径初始化失败" ; return 0;}
    Py_SetPythonHome(L"C:/programming/anaconda3/envs/pytorch");
    //调用前必须初始化python解释器
    Py_Initialize();
    if(!Py_IsInitialized()){qDebug()<<"python解释器初始化失败"; return 0;}

    // 将路径转换为Python对象
    PyObject *py_path_str = PyUnicode_FromWideChar(Py_DecodeLocale(pythonDirectoryPath.toLocal8Bit().constData(), NULL), -1);
    // 加载 python 脚本
    // 获取sys模块以进行项目.py文件的搜索
    PyObject *sys_module = PyImport_ImportModule("sys");

    // 获取sys.path
    PyObject *sys_path = PyObject_GetAttrString(sys_module, "path");
    if (!PyList_Check(sys_path)) {
        // sys.path不是列表,错误处理
        qDebug()<<"获取py搜索路径失败\n" ;
        return 0;
    } else {
        // 将自定义路径添加到sys.path
        int appended = PyList_Append(sys_path, py_path_str);
        if (appended == -1) {
            // 错误处理
            qDebug()<<"添加py搜索路径失败" ;
            return 0;
        }

        // 将sys.path转换为QStringList
        QStringList pythonPathList;
        // 遍历sys.path列表
        for (Py_ssize_t i = 0; i < PyList_Size(sys_path); ++i) {
            PyObject *path_item = PyList_GetItem(sys_path, i);
            // 将路径元素转换为QString
            QString path_str = QString::fromUtf8(PyUnicode_AsUTF8(path_item));
            // 添加到QStringList
            pythonPathList.append(path_str);
            // 减少引用计数
            Py_DECREF(path_item);
        }
        // 输出所有搜索路径到QDebug
        foreach (const QString &path, pythonPathList) {
            qDebug() << path<< "\n";
        }
    }
    PyEval_ReleaseThread(PyThreadState_Get());
    pythonIsInited = true;
    qDebug("Python解释器初始化成功");
    return true;
}
void Invoke_Python_Init :: initPythonDirectoryPath(){
    QDir dir;
    // 构建新的路径
    QString Path = dir.currentPath().append("/").append(dir.currentPath().split("/").last().split("-")[1]);
    // 将QString赋值给pythonFilePath
    pythonDirectoryPath = Path;
    pythonDirectoryIsInit = true;
}

在认为合适的地方初始化 Invoke_Python_Init 类,初始化完成后便可重复调用 invokePython 函数,即重复调用 python 脚本。

未完待续

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

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

相关文章

jvm底层

逐步细化 静态链接&#xff1a;静态方法(符号引用)替换为内存指针或者句柄直接引用) 动态链接&#xff1a;程序期间将符号引用替换为直接引用 对象头&#xff1a; 指针压缩&#xff1a; -XX:UseCompressedOops 开启指针压缩 减少内存消耗&#xff1b;大指针在主内存 缓存间移…

人脸聚类原理和算法解释

人脸聚类是指将大量人脸图像根据它们的相似性分组到不同的群集中的过程。人脸聚类通常利用人脸的特征向量表示来度量人脸之间的相似性&#xff0c;并将相似的人脸图像聚集在一起。 以下是人脸聚类的一般原理&#xff1a; 人脸特征提取&#xff1a;对每张人脸图像提取特征向量。…

上海市开展专项行动,提升车联网行业网络和数据安全防护水平

近日&#xff0c;上海市通信管理局发布了《关于开展“铸盾车联”2024年车联网网络和数据安全专项行动的通知》。通知中提到&#xff0c;此次专项行动是为了提升本市车联网行业网络和数据安全防护水平&#xff0c;筑牢车联网网络和数据安全防线&#xff0c;护航智能网联汽车产业…

Spring之事务原理篇

(/≧▽≦)/~┴┴ 嗨~我叫小奥 ✨✨✨ &#x1f440;&#x1f440;&#x1f440; 个人博客&#xff1a;小奥的博客 &#x1f44d;&#x1f44d;&#x1f44d;&#xff1a;个人CSDN ⭐️⭐️⭐️&#xff1a;Github传送门 &#x1f379; 本人24应届生一枚&#xff0c;技术和水平有…

opencv各个模块介绍(1)

Core 模块&#xff1a;核心模块&#xff0c;提供了基本的数据结构和功能。 常用的核心函数&#xff1a; cv::Mat&#xff1a;表示多维数组的数据结构&#xff0c;是OpenCV中最常用的类之一&#xff0c;用于存储图像数据和进行矩阵运算。 cv::Scalar&#xff1a;用于表示多通道…

Redis - 高并发场景下的Redis最佳实践_翻过6座大山

文章目录 概述6座大山之_缓存雪崩 &#xff08;缓存全部失效&#xff09;缓存雪崩的两种常见场景如何应对缓存雪崩&#xff1f; 6座大山之_缓存穿透&#xff08;查询不存在的 key&#xff09;缓存穿透的原因解决方案1. 数据校验2. 缓存空值3. 频控4. 使用布隆过滤器 6座大山之_…

水果检测15种YOLOV8

水果检测15种YOLOV8&#xff0c;只需要OPENCV&#xff0c;采用YOLOV8训练得到PT模型&#xff0c;然后转换成ONNX&#xff0c;OPENCV调用&#xff0c;支持C/PYTHON/ANDROID开发

41 arr.at is not a function

前言 一台机器 获取前端服务1, 一个列表能够展示出来 然后 一台机器 同样获取前端服务1, 这个列表展示不出来 然后 console里面没有任何报错[实际上是有报错, 但是没看到, 需要在vue的js代码里面去调试] 然后 这里面最终出现问题的地方是 Array.at 的使用, 我这边 js引擎版…

Spring Security安全管理

目录 一.添加依赖 效果 二.设置配置文件 认证 1.密码生成器 BCryptPasswordEncoder 配置文件中 2.inMemoryAuthentication内存认证方法 授权 效果 登录 效果 三.UserDetailsService认证授权方式 新建数据库 实体类 Role User 接口 实现类 配置文件 效果 四…

(AtCoder Beginner Contest 325) ---- D - Printing Machine -- 题解

目录 D - Printing Machine&#xff1a; 题目大意&#xff1a; 思路解析&#xff1a; 代码实现&#xff1a; D - Printing Machine&#xff1a; 题目大意&#xff1a; 思路解析&#xff1a; 打印一次后&#xff0c;需要充电一微秒后才能再次打印就可以看作每微妙只能打印一…

Vue3更新Package.json版本号

由于我之前已经更新过了&#xff0c;下面的方法提示我已经是最新的了&#xff0c;记录一下&#xff0c;过段时间在测试一下 npm install -g vue/clivue upgrade

Gitee删除自己本地仓库

1、打开自己的本地仓库 2、点击管理 3、选择删除仓库 4、将□的内容复制到⭕里

文件上传一-WEB攻防-PHP应用文件上传函数缺陷条件竞争二次渲染黑白名单JS绕过9

演示案例&#xff1a; PHP-原生态-文件上传-前后端验证PHP-原生态-文件上传-类型文件头验证PHP-原生态-文件上传-后缀黑白名单验证PHP-原生态-文件上传-解析配置&二次渲染PHP-原生态-文件上传-逻辑缺陷&函数缺陷 #学习前必读&#xff1a; 1、课前一定要明白&#xff1a…

nginx: [emerg] stream directive is duplicate in /etc/nginx/nginx.conf:56

背景&#xff1a; 在维护paas平台的时候发现一个web前端容器服务运行报错&#xff0c;提示如下&#xff1a; 问题分析&#xff1a; 根据日志的内容&#xff0c;发现是nginx.conf配置文件的stream模块配置存在问题导致的。需要查看一下nginx.conf配置文件的内容&#xff1a; 注…

LeetCode Python - 73. 矩阵置零

目录 题目描述解法方法一&#xff1a;数组标记方法二&#xff1a;原地标记 运行结果方法一方法二 题目描述 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;…

FFmpeg拉取RTSP流并定时生成10秒短视频

生成效果: 视频时长为10秒 生成格式为FLV 输出日志: 完整实现代码如下: 需要在Mac和终端先安装FFmpeg brew install ffmpeg CMake文件配置: cmake_minimum_required(VERSION 3.27) project(ffmpeg_open_stream) set(CMAKE_CXX_STANDARD 17)#头文件包目录 include_director…

可调恒流电子负载优点和应用

可调恒流电子负载是一种可以模拟真实负载的电子设备&#xff0c;它可以在电源电压和电流范围内提供恒定的电流或电压。这种设备在许多领域都有广泛的应用&#xff0c;如电力系统、通信设备、汽车电子、航空航天等。以下是可调恒流电子负载的优点和应用。 优点&#xff1a; 精确…

HarmonyOS NEXT应用开发之ArkWeb同层渲染

介绍 该方案展示了ArkWeb同层渲染&#xff1a;将系统原生组件直接渲染到前端H5页面上&#xff0c;原生组件不仅可以提供H5组件无法实现的一些功能&#xff0c;还能提升用户体验的流畅度 效果图预览 使用说明 进入页面即可看到同层渲染效果&#xff0c;Text&#xff0c;searc…

-bash: ./1.sh: /bin/bash^M: bad interpreter: No such file or directory解决方法

1、执行脚本 ./1.sh时报如下错误 -bash: ./1.sh: /bin/bash^M: bad interpreter: No such file or directory 2、在Windows编辑的脚本导入Linux系统中&#xff0c;执行报错问题 yum install -y dos2unix 3、或者本地安装 rpm -ivh /mnt/Packages/dos...... 4、然…

【战略前沿】丹麦正在建造一台英伟达人工智能超级计算机

【原文】Denmark is building an Nvidia AI supercomputer 【作者】Linnea Ahlgren 它将于今年上线&#xff0c;并以新的量子计算软件为特色。 过去一年最大的赢家——芯片制造商英伟达&#xff08;Nvidia&#xff09;和制药制造商诺和诺德&#xff08;Novo Nordisk&#xff0…