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
#include
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()