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

一、注意事项

  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.pathPyObject *sys_path = PyObject_GetAttrString(sys_module, "path");if (!PyList_Check(sys_path)) {// sys.path不是列表,错误处理qDebug()<<"获取py搜索路径失败" ;// 释放python所用内存Py_Finalize();return 0;} else {// 将自定义路径添加到sys.pathint 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.pathPyObject *sys_path = PyObject_GetAttrString(sys_module, "path");if (!PyList_Check(sys_path)) {// sys.path不是列表,错误处理qDebug()<<"获取py搜索路径失败\n" ;return 0;} else {// 将自定义路径添加到sys.pathint appended = PyList_Append(sys_path, py_path_str);if (appended == -1) {// 错误处理qDebug()<<"添加py搜索路径失败" ;return 0;}// 将sys.path转换为QStringListQStringList pythonPathList;// 遍历sys.path列表for (Py_ssize_t i = 0; i < PyList_Size(sys_path); ++i) {PyObject *path_item = PyList_GetItem(sys_path, i);// 将路径元素转换为QStringQString path_str = QString::fromUtf8(PyUnicode_AsUTF8(path_item));// 添加到QStringListpythonPathList.append(path_str);// 减少引用计数Py_DECREF(path_item);}// 输出所有搜索路径到QDebugforeach (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赋值给pythonFilePathpythonDirectoryPath = Path;pythonDirectoryIsInit = true;
}

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

未完待续

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

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

相关文章

mysql增量备份与修复

MySQL数据库增量恢复 1.一般恢复 将所有备份的二进制日志内容全部恢复 2.基于位置恢复 数据库在某一时间点可能既有错误的操作也有正确的操作 可以基于精准的位置跳过错误的操作 发生错误节点之前的一个节点&#xff0c;上一次正确操作的位置点停止 3.基于时间点恢复 跳过…

Java面试篇:Redis使用场景问题(缓存穿透,缓存击穿,缓存雪崩,双写一致性,Redis持久化,数据过期策略,数据淘汰策略)

目录 1.缓存穿透解决方案一:缓存空数据解决方案二&#xff1a;布隆过滤器 2.缓存击穿解决方案一:互斥锁解决方案二:设置当前key逻辑过期 3.缓存雪崩1.给不同的Key的TTL添加随机值2.利用Redis集群提高服务的可用性3.给缓存业务添加降级限流策略4.给业务添加多级缓存 4.双写一致性…

2015年认证杯SPSSPRO杯数学建模C题(第一阶段)荒漠区动植物关系的研究全过程文档及程序

2015年认证杯SPSSPRO杯数学建模 C题 荒漠区动植物关系的研究 原题再现&#xff1a; 环境与发展是当今世界所普遍关注的重大问题, 随着全球与区域经济的迅猛发展, 人类也正以前所未有的规模和强度影响着环境、改变着环境, 使全球的生命支持系统受到了严重创伤, 出现了全球变暖…

C++动态内存管理:new/delete与malloc/free的对比

在C中&#xff0c;动态内存管理是一个至关重要的概念。它允许我们在程序运行时根据需要动态地分配和释放内存&#xff0c;为对象创建和销毁提供了灵活性。在C中&#xff0c;我们通常会用到两对工具&#xff1a;new/delete 和 malloc/free。虽然它们都能够完成类似的任务&#x…

Windows如何搭建 ElasticSearch 集群

单机 & 集群 单台 Elasticsearch 服务器提供服务&#xff0c;往往都有最大的负载能力&#xff0c;超过这个阈值&#xff0c;服务器 性能就会大大降低甚至不可用&#xff0c;所以生产环境中&#xff0c;一般都是运行在指定服务器集群中。 除了负载能力&#xff0c;单点服务器…

map china not exists. the geojson of the map must be provided.

map china not exists. the geojson of the map must be provided. 场景&#xff1a;引入echarts地图报错map china not exists. the geojson of the map must be provided. 原因&#xff1a; echarts版本过高&#xff0c;ECharts 之前提供下载的矢量地图数据来自第三方&…

[LeetCode]LCR 081. 组合总和

题目 思路 先找出数组中最小元素&#xff0c;与目标数比较&#xff1a; 若目标数小&#xff0c;则无组合可能&#xff1b; 若相等&#xff0c;则输出该最小元素&#xff1b; 若目标数大&#xff0c;则寻找一元素的组合可能&#xff0c;寻找二元素的组合可能 以candidates [2,3…

