首页 > 编程语言 >C++ 调用 Python 接口 Mat转Numpy

C++ 调用 Python 接口 Mat转Numpy

时间:2023-08-15 11:23:31浏览次数:63  
标签:Mat PyArray Python array1 Py C++ PyObject PyTuple XDECREF

参考网站:

  1. https://blog.csdn.net/qq7835144/article/details/106073110?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-1&spm=1001.2101.3001.4242

  2. https://blog.csdn.net/weixin_46400740/article/details/116711323?spm=1001.2014.3001.5501

 

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:

 

 

 

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
 
 

完结 

 

 

标签:Mat,PyArray,Python,array1,Py,C++,PyObject,PyTuple,XDECREF
From: https://www.cnblogs.com/lidabo/p/17630785.html

相关文章

  • C/C++基础知识点——设计原则及设计模式
    如何实现模块间高内聚、低耦合?封装与抽象;添加中间层;模块化;设计思想与原则单一职责;接口隔离原则;依赖倒置;迪米特原则;多用组合少用继承;设计模式:观察者模式设计原则及设计模式六大设计原则:单一职责原则;里氏替换原则;开闭原则;依赖倒置原则;接口隔离原则;最少知识原则。......
  • esXGray开发笔记:基于直线检测的文本倾斜自动校正算法实现(python+opencv)
    昨日采用最小面积矩形的方式实现文本倾斜自动校正,但后面的角度有点麻烦,于是改用基本直线检测的算法。算法简介:检测直线,自动调节参数,至少获取11条直线(直线条数调节)计算每条直线与x轴夹角从返回的角度中找到出现次数较多的直线角度平均值并返回作为图片倾斜角度检测到角度后,就......
  • ADM4016I The index indexName on the source table source-table does not match any
    ADM4016I Theindex indexName onthesourcetable source-table doesnotmatchanypartitionedindexesonthetargettable target-table .ALTERTABLEATTACHprocessingcontinues.https://www.ibm.com/docs/en/db2/10.5?topic=messages-adm0000-adm5999LastUp......
  • python代码中取消运行中的warning
    在Python中,可以使用warnings模块来管理和控制警告的显示。你可以通过设置警告过滤器来控制是否显示特定类型的警告。以下是一些常见的方法来处理警告:过滤警告: 可以使用warnings.filterwarnings()函数来设置警告过滤器,从而控制是否显示特定类型的警告。比如,可以使用warnings.fil......
  • 7.1 C/C++ 实现动态数组
    动态数组相比于静态数组具有更大的灵活性,因为其大小可以在运行时根据程序的需要动态地进行分配和调整,而不需要在编译时就确定数组的大小。这使得动态数组非常适合于需要动态添加或删除元素的情况,因为它们可以在不浪费空间的情况下根据需要动态增加或减少存储空间。动态数组的内存......
  • 7.2 C/C++ 实现动态链表
    动态链表是一种常用的动态数据结构,可以在运行时动态地申请内存空间来存储数据,相比于静态数组和静态链表,更加灵活和高效。在动态链表中,数据元素被组织成一条链表,每个元素包含了指向下一个元素的指针,这样就可以通过指针将所有元素串联起来。使用动态链表存储数据时,不需要预先申请内......
  • 7.3 C/C++ 实现顺序栈
    顺序栈是一种基于数组实现的栈结构,它的数据元素存储在一段连续的内存空间中。在顺序栈中,栈顶元素的下标是固定的,而栈底元素的下标则随着入栈和出栈操作的进行而变化。通常,我们把栈底位置设置在数组空间的起始处,这样在进行入栈和出栈操作时,只需要维护栈顶指针即可。顺序栈的实现比......
  • 7.4 C/C++ 实现链表栈
    相对于顺序栈,链表栈的内存使用更加灵活,因为链表栈的内存空间是通过动态分配获得的,它不需要在创建时确定其大小,而是根据需要逐个分配节点。当需要压入一个新的元素时,只需要分配一个新的节点,并将其插入到链表的头部;当需要弹出栈顶元素时,只需要删除链表头部的节点,并释放其所占用的内......
  • 7.5 C/C++ 实现链表队列
    链表队列是一种基于链表实现的队列,相比于顺序队列而言,链表队列不需要预先申请固定大小的内存空间,可以根据需要动态申请和释放内存。在链表队列中,每个节点包含一个数据元素和一个指向下一个节点的指针,头节点表示队头,尾节点表示队尾,入队操作在队尾插入元素,出队操作在队头删除元素,队......
  • python如何复现DES3加密
    importbase64fromCrypto.CipherimportDES3BS=8pad=lambdas:s+(BS-len(s)%BS)*chr(BS-len(s)%BS)#3DES的MODE_CBC模式下只有前24位有意义key=b'appapiche168comappapiche168comap'[0:24]iv=b'appapich'plaintext=pad("9f5......