C++与Pyhon混合调在现实中有很多的应用场景,特别是对基于深度学习的产品开发上。所以无论是VS或者是QT都提供了相应的库来调用Python,本篇将以VS2019为例,大致讲述Python3.7在VS上混合编程的实现(注意:VS混合编程有很多的软件和硬件上的限制,特别是python版本,切勿使用3.9以上的python版本,以免个别函数调用出现问题)

1、Python环境的搭建
Python环境的搭建是混合编程实现的基础必要条件,这里主要包括,解释器的路径、解释器的debug模式(这点最容易出现问题)、python依赖包等,具体如下:
A、下载 Python 解释器并记录解释器位置
B、下载并安装 Debug 包(好多次调用失败就是这里出的错)

其中特别注意安装python版本的debug模式,具体安装如下:
a、右键点击更改

b、增加配置
c、下一步

d、选择debug模式并安装

C、安装代码运行所需依赖的 python 包

2、VS 开发环境的搭建
1、打开项目属性

2、添加库目录



3、常见函数的作用与使用
A、初始化 Py_Initialize(),使用函数前必做动作,可能产生错误,需要进行验证
B、变量申明 PyObject* pModule = NULL;
C、导入包或直接执行 python 指令 PyRun_SimpleString();
D、调用外部包或.py 文件 pModule = PyImport_ImportModule(“mytest”);
E、调用外部函数名或类 pFunc = PyObject_GetAttrString(pModule, “hello”);
F、调用函数 PyEval_CallObject(pFunc, NULL);
G、结束 python 调用 Py_Finalize();

4、参考代码

// testPython.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Python.h>
using namespace std;

//调用hello函数,测试调用外部函数及外部Python sys包的调用
void hello()
{
	Py_Initialize();//使用python之前,要调用Py_Initialize();这个函数进行初始化
	PyObject* pModule = NULL;//声明变量
	PyObject* pFunc = NULL;// 声明变量
	pModule = PyImport_ImportModule("mytest");//这里是要调用的文件名
	pFunc = PyObject_GetAttrString(pModule, "hello");//这里是要调用的函数名
	PyEval_CallObject(pFunc, NULL);//调用函数
	Py_Finalize();//调用Py_Finalize,这个根Py_Initialize相对应的。
}

//调用add函数,传两个int型参数  
void add()
{
	Py_Initialize();
	PyObject* pModule = NULL;
	PyObject* pFunc = NULL;
	pModule = PyImport_ImportModule("mytest");      //Python文件名  
	pFunc = PyObject_GetAttrString(pModule, "add");  //Python文件中的函数名  
	//创建参数:  
	PyObject* pArgs = PyTuple_New(2);               //函数调用的参数传递均是以元组的形式打包的,2表示参数个数  
	PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 5));//0---序号  i表示创建int型变量  
	PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 7));//1---序号  
	//返回值  
	PyObject* pReturn = NULL;
	pReturn = PyEval_CallObject(pFunc, pArgs);      //调用函数  
	//将返回值转换为int类型  
	int result;
	PyArg_Parse(pReturn, "i", &result);    //i表示转换成int型变量  
	cout << "5+7 = " << result << endl;

	Py_Finalize();
}

//Python测试列表
void testList()
{
	Py_Initialize();
	PyObject* pModule = NULL;
	PyObject* pList = NULL;
	PyObject* pFunc = NULL;
	PyObject* pArgs = NULL;

	pModule = PyImport_ImportModule("mytest");
	pFunc = PyObject_GetAttrString(pModule, "testList");
	pArgs = PyTuple_New(1); // 函数调用的参数传递均是以元组的形式打包的, 1表示参数个数

	double array[] = { 1.2, 4.5, 6.7, 8.9, 1.5, 0.5 };

	//创建list
	pList = PyList_New(6);
	for (int i = 0; i < PyList_Size(pList); i++)
	{
		PyList_SetItem(pList, i, PyFloat_FromDouble(array[i]));
	}

	PyTuple_SetItem(pArgs, 0, pList);

	//返回值  
	PyObject* pReturn = NULL;
	pReturn = PyEval_CallObject(pFunc, pArgs);//调用函数  

	Py_Finalize();
}
void TestOpencv() 
{
	Py_SetPythonHome(L"C:\\Users\\****\\Anaconda3");
	Py_Initialize();//使用python之前,要调用Py_Initialize();这个函数进行初始化
	PyObject* pModule = NULL;//声明变量
	PyObject* pFunc = NULL;// 声明变量
	PyRun_SimpleString("import sys");
	PyRun_SimpleString("print(sys.executable)");
	pModule = PyImport_ImportModule("change background");//这里是要调用的文件名
	pFunc = PyObject_GetAttrString(pModule, "ChangeBackground");//这里是要调用的函数名
	if (pFunc==NULL)
	{
		cout << "func exe erre!!" << endl;
	}
	PyEval_CallObject(pFunc, NULL);//调用函数
	Py_Finalize();//调用Py_Finalize,这个根Py_Initialize相对应的。
}
int main()
{
	cout << "Starting Test..." << endl;
	cout << "hello()-------------" << endl;
	hello();
	cout << "add()---------------" << endl;
	add();
	cout << "testList()----------" << endl;
	testList();
	TestOpencv();
	return 0;

}

python参考代码:

这里需要将python代码放置在VS生成的exe文件所在目录内,或者自己指定目录

### mytest.py代码
# -*- coding: utf-8 -*-
import sys

def hello():
    print(sys.executable)
def add(a,b):
    return a+b
def testList(mylist):
    print(mylist)

def GetValue():
    array_1 = [1,2,3,4,5]
    array_2 = [3, 4, 5, 6, 7]
    return array_1+array_2
print(GetValue())

基于Python的opencv测试代码:

## change background.py测试代码
#!/user/bin/env python
# -*-coding/utf-8 -*-
# Aouher Tao Hong

import cv2
import  numpy as np

def ChangeBackground():
    img = cv2.imread('photo.jpg')
    img_back = cv2.imread('background.png')
    # 日常缩放
    rows, cols, channels = img_back.shape
    img_back = cv2.resize(img_back, None, fx=0.7, fy=0.7)
    cv2.imshow('img_back', img_back)

    rows, cols, channels = img.shape
    img = cv2.resize(img, None, fx=0.4, fy=0.4)
    cv2.imshow('img', img)
    rows, cols, channels = img.shape  # rows,cols最后一定要是前景图片的,后面遍历图片需要用到

    # 转换hsv
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    # 获取mask
    lower_blue = np.array([78, 43, 46])
    upper_blue = np.array([110, 255, 255])
    mask = cv2.inRange(hsv, lower_blue, upper_blue)
    cv2.imshow('Mask', mask)

    # 腐蚀膨胀
    erode = cv2.erode(mask, None, iterations=1)
    cv2.imshow('erode', erode)
    dilate = cv2.dilate(erode, None, iterations=1)
    cv2.imshow('dilate', dilate)

    # 遍历替换
    center = [50, 50]  # 在新背景图片中的位置
    for i in range(rows):
        for j in range(cols):
            if dilate[i, j] == 0:  # 0代表黑色的点
                img_back[center[0] + i, center[1] + j] = img[i, j]  # 此处替换颜色,为BGR通道
    cv2.imshow('res', img_back)
    cv2.imwrite('output.jpg', img_back)

    cv2.waitKey(0)
    cv2.destroyAllWindows()

运行结果:

来源:黑桃不带K

物联沃分享整理
物联沃-IOTWORD物联网 » C++与Python混合编程

发表评论