C++调用python代码
使用的环境
python3.9.13
opencv4.6.0
VS2019_community
可能遇到的问题
一、在Release,X64的环境下可以运行,但是在Debug,X64环境下无法运行
在进行了相同的配置后,发现在Debug配置下无法运行,并报错误ModuleNotFoundError: No module named ‘numpy.core._multiarray_umath‘
可能是Numpy版本的原因,也可能是python3.9的Debug不支持到VS2019,但是无从解决
并需要注意到,在配置了numpy的include,lib目录后不要更新numpy==1.xx.x到2.xx版本,2.xx版本的numpy路径有变化,会导致前面的路径失效
二、遇到无法找到python39_d.lib的问题
第一考虑项目配置属性有没有错误
第二考虑是否有安装python的Debug功能
按如下操作查看
Modify -> 再点下next来到如下界面,查看红框内两个Debug功能是否有框选
没框选的话选上,然后install安装,再到python39/libs中查看是否有python39_d.lib,有的话应该就安装成功了
主要流程如下
1. 配置好Python环境和opencv环境
要安装正确版本的python,并配置好系统变量中的Path,如果本机中安装有多个python版本,需将当前项目要使用的python版本系统变量放到其他系统变量的上方,最好置顶,如下所示
安装好opencv,注意与python的版本支持问题,如opencv-gpu目前只支持python3.8
opencv一样把路径添加到环境变量中的Path
最好将vc15/bin 也添加到Path中,不然后面可能遇到找不到opencv_worldxxx.dll的问题,选择vc14就添加vc14
2. 项目结构
2.1 在VS中创建一个C++项目
选择C++控制台应用,项目名称自取,勾选(默认) 解决方案与项目放在同一目录
2.2 导入python项目
将python项目放到C++项目目录下
右击解决方案->添加->现有项
选择刚才放到路径下的项目中的python project文件
2.3 编写C++代码
可以先配置好 3.项目属性配置 再来写C++调用python的代码
在ConsoleApplication1.cpp中编写代码,C++调用python代码样例如下
#include <Python.h>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <windows.h>
#include <numpy/ndarrayobject.h>
using namespace cv;
using namespace std;
#define myExport extern "C" __declspec(dllexport)
#define PI acos(-1)
//导入模型
int import_model(PyObject*& pDict) {
import_array(); //初始化 NumPy 模块
if (!Py_IsInitialized()) { //初始化python接口
cout << "python init fail" << endl;
PyErr_Print();
return -1;
}
PyObject* pModule = NULL; //初始化变量名为NULL
PyObject* pFuncFive = NULL;
PyObject* pReturn = NULL;
PyRun_SimpleString("import sys"); //初始化python系统文件路径,保证可以访问到 .py文件
PyRun_SimpleString("sys.path.append('PyC')"); //PyC是C++所调用的Python文件所在的路径。
pModule = PyImport_ImportModule("PyC"); //调用python文件名。当前的测试python文件名是 PyC.py
if (pModule == NULL) {
cout << "Failed to import Python module" << endl;
PyErr_Print();
return -1;
}
pDict = PyModule_GetDict(pModule); //获取模块字典对象
if (pDict == NULL) {
cout << "Failed to get module dictionary" << endl;
PyErr_Print();
return -1;
}
pFuncFive = PyDict_GetItemString(pDict, "load_model"); //获取模块中的函数
if (pFuncFive == NULL) {
cout << "Failed to get module function 'load_model'" << endl;
PyErr_Print();
return -1;
}
pReturn = PyObject_CallObject(pFuncFive, NULL); //获取函数返回结果
if (pReturn == NULL) {
cout << "Failed to get model" << endl;
PyErr_Print();
return -1;
}
Py_XDECREF(pModule);
//Py_XDECREF(pFuncFive);
Py_XDECREF(pReturn);
return 0;
}
//调用函数获取单张图片中的烟条角度
void get_angle_info(string imgpath, string outpath, int max_angle, PyObject* pDict, char*& nResult) {
PyObject* pFuncFive = NULL;
PyObject* pReturn = NULL;
if (pDict == NULL) {
cout << "Failed to get module dictionary" << endl;
PyErr_Print();
return;
}
pFuncFive = PyDict_GetItemString(pDict, "check_angle"); //获取模块中的函数
if (pFuncFive == NULL) {
cout << "Failed to get module function 'check_angle'" << endl;
PyErr_Print();
return;
}
PyObject* pyStrImgpath = Py_BuildValue("s", imgpath.c_str());
PyObject* pyStrOutpath = Py_BuildValue("s", outpath.c_str());
PyObject* pyMaxAngle = Py_BuildValue("i", max_angle);
PyObject* ArgArray = PyTuple_New(3); //建立参数个数
PyTuple_SetItem(ArgArray, 0, pyStrImgpath); //第1个参数
PyTuple_SetItem(ArgArray, 1, pyStrOutpath); //第2个参数
PyTuple_SetItem(ArgArray, 2, pyMaxAngle); //第3个参数
pReturn = PyObject_CallObject(pFuncFive, ArgArray); //得到函数的返回结果
if (pReturn == NULL) {
cout << "Failed to get function return" << endl;
return;
}
PyArg_Parse(pReturn, "s", &nResult);
Py_XDECREF(ArgArray);
Py_XDECREF(pReturn);
}
myExport void APIGetAngleFromCSharp(char imgpath[], char outpath[], int max_angle, int flag[], char*& nResult, void*& pdict_ptr)
{
PyObject* pDict = NULL;
if (flag[0] == 0) { //回收数据集
Py_Initialize(); //打开python解析器
import_model(pDict);
flag[0] = 1;
pdict_ptr = (void*)pDict;
return;
}
pDict = (PyObject*)pdict_ptr;
if (pDict == NULL) {
cout << "Failed to get module dictionary" << endl;
return;
}
if (flag[1] == 1) {
//Py_XDECREF(pDict);
Py_Finalize();
return;
}
get_angle_info(imgpath, outpath, max_angle, pDict, nResult);
flag[2] = 1;
}
3. 项目属性配置
1.第一需要注意的是配置为 Debug 还是 Release ,以及是X64还是X86平台。
选哪个的操作一样,但是一定要注意运行时的选项要和配置属性时候选的是一样的
2.右击项目名称选择属性
3.此处我们选择Release与X64,并点击VC++目录,添加包含目录以及库目录的路径
4.其中包含目录添加python与opencv如下路径
5.库目录
6.选择C/C++ -> 预处理器 -> 预处理器定义并添加下面字段
NDEBUG
_CONSOLE
_CRT_NONSTDC_NO_DEPRECATE
_CRT_SECURE_NO_WARNINGS
7.选择链接器 -> 输入 -> 附加依赖项
此处注意
如果是 Debug 配置:此处添加 opencv_world460d.lib ; python39_d.lib
如果是 Release 配置:此处添加 opencv_world460.lib ; python39.lib
opencv和python版本不同会导致后面数字不同,python 3.8版本就是python38.lib,opencv可以到 lib 目录下看看,python在libs下
8.点应用或者确定,然后就可以在.cpp文件时写一下demo测试下调用python代码了