【c++ 调用python】


参考网站:

C++调用python脚本:C++opencv数据与python opencv数据交互
C++如何调用Python 多种类型调用

1、配置项目属性表

将Python目录下的include和libs文件夹路径配置到属性表中,如果需要用到虚拟环境,就把envs虚拟环境下的相关文件路径配置到属性表

如果 需要用到一些其他的第三方库 就要再次进行关联。例如用numpy 就需要去Lib/site-packages 下 关联需要用到的包

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、C++代码编辑

导入头文件 Python.h:#include <Python.h>

// 架构
 
#include <iostream>
#include "Python.h"
using namespace std;
int main() 
{
	//初始化Python环境 
	Py_SetPythonHome(L"D:\\anaconda");//路径为python.exe所在路径,注意使用双斜杠或反斜杠
	Py_Initialize();
	 
	// 添加项目所属 目录
	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('.')"); //路径问py文件所在目录,如果在当前目录下则使用 '.'
	 
	PyObject * pFunc = NULL;
	//导入模块
	PyObject* pModule = PyImport_ImportModule("test");//py文件名
	if (!pModule)
	{ 
		cout << "Python get module failed." << endl;
		return 0;
	}
	
	cout << "Python get module succeed." << endl;
	// PyObject_GetAttrString
	pFunc = PyObject_GetAttrString(pModule, "func"); //函数名为 func
	 
	PyEval_CallObject(pFunc, NULL); //调用 无返回类型
	Py_Finalize();
	 
	return 0; 
}

报错1:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
报错2
Python 错误 Fatal Python Error: Py_Initialize Unable to Load the File System Codec
通过 C/C++ 编译器加载 Python 的系统编解码器文件时出现问题。

以下因素可能导致 Python 中出现致命错误。

在系统/环境变量中找不到Python,所以系统无法定位到它。
可能有不止一种 Python 版本可用。
看来系统上没有正确安装Python。

报错3

Python path configuration:
  PYTHONHOME = (not set)
  PYTHONPATH = (not set)
  program name = 'python'
  isolated = 0      
  environment = 1
  user site = 1
  import site = 1
  sys._base_executable = 'C:\\code\\cpp\\PDFToDoc\\x64\\Release\\PDFToDoc.exe'
  sys.base_prefix = 'C:\\Users\\duole\\anaconda3'
  sys.base_exec_prefix = 'C:\\Users\\duole\\anaconda3'
  sys.platlibdir = 'lib'
  sys.executable = 'C:\\code\\cpp\\PDFToDoc\\x64\\Release\\PDFToDoc.exe'
  sys.prefix = 'C:\\Users\\duole\\anaconda3'
  sys.exec_prefix = 'C:\\Users\\duole\\anaconda3'
  sys.path = [
    'C:\\Users\\duole\\anaconda3\\python39.zip',
    '.\\DLLs',
    '.\\lib',
    'C:\\code\\cpp\\PDFToDoc\\x64\\Release',
  ]
Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
Python runtime state: core initialized
ModuleNotFoundError: No module named 'encodings'

Current thread 0x000042d4 (most recent call first):
<no Python frame>

在这里插入图片描述

3、传参类型表

在这里插入图片描述

1.调用无参 无返回值

PyEval_CallObject(pFunc, NULL);  //直接调用

2.调用无参 但有返回值

//调用无参 但有返回值

PyObject * pp = PyEval_CallObject(pFunc, NULL); //返回值给pp Object对象  
int res = 0; //接收数据 int类型   PyArg_Parse(pp, "i", &res); //类型转换 i就是整形  
cout << "res:" << res << endl;//输出结果

3.调用有参 无返回值

PyObject* pArgs = PyTuple_New(2); //初始化俩个参数
PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 2)); //0:表示序号。第一个参数。
PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 4)); //1:也表示序号。第二个参数。i:表示传入的参数类型是int类型。
PyEval_CallObject(pFunc, pArgs); //无返回类型

4.调用有参 有返回值

PyObject* pArgs = PyTuple_New(2); //初始化两个参数
PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 2)); //0:表示序号。第一个参数。
PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 4)); //1:也表示序号。第二个参数。i:表示传入的参数类型是int类型。
PyObject * pp = PyEval_CallObject(pFunc, pArgs); //无返回类型

int res = 0;
PyArg_Parse(pp, "i", &res);//转换返回类型
cout << "res:" << res << endl;//输出结果

5.c++ Mat 转 python Numpy

Mat转Numpy需要配置numpy库,见上面

