基于Qt框架的C++调用python脚本

Debug版本

        QtCreator、Vs 配置python出现的问题可参考这两位位老哥的贴子

VS:

http://t.csdnimg.cn/BoIyXicon-default.png?t=N7T8http://t.csdnimg.cn/BoIyX

QtCreator:

http://t.csdnimg.cn/rwqpticon-default.png?t=N7T8http://t.csdnimg.cn/rwqpt

        一看他们就是没少踩坑的,里面出现的所有bug我都遇到过了,很感谢他们!

        首先针对debug版本的环境问题,如果你的电脑已经配置了anaconda或者pycharm环境或者环境变量,此时想在项目中安装单独的py版本,参照网上链接后,可能会出现环境变量始终无法改的问题,想要调试到debug,环境变量得设置为你安装的py版本位置,解决不了就只能卸载conda然后重新安装单独的py。

       现在默认你的环境变量已经设置好,开始初始化:

#ifdef QT_DEBUG
			Py_SetPythonHome(L"C:/Users/DELL/Desktop/Qt_Projects/CC_system/Template/env/pyforcpp");
			Py_Initialize();
			if (!Py_IsInitialized()) 
			{
				qDebug() << "无法初始化python解释器.";
				return false;
			}
			QString pythonPathAppend = "sys.path.append('" + QDir::currentPath() + "/lib/py_code" + "')";
			PyRun_SimpleString("import sys");
			PyRun_SimpleString(pythonPathAppend.toLocal8Bit().data());
			PyRun_SimpleString("sys.path.append('C:/Users/DELL/Desktop/Qt_Projects/CC_system/Template/env/pyforcpp/Lib/site-packages')");
#endif
  • Py_SetPythonHome:设置debug运行环境路径,为你项目中的py安装环境即可,我把py安装在项目根目录中的env/pyforcpp中(项目名:Template,环境:python38,官网下载即可):
Py_SetPythonHome(L"C:/Users/DELL/Desktop/Qt_Projects/CC_system/Template/env/pyforcpp");

  • Py_Initialize():c++中python配置的初始化,不能通过会报错;
Py_Initialize();
  • 设置py脚本所在的位置
QString pythonPathAppend = "sys.path.append('" + QDir::currentPath() + "/lib/py_code" + "')";
PyRun_SimpleString("import sys");
PyRun_SimpleString(pythonPathAppend.toLocal8Bit().data());
  • 设置三方库所在的位置
PyRun_SimpleString("sys.path.append('C:/Users/DELL/Desktop/Qt_Projects/CC_system/Template/env/pyforcpp/Lib/site-packages')");

Release版本

        和debug版本差不多,关键就在打包问题。Py_SetPythonHome设置你打包版本的环境,这个非常重要!!

#ifndef QT_DEBUG
			Py_SetPythonHome((wchar_t*)(L"./python_env"));

			Py_Initialize();
			if (!Py_IsInitialized())
			{
				qDebug() << "py初始化失败!";
			}

			PyRun_SimpleString("import sys");
			PyRun_SimpleString("sys.path.append(\"./\")");//这一步很重要,修改Python路径
#endif

qt打包

        首先不管是qt还是vs,找到release之后生成exe文件,先用windeployqt,把目标exe程序的qt库打包下来,假设目标文件夹为Template_Release;

python 脚本打包

        建议使用pyinstaller(使用方法自己百度),会生成build和dist文件:

        butter_c是我py脚本的名字,你只用含有找到很多.pyd和.dll目录即可,不同版本的pyinstaller生成的文件可能不同,将其下所有内容拷贝置Template_Release目录下(必须和qt生成目标exe在同一目录级),此时Template_Release目录下就有qt+py打包的文件;

python 环境打包

        在Template_Release目录下创建文件python_env,将env/pyforcpp中的如下文件拷贝至python_env中,因为代码里设置了Py_SetPythonHome((wchar_t*)(L"./python_env"));

其他需要注意的

        在Template_Release目录中还需要将你写好的所有py脚本放置进去

运行exe,如果还缺啥dll就往里面补啥,至此,Template_Release下的exe可以在未安装python环境的电脑运行。

完整代码

        在c++中调用py脚本,自己创建了一个单例工厂,有需要就copy,将指针传到你的项目中即可

#pragma once
#include <Python.h>
#include <QDebug>
class Python_Interpreter {
public:
	static Python_Interpreter& getInstance()
	{
		static Python_Interpreter instance;
		return instance;
	}

