C++ 调用 Python 接口 Mat转Numpy

参考网站:

  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 下 关联需要用到的包

C++ 调用 Python 接口 Mat转Numpy

C++ 调用 Python 接口 Mat转Numpy

C++ 调用 Python 接口 Mat转Numpy

C++ 调用 Python 接口 Mat转Numpy

C++ 调用 Python 接口 Mat转Numpy

C++ 调用 Python 接口 Mat转Numpy

2、C++代码编辑

导入头文件 Python.h:#include

//  架构
#include
#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:

C++ 调用 Python 接口 Mat转Numpy

C++ 调用 Python 接口 Mat转Numpy

C++ 调用 Python 接口 Mat转Numpy

3、传参类型表

C++ 调用 Python 接口 Mat转Numpy

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++ Matpython Numpy

Mat转Numpy需要配置numpy库,见上面

#include   //导入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(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);

报错:

C++ 调用 Python 接口 Mat转Numpy

解决办法: Py_Initialize() 后加入”import_array()”语句即可。 在有返回值的函数里,括号里需要有对应类型的返回值

C++ 调用 Python 接口 Mat转Numpy

注意:当编译”import_array()”时,可能会出现以下错误:

C++ 调用 Python 接口 Mat转Numpy

解决方法:在自己安装的python目录中搜索”object.h”文件,将其56行”#define Py_REF_DEBUG”语句注释掉即可。

C++ 调用 Python 接口 Mat转Numpy

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 报错

C++ 调用 Python 接口 Mat转Numpy

问题出在python.h这个头文件中存在一个变量名叫”slots”,然而slots又是qt的关键字,所以qt的moc会把它当成宏先处理掉。

找到python/include下object.h文件 将第448行改为

C++ 调用 Python 接口 Mat转Numpy
#undef slots
    PyType_Slot *slots; /* terminated by slot==0. */
#define slots Q_SLOTS

c++ 调用Python接口 Mat传参与接收 完整代码

c++端代码

#include "Python.h"
#include
#include
#include

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(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

完结

Original: https://blog.csdn.net/d597797974/article/details/116746966
Author: 饮酒宿清风
Title: C++ 调用 Python 接口 Mat转Numpy

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/763268/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Python数据分析上机

    一,Numpy数值计算上机 1.创建数组并进行运算。(1)创建一个数值范围为0~1,间隔为0.01的数组,并查看该数组的维度。(2)创建100个服从正态分布的随机数,并查看数组的类…

    Python 2023年8月2日
    057
  • 数据结构之排序【直接插入排序和希尔排序的实现及分析】

    引言: 今天天气还是依然的冷,码字越来越不容易了,本来上次写了一个比较好的引言,但是因为电脑第二天没电,并且我没有保存,现在找不到了,所以今天我们的引言就这样吧!今天给大家介绍一下…

    Python 2023年10月27日
    041
  • python+django+vue搭建前后端分离项目Part1

    文章目录 Python环境搭建 安装django框架 创建django项目 * 新建static静态文件夹 创建django App(后端) 创建vue项目(前端) 集成vue项目…

    Python 2023年8月4日
    065
  • 参数化_PyTest:参数化简介

    使用参数化功能为Python软件包编写非常简洁的单元测试的指南。 第一部分将说明随附软件包的结构以及如何在您的系统上进行设置。 如果您只想查看PyTest中的参数化示例,则可以直接…

    Python 2023年9月14日
    041
  • js实现输入内容的实时字数统计

    效果 输入内容的同时,字数会相应同步改变 实现方式 使用jQuery实现的,比较简单。 $(‘#’).bind(‘input propertychange’, function (…

    Python 2023年6月12日
    081
  • python及pygame雷霆战机游戏项目实战05 改进的碰撞

    项目详细介绍 项目详细介绍 在这个系列中,将制作一个雷霆战机游戏。 ; 碰撞发生了什么? Pygame中的默认碰撞类型是使用 collide_rect()函数,该函数使用两个精灵的…

    Python 2023年9月19日
    054
  • pytest+request+allure+excel接口自动化搭建 从0到1【四 Allure测试报告】

    Allure报告的使用 安装Allure报告 * Mac下安装allure环境 allure使用 自定义Allure报告样式 * 修改报告输出格式 修改报告格式排版乱的问题 自定义…

    Python 2023年9月13日
    058
  • OpenCV-眼睛控制鼠标

    找来了一篇好玩的 大伙可以试试啊 如何用眼睛来控制鼠标?一种基于单一前向视角的机器学习眼睛姿态估计方法。在此项目中,每次单击鼠标时,我们都会编写代码来裁剪你们的眼睛图像。使用这些数…

    Python 2023年9月28日
    056
  • 直方图的绘制 基于python-matplotlib库

    文章目录 1.关于直方图 2 plt.hist() 3. 绘制一幅简单的 频数 分布直方图 4. 绘制一幅 频率 分布直方图 5. 累积分布直方图(水平方向) ʚʕ̯•͡˔•̯᷅ʔ…

    Python 2023年8月31日
    037
  • django_models_外键应用

    一、什么是主键,什么是外键 这是一个太老声长谈的问题,我认为1、主键:在一个数据库表格中的唯一标识,因此主键有个重要的属性,是不能重复且唯一,且不能为空,比如说,一个班级里有两个学…

    Python 2023年8月4日
    049
  • VScode配置Python开发环境

    一、下载安装 1.VScode的安装包 Visual Studio Code – Code Editing. Redefined 2.Python的安装包 Downlo…

    Python 2023年8月3日
    068
  • Ansible 企业级自动化运维平台开发实战

    一、运维开发 普通的运维方式:使用Xshell或者脚本去操作服务器。 运维开发的方式:可以实现把运维的工作Web化。 运维开发优点:可以把运维工作简单化、运维工作规划化。 运维开发…

    Python 2023年8月15日
    036
  • MySQL 学习笔记(五)–mysqldump

    mysqldump 与 –set-gtid-purged 设置 (1) mysqldump The mysqldump client utility performs …

    Python 2023年6月9日
    084
  • 联合迭代器与生成器,enumerate() 内置函数真香!

    花下猫语:Python 中很多内置函数的作用都非常大,比如说 enumerate() 和 zip(),它们使得我们在作迭代操作时极为顺手。这是一篇很多年前的 PEP,提议在 Pyt…

    Python 2023年6月9日
    076
  • input与print语法

    1.input输入语法 input是用来接收用户输入的一种语法,实现计算机与用户之间的交互,改方法有一个返回值,返回的是用户输入的字符串! 语法: res = input&…

    Python 2023年5月23日
    058
  • 我让我 9 岁的女儿利用 ChatGPT 来学习数学

    孩子问:什么是等值分数 Chat GPT:等值分数是具有相同值的分数,即使它们可能具有不同的分子和分母。例如,1/2 和 2/4 是等值分数,因为它们都表示相同的数量,即二分之一。…

    Python 2023年11月4日
    049
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球