#include <numpy/arrayobject.h> //导入numpy头文件
Mat img = imread("./frame.png"); // 读取图片
 
if (img.empty())
{
	cout << "img read wrong" << endl;
	Py_Finalize();
	return -1;
} 
cout << img.size() << endl; 

// CV::Mat 转 python numpy------------------------------------
auto sz = img.size(); // 获取图像的尺寸
int x = sz.width;
int y = sz.height;
int z = img.channels();
uchar *CArrays = new uchar[x*y*z];//这一行申请的内存需要释放指针,否则存在内存泄漏的问题
 
int iChannels = img.channels();
int iRows = img.rows;
int iCols = img.cols * iChannels;
if (img.isContinuous())
{
	iCols *= iRows;
	iRows = 1;
}
 
uchar* p;
int id = -1;
 
for (int i = 0; i < iRows; i++)
{
	// get the pointer to the ith row
	p = img.ptr<uchar>(i);
	// operates on each pixel
	for (int j = 0; j < iCols; j++)
	{
		CArrays[++id] = p[j];//连续空间
	}
}
 
import_array1(-1);
npy_intp Dims[3] = { y, x, z }; //注意这个维度数据!
 
PyObject *PyArray = PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE, CArrays); 

报错:

在这里插入图片描述

解决办法:在Py_Initialize()后加入“import_array()”语句即可。 在有返回值的函数里,括号里需要有对应类型的返回值

在这里插入图片描述

注意:当编译"import_array()"时,可能会出现以下错误:

在这里插入图片描述
在这里插入图片描述

解决方法:在自己安装的python目录中搜索"object.h"文件,将其56行"#define Py_REF_DEBUG"语句注释掉即可。

在这里插入图片描述
在这里插入图片描述

6.c++ PyArrayObject 转 Mat

//将PyObject *pReturn 转换为Mat类型
PyArrayObject *Py_array1;
 
//读取从python脚本返回的numpy值 
//查看是否是元组数据 
if (PyTuple_Check(pReturn)) 
{
	//当返回值不止一个,pReturn是一个元组
	PyArg_UnpackTuple(pReturn, "ref", 2, 2, &Py_array1, &a); //解析元组的内容
	 
	//获取矩阵维度
	npy_intp *Py_array1_shape = PyArray_DIMS(Py_array1); //获取元组第一个元素(矩阵)的大小
	 
	npy_intp array1row = Py_array1_shape[0];
	npy_intp array1col = Py_array1_shape[1]; 
	npy_intp array1high = Py_array1_shape[2];
	 
	Mat mask(array1row, array1col, CV_8UC3, PyArray_DATA(Py_array1));
	 
	imwrite("./cut.png", mask); 
	imshow("su", mask); 
	waitKey(0);
	 
	// Py_XDECREF(PyArray);
	/*这里Py_XDECREF(ArgList); 和 Py_XDECREF(PyArray);不能同时使用,否则会引起内存访问冲突
	* 我的理解是:PyTuple_SetItem并不复制数据,只是引用的复制。因此对这两个对象中的任意一个使用
	* Py_XDECREF都可以回收对象。使用两次的话反而会导致冲突。
	*/
	 
	Py_XDECREF(ArgList);
	delete[] CArrays; // 释放数组内存,最好在PyArray被使用完以后释放
	CArrays = nullptr;
	Py_XDECREF(pReturn); 
}

VS Qt中C++调用Python 报错
在这里插入图片描述

问题出在python.h这个头文件中存在一个变量名叫“slots”,然而slots又是qt的关键字,所以qt的moc会把它当成宏先处理掉。

找到python/include下object.h文件 将第448行改为
在这里插入图片描述

#undef slots
PyType_Slot *slots; /* terminated by slot==0. */
#define slots Q_SLOTS

c++ 调用Python接口 Mat传参与接收 完整代码
c++端代码

#include "Python.h"
#include <numpy/ndarrayobject.h>
#include <opencv2/opencv.hpp>
#include <iostream>
 
using namespace cv;
using namespace std;
 