Future机制实际应用

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 常见的两种创建线程…

vue-office/docx插件实现docx文件预览

1.下包 //预览docx文件 npm install vue-office/docx vue-demi//如果是vue2.6版本或以下还需要额外安装 vue/composition-api2.引入 <template><div>//在src填入文档地址<VueOfficeDocx srchttp://...../xx.docx style"width:80%" rendered"re…

C++ 3.25作业

1、定义自己的命名空间&#xff0c;其中有string类型的变量&#xff0c;再定义两个函数&#xff0c;一个函数完成字符串的输入&#xff0c;一个函数完成求字符串长度&#xff0c;再定义一个全局函数完成对该字符串的反转 #include <iostream>using namespace std;namesp…

如何从外网访问内网服务器?

在网络通信中&#xff0c;内网服务器指的是位于私有网络内部的服务器&#xff0c;它们可以提供各种服务&#xff0c;如网站、应用程序等。由于安全性的考虑&#xff0c;内网服务器通常无法直接从外部网络访问。本文将介绍如何通过使用【天联】组网来实现从外网访问内网服务器的…

基于Spring Boot+Vue的美食推荐商城系统

末尾获取源码作者介绍&#xff1a;大家好&#xff0c;我是墨韵&#xff0c;本人4年开发经验&#xff0c;专注定制项目开发 更多项目&#xff1a;CSDN主页YAML墨韵 学如逆水行舟&#xff0c;不进则退。学习如赶路&#xff0c;不能慢一步。 目录 一、项目简介 二、开发技术与环…

Element-Plus下拉菜单边框去除教程

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

2016年认证杯SPSSPRO杯数学建模C题(第二阶段)如何有效的抑制校园霸凌事件的发生全过程文档及程序

2016年认证杯SPSSPRO杯数学建模 C题 如何有效的抑制校园霸凌事件的发生 原题再现&#xff1a; 近年来&#xff0c;我国发生的多起校园霸凌事件在媒体的报道下引发了许多国人的关注。霸凌事件对学生身体和精神上的影响是极为严重而长远的&#xff0c;因此对于这些情况我们应该…

【Unity】调整Player Settings的Resolution设置无效

【背景】 Build时修改了Player Settings下的Resolution设置&#xff0c;但是再次Building时仍然不生效。 【分析】 明显是沿用了之前的分辨率设定&#xff0c;所以盲猜解决办法是Build相关的缓存文件&#xff0c;或者修改打包名称。 【解决】 实测修改版本号无效&#xf…

Windows服务器性能监控

Windows服务器操作系统设计用于运行在客户端-服务器架构内的服务器上&#xff0c;这些服务器通常设计用于处理繁重的工作负载&#xff0c;并作为企业中涉及的大多数软件操作的骨干。因此&#xff0c;为了防止由于性能问题而导致的任何服务损失并保持操作的无缝流&#xff0c;Wi…

Linux-进程控制(进程创建、进程终止、进程等待)

一、进程创建 1.1 fork函数介绍 在命令行下我们可以通过 ./ exe文件 来创建一个进程&#xff0c;通过fork函数&#xff0c;我们可以通过代码的形式从一个进程中创建一个进程&#xff0c;新进程为子进程&#xff0c;原进程为父进程&#xff0c;子进程在创建时&#xff0c;会与…

教育建筑智慧能源管理平台解决方案【新型电力系统下的绿色校园能源管理平台】

一、行业特点 1.建筑类型多&#xff1a;集教学、科研、生活于一体&#xff0c;占地面积大&#xff0c;建筑类型多&#xff0c;功能划分复杂。 2.供电可靠性要求高&#xff1a;教育建筑中的高层建筑、图书馆、实验楼等特级和一级负荷比较多&#xff0c;一旦发生故障会危及生命…

STM32 ESP8266模块的曲折探索

这是本文的配套资料&#xff0c;最终工程请参考 新_ESP8266资料\stm32f103成功移植的项目 【免费】stm32f103c8t6esp8266资料资源-CSDN文库 一、等到了ready 产品参数 我使用的是ai-thinker的esp8266-01s&#xff0c;以下为产品规格书 引脚定义&#xff1a; 依据引脚定义&…

android studio忽略文件

右键文件&#xff0c;然后忽略&#xff0c;就不会出现在commit里面了 然后提交忽略文件即可