win10 C++调用python脚本实现两个环境下opencv参数传递

win10 C++调用python脚本实现两个环境下opencv参数传

本文主要实现C++调用python脚本,实现向python函数传递图像和从python函数的返回值接收图像。

实现环境:win10+vs2015+Anaconda3

vs2015配置opencv

vs2015配置python环境

由于涉及到opencv参数传递,我们除了要在C++中调用python的相关函数,还需要调用numpy的相关函数。因此配置环境时即需要配置python,又需要配置numpy。

  • 在release模式下添加属性表,这里我将其命名为python
    在这里插入图片描述
  • 打开新创建的属性表,添加包含目录D:\Anaconda3\include 和 D:\Anaconda3\Lib\site-packages\numpy\core\include。这里的目录是我的Anaconda安装目录。第一个目录中包含python解释器,第二个目录中包含numpy的头文件。如下图所示。
    在这里插入图片描述
  • 添加库目录,路径分别为D:\Anaconda3\libs 和 D:\Anaconda3\Lib\site-packages\numpy\core\lib。同理,前者对应python,后者对应numpy。如下图所示。
    在这里插入图片描述
  • 添加依赖库,如下图所示。这两个依赖库分别是python37.lib 和 npymath.lib。分别位于D:\Anaconda3\libs 和 D:\Anaconda3\Lib\site-packages\numpy\core\lib。
    在这里插入图片描述
  • 到此为止属性配置完成。需要注意的是,目前只是针对release模式下进行属性配置。由于确实debug模式下所需要的依赖库,因此无法对debug模式进行属性配置。也有些博客讲解了如何生成debug模式下的python依赖库。

代码(部分代码来自于其他CSDN博客,由于该博客成文较晚,忘记了那些参考链接,如有侵权请留言)

C++代用python代码最糟心的一点是内存泄漏,我的代码并不能完全避免内存泄漏,至少目前还不敢保证没有问题。仍在进一步的测试中。

  • python代码
#coding:utf-8
import cv2

def run(imgdata):		# 输入参数是一张图片
	print(imgdata.shape)		# 打印图片尺寸
	return imgdata, 0		# 返回图片和一个数字
  • C++代码
#include "Python.h"
#include <numpy/arrayobject.h>	
//配置属性表以后vs就可以检测到这两个头文件。如果没有,切换一下release、debug模式,刷新一下
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

int main() {
	Py_SetPythonHome(L"D:\\Anaconda3");		//设置Python路径
	Py_Initialize();	// 初始化Python
	import_array();		// 使用Numpy的相关函数前必须声明这一行代码
	// 检查初始化是否成功
	if (!Py_IsInitialized())
		return -1;


	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");	// demo_test.py的路径,这里与c_call_python放在同一个目录下
	PyObject *moduleName = PyUnicode_FromString("demo_test");  //载入名为demo_test.py的文件
	PyObject *pModule = PyImport_Import(moduleName); 
	if (!pModule)		//如果不存在改文件,则结束
	{
		printf("can't find py");
		getchar();		//点击回车关闭窗口
		Py_Finalize();			//关闭python解释器
		return -1;
	}


	int *a;
	for (int i = 1; i<10000000000; i++)  // 重复执行测试稳定性
	{
		cout << i << endl;
		Mat img = imread("su.jpg");  // 读取图片
		if (img.empty())
		{
			Py_Finalize();
			return -1;
		}
	
		// 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];//连续空间
			}
		}
		npy_intp Dims[3] = { y, x, z }; //注意这个维度数据!
		PyObject *ArgList = PyTuple_New(1);  //参数列表:创建一个长度为1的元组
		PyObject *PyArray = PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE, CArrays);
		PyTuple_SetItem(ArgList, 0, PyArray); //将PyArray的引用指向元组ArgList的第0个元素
		PyObject *pFunc = PyObject_GetAttrString(pModule, "run");  //获取函数
		if (!pFunc)
		{
			printf("can't find function [run]");
			getchar();
			Py_Finalize();
			return -1;
		}
		PyObject *pReturn = PyObject_CallObject(pFunc, ArgList);
		if (pReturn == 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)); //转三通道彩色图
			// Py_XDECREF(PyArray);
			/*这里Py_XDECREF(ArgList); 和 Py_XDECREF(PyArray);不能同时使用,否则会引起内存访问冲突
			 * 我的理解是:PyTuple_SetItem并不复制数据,只是引用的复制。因此对这两个对象中的任意一个使用
			 * Py_XDECREF都可以回收对象。使用两次的话反而会导致冲突。
			 */
			Py_XDECREF(ArgList);
			delete[] CArrays;		// 释放数组内存,最好在PyArray被使用完以后释放
			CArrays = nullptr;
			Py_XDECREF(pFunc);		//Py_XDECREF是很有必要的,为了避免内存泄漏
			Py_XDECREF(pReturn);	
			// delete(Py_array1);
			// imshow("su", mask);
			// waitKey(0);
			mask.release();
		}
	}
	// Py_CLEAR(moduleName);
	// Py_CLEAR(pModule);
	Py_XDECREF(moduleName);
	Py_XDECREF(pModule);
	Py_Finalize();	// 关闭Python
	// system("pause");
	// getchar();
	return 0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值