int main() 
{
	// 初始化-----------------------------------------------
	Py_SetPythonHome(L"D:/anaconda"); 
	Py_Initialize();
	 
	cout << "Python start --------------------" << endl;
	if (!Py_IsInitialized()) 
	{
		cout << "Python start defeat--------------------" << endl;
		return -1;
	}
	 
	// 加载python文件----------------------------------------------
	 
	PyRun_SimpleString("import sys"); 
	PyRun_SimpleString("sys.path.append('.')"); // demo_test.py的路径
	 
	PyObject *moduleName = PyUnicode_FromString("demo_test"); //载入名为demo_test.py的文件
	
	PyObject *pModule = PyImport_Import(moduleName);
	if (!pModule)
	{ 
		//如果不存在改文件,则结束
		printf("can't find python file");
		Py_Finalize(); //关闭python解释器
		return -1;
	}
	 
	PyObject *pFunc = PyObject_GetAttrString(pModule, "run"); //获取函数
	 
	if (!pFunc)
	{
		printf("can't find function [run]");
		Py_Finalize();
		return -1;
	}
	 
	int *a; 
	// 读取图片---------------------------------------------------
	Mat img = imread("frame.png"); // 读取图片 
	if (img.empty()) 
	{ 
		cout << "img read wrong" << endl;
		Py_Finalize(); 
		return -1; 
	}
	cout << img.size() << endl;
	 
	// CV::Mat 转 python numpy------------------------------------
	auto sz = img.size(); // 获取图像的尺寸
	int x = sz.width;
	int y = sz.height;
	int z = img.channels();
	 
	uchar *CArrays = new uchar[x*y*z];//这一行申请的内存需要释放指针,否则存在内存泄漏的问题
	
	int iChannels = img.channels();
	int iRows = img.rows;
	int iCols = img.cols * iChannels; 
	if (img.isContinuous())
	{
		iCols *= iRows; 
		iRows = 1;
	}
	 
	uchar* p;
	int id = -1;
	for (int i = 0; i < iRows; i++) 
	{
		// get the pointer to the ith row
		p = img.ptr<uchar>(i);
		// operates on each pixel 
		for (int j = 0; j < iCols; j++) 
		{ 
			CArrays[++id] = p[j];//连续空间 
		}
	}
	 
	import_array1(-1);
	npy_intp Dims[3] = { y, x, z }; //注意这个维度数据!
	PyObject *PyArray = PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE, CArrays);
	 
	// 准备其他python函数需要的参数
	//...
	// 将图片以及其他参数进行封装
	 
	PyObject *ArgList = PyTuple_New(1); //参数列表:创建一个长度为1的元组
	PyTuple_SetItem(ArgList, 0, PyArray); //将PyArray的引用指向元组ArgList的第0个元素
	 
	PyObject *pReturn = PyObject_CallObject(pFunc, ArgList);
	if (pReturn == NULL) 
	{
		printf("Return value is NULL.");
		Py_Finalize();
		return -1;
	}
	 
	PyArrayObject *Py_array1;
	 
	//读取从python脚本返回的numpy值 
	//查看是否是元组数据
	if (PyTuple_Check(pReturn)) 
	{
		//当返回值不止一个,pReturn是一个元组
		PyArg_UnpackTuple(pReturn, "ref", 2, 2, &Py_array1, &a); //解析元组的内容
		
		//获取矩阵维度 
		npy_intp *Py_array1_shape = PyArray_DIMS(Py_array1); //获取元组第一个元素(矩阵)的大小
		 
		npy_intp array1row = Py_array1_shape[0];
		npy_intp array1col = Py_array1_shape[1];
		npy_intp array1high = Py_array1_shape[2];
		
		Mat mask(array1row, array1col, CV_8UC3, PyArray_DATA(Py_array1));
		imwrite("test.png", mask);
		imshow("out", mask);
		waitKey(0);
		 
		// Py_XDECREF(PyArray); 
		/*这里Py_XDECREF(ArgList); 和 Py_XDECREF(PyArray);不能同时使用,否则会引起内存访问冲突
		* 我的理解是:PyTuple_SetItem并不复制数据,只是引用的复制。因此对这两个对象中的任意一个使用
		* Py_XDECREF都可以回收对象。使用两次的话反而会导致冲突。
		*/
		 
		Py_XDECREF(ArgList); 
		delete[] CArrays; // 释放数组内存,最好在PyArray被使用完以后释放 
		CArrays = nullptr; 
		Py_XDECREF(pReturn);
	}
	 
	//Py_CLEAR(moduleName); 
	//Py_CLEAR(pModule);
	
	Py_XDECREF(moduleName);
	Py_XDECREF(pModule);
	Py_XDECREF(pFunc); //Py_XDECREF是很有必要的,为了避免内存泄漏
	Py_Finalize(); // 关闭Python 
	return 0; 
}
 

python端代码

注意这里的返回值是元祖形式

#coding:utf-8
import cv2
import numpy as np      
 
def run(imgdata):
	return imgdata, 0

完结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

【网络星空】

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值