首页 > 编程语言 >VS2019 C++ 调用python函数/类对象的方法

VS2019 C++ 调用python函数/类对象的方法

时间:2023-01-18 15:15:16浏览次数:71  
标签:调用 VS2019 python Py C++ PyObject ArgArray

1.环境配置

  • VS工程配置要和python一致,安装的python如果是64位的,工程配置也要选成64位的
    在这里插入图片描述

  • 在工程配置中添加包含目录和库目录,添加python环境目录里的include和libs文件夹路径。想要运行的keras-yolo3是在Anaconda中配置的环境,所以相应的文件夹路径可以在Anaconda的环境文件中找到
    在这里插入图片描述

  • 打开项目属性页,【VC++目录】中的包含目录和库目录中设置上图中的python头文件和库文件目录
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 添加依赖项,【链接器】→【输入】→【附加依赖项】,添加libs目录里面的python35_d.lib,一开始是没有这个的,只有pyth35.lib,这里复制一份重命名为python35_d.lib,因为VS默认会检测后者,不改的话可能会报错。
    在这里插入图片描述在这里插入图片描述

  • 配置结束

二、C++中运行python代码

#include<python.h>
#include<iostream>

int main()
{
      Py_Initialize();//使用python之前,要调用Py_Initialize();这个函数进行初始化
      PyRun_SimpleString("print('hello world!')");
      Py_Finalize();
}

生成解决方案报错如下:
在这里插入图片描述原因:slots是QT的关键字,所以才出现该问题
解决方法:可以暂时将slots改名为slots1,重新生成解决方案,错误消除。

报错:缺少python35.dll,程序无法继续运行
解决方法:在Anaconda的安装包package文件夹下,找到复制粘贴到C:\Windows\System32目录下。
在这里插入图片描述报错:未经处理的异常
在这里插入图片描述Fatal Python error: Py_Initialize: unable to load the file system codec
报错原因:电脑上有其他版本的python,以前装的
解决方法:删除以前装的,或者是使用Py_SetPythonHome()指定python.exe路径,如下图:
在这里插入图片描述
运行程序发现跑不出print的结果,需要设置
1.在配置属性中,找到生成事件,在找到后期生成事件;
2.在命令行的右边空白处添加“editbin /SUBSYSTEM:CONSOLE $(OUTDIR)$(ProjectName).exe”,点击确定

运行结果:
在这里插入图片描述

三、c++调用python函数并输出返回值

	Py_SetPythonHome(L"D:\\Users\\simon\\Anaconda3\\envs\\keras-yolo3");//指定python.exe位置
	Py_Initialize(); //使用python前要调用此函数,进行初始化
	
	if (!Py_IsInitialized()) //如果没有初始化成功
	{
		cout << "fail to initial!" << endl;
		Py_Finalize();
	}

	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");//设置.py文件所在位置

	//声明变量
	PyObject* pModule = NULL; //.py文件 
	PyObject* pFunc = NULL;  //py文件中的函数
	PyObject* pParams = NULL; //函数参数
	PyObject* pResult = NULL;  //函数返回的结果
	
	pModule = PyImport_ImportModule("testPython"); //调用上述路径下的testPython.py文件
	if (pModule == NULL)
	{
		cout << "don't find the python file!" << endl;
	}
	 
	pFunc = PyObject_GetAttrString(pModule, "add_number");  //从指定.py文件中调用函数add_number
	pParams = Py_BuildValue("(ii)",1,1);//设置函数参数,i表示int整型,两个i表示有两个参数,s表示字符串等
	pResult = PyObject_CallObject(pFunc, pParams);//调用函数,返回计算结果

	int res;
	PyArg_Parse(pResult, "i", &res);//将返回结果转换成C++类型
	cout << "res:" << res << endl;

	Py_Finalize();

testPython.py中的add_number函数定义如下:

def add_number(a,b):
    return a+b

运行结果:
在这里插入图片描述
python函数中的不能含有print语句,否则PyImport_ImportModule(“testPython”)返回值为空。
替代方法:

import sys

	sys.stderr.write('test .....\n')

四、c++调用python类(调用yolo3对象,传图像参数)

因为需要转换图像格式,从opencv的Mat格式转为python的PIL格式,需要 用到numpy的C++接口,所以需要先配置一下
项目属性页:【VC++目录】→【包含目录】,配置如下目录,在头文件中 #include<numpy/arrayobject.h>
在这里插入图片描述在程序中写入import_array()时,报错
在这里插入图片描述
原因:import_array其实是一个宏定义,宏的最后有返回值,但和外层函数的返回值不同,所以报错。右击→速览定义可以看到
在这里插入图片描述解决方法:
1.去掉宏定义中的返回值(不合适,破坏封装好的numpy函数)
2.直接调用_import_array()函数,就没有返回值了

