在项目中,我们经常同时拥有Python和C++的代码,比如用Python跑深度学习,然后后续工程用C++实现,一种较为简便的实现方式为在Python和C++之间相互调用函数,而无需繁琐的代码转换。
下面介绍在Winsdows10、Visual Studio2022,用C++调用Python程序的环境配置和测试代码,以及opencv4的环境配置。
查看Anaconda虚拟环境位置(Python3.7)
(base) C:\Users\LENOVO>python
>>> import sys
>>> sys.path
//输出结果
['', 'E:\\Anaconda\\anaconda\\python37.zip', 'E:\\Anaconda\\anaconda\\DLLs', 'E:\\Anaconda\\anaconda\\lib', 'E:\\Anaconda\\anaconda', 'E:\\Anaconda\\anaconda\\lib\\site-packages', 'E:\\Anaconda\\anaconda\\lib\\site-packages\\win32', 'E:\\Anaconda\\anaconda\\lib\\site-packages\\win32\\lib', 'E:\\Anaconda\\anaconda\\lib\\site-packages\\Pythonwin']
我的虚拟环境目录是:
E:\Anaconda\anaconda
安装配置好虚拟环境,对已有python代码进行测试,确定能够在Pycharm等IDE中能够跑通。
C++调用Python其实就是建立了一个Python解释器。
在VS中,首先新建一个C++工程(命名:C_yolo7,设为启动项目),然后在同一个解决方案中新建Python工程(命名:Py_yolo7)。
目录如图所示:
C++中新建一个C_yolo7.cpp文件,代码如下:
#include <Python.h>
#include <iostream>
using namespace std;
int main()
{
cout << "load env " << endl;
//1、初始化python接口
Py_Initialize();
if (!Py_IsInitialized()) {
cout << "python init fail" << endl;
return 0;
}
//初始化变量为NULL
PyObject* pModule = NULL;
PyObject* pFunc = NULL;
PyObject* pName = NULL;
//2、初始化python系统文件路径,保证可以访问到 .py文件
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('../Py_yolo7')"); //../Py_yolo7是C++所调用的Python文件所在的路径,路径一定要对。
//3、调用python文件名。当前的测试python文件名是 Py_yolo.py
pModule = PyImport_ImportModule("Py_yolo");
if (pModule == NULL) {
cout << "module not found" << endl;
return 1;
}
//4、调用函数
pFunc = PyObject_GetAttrString(pModule, "AdditionFc");
if (!pFunc || !PyCallable_Check(pFunc)) {
cout << "not found function add_num" << endl;
return 2;
}
//5、给python传参数
PyObject* pArgs = PyTuple_New(2);
PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 2));
PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 4));
// 6、使用C++的python接口调用该函数
PyObject* pReturn = PyEval_CallObject(pFunc, pArgs);
// 7、接收python计算好的返回值
int nResult;
PyArg_Parse(pReturn, "i", &nResult);
cout << "return result is " << nResult << endl;
//8、结束python接口初始化
Py_Finalize();
return 0;
}
Python中新建两个文件Py_yolo.py和debug.py,代码如下:
Py_yolo.py
from debug import add
def AdditionFc(a, b):
print("Now is in python module")
c = add(a, b)
#c = a+b
print("{} + {} = {}".format(a, b, c))
return c
debug.py
import numpy
import cv2
def add(a, b):
print("hello")
return a + b + 2
目的:在C_yolo7.cpp中调用Py_yolo.py中的函数,同时Py_yolo.py又会调用debug.py中的函数,在debug.py中引入Python第三方库numpy和cv2,全面进行测试。
按照之前配置的Anaconda虚拟环境及其位置
1.右键C++工程,选择属性页
2.在VC++目录中,配置
包含目录:
E:\Anaconda\anaconda\include
库目录:
E:\Anaconda\anaconda\libs
python37.lib
5.配置环境变量
在系统变量-path中添加:
E:\Anaconda\anaconda
E:\Anaconda\anaconda\Scripts
E:\Anaconda\anaconda\Library
以及编辑系统变量
PYTHONHOME=E:\Anaconda\anaconda
若在Py文件中不能成功导入Python第三方库,可以尝试以下两个办法:
方法一:
将下面两个文件夹复制到C++编译的exe同目录下:
E:\Anaconda\anaconda\DLLs
E:\Anaconda\anaconda\Lib
//复制到这个文件夹下,xxx是C_yolo7 C++工程所在目录
×××\x64\Release\
方法二:
在Anaconda环境中,进入所需的虚拟环境,conda list或者pip list查看已经安装的Python第三方库,把在项目中所需的Python第三方库卸载后重新安装一遍即可(没安装的库安装一下),这个方法解决因环境冲突导致的问题。
(base) C:\Users\LENOVO>conda list
(base) C:\Users\LENOVO>pip3 uninstall xxx
(base) C:\Users\LENOVO>pip3 install xxx //xxx为第三方库名
load env
Now is in python module
hello
2 + 4 = 8
return result is 8
xxx\Cyolo\C_yolo7\x64\Release\C_yolo7.exe (进程 1064)已退出,代码为 0。
按任意键关闭此窗口...
1、官网下载opencv4版本
2、打开C++工程属性页面(路径依据个人路径而定):
包含目录:
E:\opencv\opencv\build\include
库目录:
E:\opencv\opencv\build\x64\vc15\lib
3、链接器->输入,添加附加依赖项:
opencv_world460.lib
4、配置环境变量:
系统变量 path中添加:
E:\opencv\opencv\build\x64\vc15\bin
建议重启电脑使环境变量生效。
5.测试代码
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat img = imread("E:\\opencv\\opencv_vs_test\\bus.jpg"); //添加自己的图片路径
namedWindow("opencv_test");
imshow("opencv_test", img);
waitKey(0);
return(0);
}
运行结果显示图片表示测试成功!
1、在c++中使用numpy库C++中使用numpy库
2、Python训练好深度模型(比如yolov7)后,一定要检查Python运行环境配置完全正确,才能在C++中正确调用,因为C++调用Python程序不正确时是不报错的,只会返回NULL,故如果程序能够在Pycharm等IDE中能跑通前提下,出错基本只能在环境配置和文件搜索路径上出问题了。
以下是C++利用opencv4读取图片,将图片数据传入Python中的yolov5进行推理,并将推理结果返回至C++的运行结果:
3、numpy C++调用Python部分官方文档numpy C++调用Python部分官方文档
4、C中处理Python的Numpy数组的代码范例
C中处理Python的Numpy数组的代码范例
后续更新如何在Linux下Python调用C++和C++调用Python,以及Windows下Python调用C++。