	bool initialize()
	{
		if (!Py_IsInitialized()) 
		{
			//debug
#ifdef QT_DEBUG
			Py_SetPythonHome(L"C:/Users/DELL/Desktop/Qt_Projects/CC_system/Template/env/pyforcpp");
			Py_Initialize();
			if (!Py_IsInitialized()) 
			{
				qDebug() << "无法初始化python解释器.";
				return false;
			}
			QString pythonPathAppend = "sys.path.append('" + QDir::currentPath() + "/lib/py_code" + "')";
			PyRun_SimpleString("import sys");
			PyRun_SimpleString(pythonPathAppend.toLocal8Bit().data());
			PyRun_SimpleString("sys.path.append('C:/Users/DELL/Desktop/Qt_Projects/CC_system/Template/env/pyforcpp/Lib/site-packages')");
#endif
#ifndef QT_DEBUG
			// 设置 Python 环境Template
			Py_SetPythonHome((wchar_t*)(L"./python_env"));

			Py_Initialize();
			if (!Py_IsInitialized())
			{
				qDebug() << "py初始化失败!";
			}

			PyRun_SimpleString("import sys");
			PyRun_SimpleString("sys.path.append(\"./\")");//这一步很重要,修改Python路径
#endif
		}
		return true;
	}

	void finalize()
	{
		if (Py_IsInitialized()) 
		{
			qDebug() << "无法正常终止python.";
			Py_Finalize();
		}
	}

	PyObject* importModule(const QString& moduleName)
	{
		return PyImport_ImportModule(moduleName.toStdString().c_str());

	}

	PyObject* getFunction(PyObject* module, const QString& functionName)
	{
		return PyObject_GetAttrString(module, functionName.toStdString().c_str());
	}

	//以下是自定义模块

	// 将Python列表转换为QVector<double>的辅助函数
	QVector<double> PyListToQVector(PyObject* pList);

	// 将QVector<double>转换为Python列表的辅助函数
	PyObject* PyList_FromVector(const QVector<double>& vector);

	//巴特沃斯滤波器
	QVector<double> butter(QVector<double>input, QString filter, int N, double col_fre, double Wn1=0.0, double Wn2 = 0.0);

	//自相关,互相关的误码率计算
	double getErrorRate(QVector<double>input1, QVector<double>input2, int L, int fos);


private:
	Python_Interpreter() {}
	Python_Interpreter(const Python_Interpreter&) = delete;
	Python_Interpreter& operator=(const Python_Interpreter&) = delete;
};

        程序中的自定义模块在对应cpp中实现即可,这边就展示一个py的有参调用

#include "Python_Interpreter.h"

double Python_Interpreter::getErrorRate(QVector<double>input1, QVector<double>input2, int L, int fos)
{
	double error = -1.0;
	if (!getInstance().initialize())
	{
		PyErr_Print();
		return error;
	}

	PyObject* pModule = getInstance().importModule("correlate_c");
	if (!pModule)
	{
		qDebug() << "无法加载 Python 模块。";

		PyErr_Print();
		return error;
	}

	PyObject* pFunc = getInstance().getFunction(pModule, "main_function");
	if (!pFunc || !PyCallable_Check(pFunc))
	{
		qDebug() << "无法获取 Python 函数。";
		Py_DECREF(pModule);

		PyErr_Print();
		return error;
	}

	// 在这里正确定义和初始化 pArgs 和 pResult
	PyObject* pArgs = PyTuple_New(4);
	PyTuple_SetItem(pArgs, 0, PyList_FromVector(input1)); // 将QVector转换为PyObject(Python列表)
	PyTuple_SetItem(pArgs, 1, PyList_FromVector(input2)); // 将QVector转换为PyObject(Python列表)
	PyTuple_SetItem(pArgs, 2, Py_BuildValue("i", L));//码元数目
	PyTuple_SetItem(pArgs, 3, Py_BuildValue("i", fos));//采样率


	PyObject* pResult = PyObject_CallObject(pFunc, pArgs);
	if (!pResult) {
		qDebug() << "无法调用python代码中的函数.";
		Py_DECREF(pArgs);
		Py_DECREF(pFunc);
		Py_DECREF(pModule);

		PyErr_Print();
		return error;
	}

	double output = PyFloat_AsDouble(pResult); // 直接解析返回值为double
	
	Py_DECREF(pArgs);
	Py_DECREF(pResult);
	Py_DECREF(pFunc);
	Py_DECREF(pModule);

	return output;

}

测试

        运行一下exe,看看butter_c.py中调用 numpy库 和 scipy库 的巴特沃斯滤波器的效果:

        运行速度很快很稳定,动态图像正确,完毕!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值