生成解决方案报错:
在这里插入图片描述
无法解析的外部符号 __imp___Py_RefTotal

无法解析的外部符号 __imp___Py_NegativeRefcount,该符号在函数 __import_array 中被引用

原因:产生这个错误,主要是因为python/C API配置文件中的Py_DEBUG/Py_TRACE_REFS引起,

解决方案:
修改python/C API的配置文件,修改目录:\include下的pyconfig.h和object.h文件:
1.找到目录,因为是用的Anaconda的虚拟配置环境,所以要修改的文件在Anaconda路径下
2.用everything搜索pyconfig,根据要调用的python文件所用的python版本,我用的3.5所以找到对应的路径
在这里插入图片描述
在这里插入图片描述
3.修改两个头文件object.h和pyconfig.h
在object中,修改54行的

/* Py_DEBUG implies Py_TRACE_REFS. */
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
#define Py_TRACE_REFS
#endif

/* Py_DEBUG implies Py_TRACE_REFS. */
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
//#define Py_TRACE_REFS
#endif

在pyconfig中,修改358行的

#ifdef _DEBUG
#	define Py_DEBUG
#endif

#ifdef _DEBUG
//#	define Py_DEBUG
#endif

4.保存两个h文件后,重新生成解决方案,报错消失。

PyObject_CallMethod()返回值为NULL

PyObject* pList = PyObject_CallMethod(pInstanceYOLO, "detect_image","O", ArgArray);
def detect_image(self, image):

原因:别人博客中说类方法的self参数不需要参数,但这边就是因为缺少了self参数才会出现问题

改为下式,pInstanceYOLO实例自身对应的就是self参数,format改为(OO)表示有两个输入对象参数

PyObject* pList = PyObject_CallMethod(pInstanceYOLO, "detect_image","(OO)", pInstanceYOLO, ArgArray);

调用类对象方法的代码如下

    Py_SetPythonHome(L"D:\\Users\\simon\\Anaconda3\\envs\\keras-yolo3");//指定python.exe位置
	Py_Initialize(); //使用python前要调用此函数,进行初始化,开启虚拟机
	
	if (!Py_IsInitialized()) //如果没有初始化成功
	{
		cout << "fail to initial!" << endl;
		Py_Finalize();
	}
	_import_array(); //PyArray_SimpleNewFromData之前必须先引入此函数

	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./keras-yolo3/')");//设置.py文件所在位置

	//声明变量
	PyObject* pModule = NULL; //.py文件 
	PyObject* pFunc = NULL;  //py文件中的函数
	PyObject* pClass = NULL; //类 
	PyObject* pInstance = NULL; //实例
	
	pModule = PyImport_ImportModule("yolo"); //调用上述路径下的yolo.py文件
	if (pModule == NULL)
	{
		cout << "Can't find the python file!" << endl;
	}

	//模块的字典列表
	PyObject* pDict = PyModule_GetDict(pModule); //获得Python模块中的函数列
	if (pDict == NULL)
	{
		cout << "Can't find the dictionary!" << endl;
		return;
	}

	//获取YOLO类
	PyObject* pClassYOLO = PyDict_GetItemString(pDict, "YOLO");//获取函数字典中的YOLO类
	if(pClassYOLO == NULL)
	{
		cout << "Can't find YOLO class!" << endl;
		return;
	}

	//构造YOLO类的实例
	PyObject* pInstanceYOLO = PyInstanceMethod_New(pClassYOLO);
	if (pInstanceYOLO == NULL)
	{
		cout << "Can't find YOLO instance!" << endl;
		return;
	}

	//读取图像并转换格式,opencv读取图像的存储格式是BGR格式,而PIL中为RGB,
	//本项目是用opencv读取图像,yolo3算法中用的是PIL格式,所以图像在传入yolo类之前需要先转换格式
	Mat src = imread("./keras-yolo3/small10.jpg");
	cvtColor(src, src, COLOR_BGR2RGB);//转成PIL格式
	int m, n;
	m = src.rows; //行数
	n = src.cols * 3; //列数*通道数
	unsigned char* data = (unsigned char*)malloc(sizeof(unsigned char) * m * n);
	int num = 0;
	for (int i = 0; i < m; i++)
	{
		for (int j = 0; j < n; j++)
		{
			data[num] = src.at<unsigned char>(i, j);
			num++;
		}
	}
	npy_intp Dims[2] = { m,n };  //图像的维度信息
	PyObject* PyArray = PyArray_SimpleNewFromData(2, Dims, NPY_UBYTE, data); //建立函数的形参
	PyObject* ArgArray = PyTuple_New(1);//新建长度为1的元组
	PyTuple_SetItem(ArgArray, 0, PyArray);//设置元组ArgArray[0]为PyArray图像

	//Mat src = imread("./keras-yolo3/small10.jpg");
	//cvtColor(src, src, COLOR_BGR2RGB);//转成PIL格式
	//int m, n,channels;
	//m = src.rows; //行数
	//n = src.cols ; //列数
	//channels = src.channels();//通道数
	//unsigned char* data = (unsigned char*)malloc(sizeof(unsigned char) * m * n*3);
	//int num = 0;
	//for (int i = 0; i < m; i++)
	//{
	//	for (int j = 0; j < n*3; j++)
	//	{
	//		data[num] = src.at<unsigned char>(i, j);
	//	}
	//}
	//npy_intp Dims[3] = { m, n, channels };  
	//PyObject* PyArray = PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE, data);
	//PyObject* ArgArray = PyTuple_New(1);//新建长度为1的元组
	//PyTuple_SetItem(ArgArray, 0, PyArray);//设置元组ArgArray[0]为PyArray图像

	
	//调用YOLO实例对象的函数
	PyObject* pList = PyObject_CallMethod(pInstanceYOLO, "detect_image","(OO)", pInstanceYOLO, ArgArray);//pInstanceYOLO对应self,ArgArray对应image
	if(pList == NULL)
	{
		cout << "Failed to use fucntion!" << endl;
		return;
	}

	Py_DECREF(ArgArray);
	Py_DECREF(PyArray);
	Py_DECREF(pInstanceYOLO);
	Py_DECREF(pDict);
	Py_Finalize();
  •  

