文章目录
参考网站:
C++调用python脚本:C++opencv数据与python opencv数据交互
C++如何调用Python 多种类型调用
1、配置项目属性表
将Python目录下的include和libs文件夹路径配置到属性表中,如果需要用到虚拟环境,就把envs虚拟环境下的相关文件路径配置到属性表
如果 需要用到一些其他的第三方库 就要再次进行关联。例如用numpy 就需要去Lib/site-packages 下 关联需要用到的包
2、C++代码编辑
导入头文件 Python.h:#include <Python.h>
// 架构
#include <iostream>
#include "Python.h"
using namespace std;
int main()
{
//初始化Python环境
Py_SetPythonHome(L"D:\\anaconda");//路径为python.exe所在路径,注意使用双斜杠或反斜杠
Py_Initialize();
// 添加项目所属 目录
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('.')"); //路径问py文件所在目录,如果在当前目录下则使用 '.'
PyObject * pFunc = NULL;
//导入模块
PyObject* pModule = PyImport_ImportModule("test");//py文件名
if (!pModule)
{
cout << "Python get module failed." << endl;
return 0;
}
cout << "Python get module succeed." << endl;
// PyObject_GetAttrString
pFunc = PyObject_GetAttrString(pModule, "func"); //函数名为 func
PyEval_CallObject(pFunc, NULL); //调用 无返回类型
Py_Finalize();
return 0;
}
报错1:
报错2
Python 错误 Fatal Python Error: Py_Initialize Unable to Load the File System Codec
通过 C/C++ 编译器加载 Python 的系统编解码器文件时出现问题。
以下因素可能导致 Python 中出现致命错误。
在系统/环境变量中找不到Python,所以系统无法定位到它。
可能有不止一种 Python 版本可用。
看来系统上没有正确安装Python。
报错3
Python path configuration:
PYTHONHOME = (not set)
PYTHONPATH = (not set)
program name = 'python'
isolated = 0
environment = 1
user site = 1
import site = 1
sys._base_executable = 'C:\\code\\cpp\\PDFToDoc\\x64\\Release\\PDFToDoc.exe'
sys.base_prefix = 'C:\\Users\\duole\\anaconda3'
sys.base_exec_prefix = 'C:\\Users\\duole\\anaconda3'
sys.platlibdir = 'lib'
sys.executable = 'C:\\code\\cpp\\PDFToDoc\\x64\\Release\\PDFToDoc.exe'
sys.prefix = 'C:\\Users\\duole\\anaconda3'
sys.exec_prefix = 'C:\\Users\\duole\\anaconda3'
sys.path = [
'C:\\Users\\duole\\anaconda3\\python39.zip',
'.\\DLLs',
'.\\lib',
'C:\\code\\cpp\\PDFToDoc\\x64\\Release',
]
Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
Python runtime state: core initialized
ModuleNotFoundError: No module named 'encodings'
Current thread 0x000042d4 (most recent call first):
<no Python frame>
3、传参类型表
1.调用无参 无返回值
PyEval_CallObject(pFunc, NULL); //直接调用
2.调用无参 但有返回值
//调用无参 但有返回值
PyObject * pp = PyEval_CallObject(pFunc, NULL); //返回值给pp Object对象
int res = 0; //接收数据 int类型 PyArg_Parse(pp, "i", &res); //类型转换 i就是整形
cout << "res:" << res << endl;//输出结果
3.调用有参 无返回值
PyObject* pArgs = PyTuple_New(2); //初始化俩个参数
PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 2)); //0:表示序号。第一个参数。
PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 4)); //1:也表示序号。第二个参数。i:表示传入的参数类型是int类型。
PyEval_CallObject(pFunc, pArgs); //无返回类型
4.调用有参 有返回值
PyObject* pArgs = PyTuple_New(2); //初始化两个参数
PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 2)); //0:表示序号。第一个参数。
PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 4)); //1:也表示序号。第二个参数。i:表示传入的参数类型是int类型。
PyObject * pp = PyEval_CallObject(pFunc, pArgs); //无返回类型
int res = 0;
PyArg_Parse(pp, "i", &res);//转换返回类型
cout << "res:" << res << endl;//输出结果
5.c++ Mat 转 python Numpy
Mat转Numpy需要配置numpy库,见上面
#include <numpy/arrayobject.h> //导入numpy头文件
Mat img = imread("./frame.png"); // 读取图片
if (img.empty())
{
cout << "img read wrong" << endl;
Py_Finalize();
return -1;
}
cout << img.size() << endl;
// 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];//连续空间
}
}
import_array1(-1);
npy_intp Dims[3] = { y, x, z }; //注意这个维度数据!
PyObject *PyArray = PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE, CArrays);
报错:
解决办法:在Py_Initialize()后加入“import_array()”语句即可。 在有返回值的函数里,括号里需要有对应类型的返回值
注意:当编译"import_array()"时,可能会出现以下错误:
解决方法:在自己安装的python目录中搜索"object.h"文件,将其56行"#define Py_REF_DEBUG"语句注释掉即可。
6.c++ PyArrayObject 转 Mat
//将PyObject *pReturn 转换为Mat类型
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));
imwrite("./cut.png", mask);
imshow("su", mask);
waitKey(0);
// Py_XDECREF(PyArray);
/*这里Py_XDECREF(ArgList); 和 Py_XDECREF(PyArray);不能同时使用,否则会引起内存访问冲突
* 我的理解是:PyTuple_SetItem并不复制数据,只是引用的复制。因此对这两个对象中的任意一个使用
* Py_XDECREF都可以回收对象。使用两次的话反而会导致冲突。
*/
Py_XDECREF(ArgList);
delete[] CArrays; // 释放数组内存,最好在PyArray被使用完以后释放
CArrays = nullptr;
Py_XDECREF(pReturn);
}
VS Qt中C++调用Python 报错
问题出在python.h这个头文件中存在一个变量名叫“slots”,然而slots又是qt的关键字,所以qt的moc会把它当成宏先处理掉。
找到python/include下object.h文件 将第448行改为
#undef slots
PyType_Slot *slots; /* terminated by slot==0. */
#define slots Q_SLOTS
c++ 调用Python接口 Mat传参与接收 完整代码
c++端代码
#include "Python.h"
#include <numpy/ndarrayobject.h>
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
// 初始化-----------------------------------------------
Py_SetPythonHome(L"D:/anaconda");
Py_Initialize();
cout << "Python start --------------------" << endl;
if (!Py_IsInitialized())
{
cout << "Python start defeat--------------------" << endl;
return -1;
}
// 加载python文件----------------------------------------------
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('.')"); // demo_test.py的路径
PyObject *moduleName = PyUnicode_FromString("demo_test"); //载入名为demo_test.py的文件
PyObject *pModule = PyImport_Import(moduleName);
if (!pModule)
{
//如果不存在改文件,则结束
printf("can't find python file");
Py_Finalize(); //关闭python解释器
return -1;
}
PyObject *pFunc = PyObject_GetAttrString(pModule, "run"); //获取函数
if (!pFunc)
{
printf("can't find function [run]");
Py_Finalize();
return -1;
}
int *a;
// 读取图片---------------------------------------------------
Mat img = imread("frame.png"); // 读取图片
if (img.empty())
{
cout << "img read wrong" << endl;
Py_Finalize();
return -1;
}
cout << img.size() << endl;
// 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];//连续空间
}
}
import_array1(-1);
npy_intp Dims[3] = { y, x, z }; //注意这个维度数据!
PyObject *PyArray = PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE, CArrays);
// 准备其他python函数需要的参数
//...
// 将图片以及其他参数进行封装
PyObject *ArgList = PyTuple_New(1); //参数列表:创建一个长度为1的元组
PyTuple_SetItem(ArgList, 0, PyArray); //将PyArray的引用指向元组ArgList的第0个元素
PyObject *pReturn = PyObject_CallObject(pFunc, ArgList);
if (pReturn == NULL)
{
printf("Return value is 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));
imwrite("test.png", mask);
imshow("out", mask);
waitKey(0);
// Py_XDECREF(PyArray);
/*这里Py_XDECREF(ArgList); 和 Py_XDECREF(PyArray);不能同时使用,否则会引起内存访问冲突
* 我的理解是:PyTuple_SetItem并不复制数据,只是引用的复制。因此对这两个对象中的任意一个使用
* Py_XDECREF都可以回收对象。使用两次的话反而会导致冲突。
*/
Py_XDECREF(ArgList);
delete[] CArrays; // 释放数组内存,最好在PyArray被使用完以后释放
CArrays = nullptr;
Py_XDECREF(pReturn);
}
//Py_CLEAR(moduleName);
//Py_CLEAR(pModule);
Py_XDECREF(moduleName);
Py_XDECREF(pModule);
Py_XDECREF(pFunc); //Py_XDECREF是很有必要的,为了避免内存泄漏
Py_Finalize(); // 关闭Python
return 0;
}
python端代码
注意这里的返回值是元祖形式
#coding:utf-8
import cv2
import numpy as np
def run(imgdata):
return imgdata, 0
完结