是想在C++项目里调用python类封装的目标检测对象YOLO的,发现有很多问题,暂时解决不了…应该是因为python环境的问题,放弃了… 尝试keras模型的C++调用

比较有价值的参考

C++与Python的混合编程-C++调用Python
如何在C++中使用python类
c++调用python的代码、函数、类
C++中如何将图像作为参数传给Python函数
python的C接口中对参数类型的描述文件,如:i,O,s…
Python的C接口函数

 

标签:调用,VS2019,python,Py,C++,PyObject,ArgArray
From: https://www.cnblogs.com/lidabo/p/17059833.html

相关文章

  • c++生成csv文件并在python界面可视化
    前景概要为什么生成的是csv文件而不是txt文件因为txt在python那边处理起来比较麻烦需要两组数而数与数之间存在对应关系这样两组数同样需要两组就是两组xy数值然后......
  • 【C++】【Ctrl+CV即可食用】三维点拟合空间直线
    前景概述网上三维点拟合空间直线的代码很多大多数都是python或者matlab这里贴一个C++的代码原目的是拟合出直线之后任取两个点手动计算一下斜率数学原理最小二乘拟合......
  • Python工具箱系列(二十三)
    基于游标的操作游标是数据库操作的相对底层的能力。简单的操作如下:importmysql.connectorimportrandomhost='localhost'user='root'password='8848is8848'dbname=......
  • Python学习中的六个技巧小结
    1.引言“Beautifulisbetterthanugly.”上述为著名的TheZenofPython的第一句话,也是有追求的python开发人员的信条之一。所以我们的问题来了:如何编写漂亮的Python代......
  • python property使用
    classGoods():def__init__(self):self._price=""@propertydefprice(self):[email protected](self,val......
  • python 引用父类super
    classParent():def__init__(self,name):print(name)classSon(Parent):def__init__(self,name):super().__init__(name)s=Son(name="ccc")......
  • 类型提示和python函数中'->'的用法
    一、类型提示在python中,我们定义一个有参函数,调用该函数时需要传入参数,如下所示:#定义一个简单的函数defget_full_name(first_name,last_name):full_name=fir......
  • 如果有效python code review
    这篇文章主要介绍一些工具,方法,可以帮助我们做codepre-commit检查,这样我们做codereview之前,这些工具方法就帮我们解决了一些代码风格的问题和静态检查就能检查出来......
  • Python导入Excel表格数据并以字典dict格式保存
      本文介绍基于Python语言,将一个Excel表格文件中的数据导入到Python中,并将其通过字典格式来存储的方法。  我们以如下所示的一个表格(.xlsx格式)作为简单的示例。其中,表......
  • python3中(?P的正则应用
    importre'''其中?P可以理解为将字符串s分组处理并命名为province、city、block'''s='13g00x21yy'res=re.search('(?P<province>\d{2}).*(?P<city>\d{2}).*(?P<block>\d......