【python的numpy数组(c++接口PyArrayObject*) 和c++的Mat的相互转换】

python的numpy数组(c++接口PyArrayObject*) 和c++的Mat的相互转换

背景

想要尝试qt+onnx跑个双目的模型,结果在onnx的c++版本上跑出现了谜之内存泄漏,为了先达成目标,先用c++调用python的函数来实现功能。
这时候出现一个需要考虑的问题:c++的Mat和python的numpy数组如何相互转换

需求定义

将保存在Mat内的图像传递到PyArrayObject内,将保存在PyArrayObject内的图像传递到Mat内

前人工作

参考这篇文章,实现了将mat内容传递到PyArrayObject*的功能,代码片段如下:

        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];//连续空间
            }
        }
 
        npy_intp Dims[3] = { y, x, z}; //注意这个维度数据!
        PyObject *PyArray = PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE, CArrays);
		/*   些许操作之后,最后释放内存 */
        delete []CArrays ;
        CArrays =nullptr;

探索尝试过程

在网上冲浪好半天,可能是眼残啊,没找到啥将保存在PyArrayObject*内的图像传递到Mat内的实现,于是自己尝试了一下:

void np2mat(PyObject* np, Mat& img)
{
    PyArrayObject *arr = (PyArrayObject *)np;
    
    auto sz = img.size();
    int x = sz.width;
    int y = sz.height;
    int z = img.channels();
    int size = x*y*z;
    
    memcpy((uchar*)img.data,arr->data,size);
}

在维度一致的情况下,可以实现功能。那看来要实现会比想象中简单,PyArrayObject和mat里的data都指向数组的首地址,反过来看将mat内容传递到PyArrayObject*也可以简化为:

void np2mat(PyObject* np, Mat& img)
{
    if(img.empty())
        return NULL;

    auto sz = img.size();
    int x = sz.width;
    int y = sz.height;
    int z = img.channels();
    npy_intp Dims[3] = { y, x, z}; //注意这个维度数据!

    PyArrayObject *PyArray = (PyArrayObject *)PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE,(uchar*)img.data);
    return (PyObject*) PyArray;
}

可能需要这么些个头文件,具体在电脑啥位置可以百度,和各人python环境位置相关:

#include <Python.h>
#include <object.h>
#include <numpy/arrayobject.h>

结果双目跑onnx(python)

在使用GPU的情况下,速度不算很快,还需要进一步优化

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
如果你有一个 C++ 数组,想要在 Python 中将其转化为 NumPy 矩阵,可以使用 `numpy.ctypeslib.as_array()` 函数。具体步骤如下: 1. 首先,需要将 C++ 数组导出为一个动态链接库(DLL 或 SO 文件),使得 Python 可以调用其中的函数。 2. 在 Python 中,使用 `numpy.ctypeslib.load_library()` 函数加载这个动态链接库,然后使用 `numpy.ctypeslib.as_array()` 函数将 C++ 数组转化为 NumPy 数组。 3. 最后,使用 `numpy.matrix()` 函数将 NumPy 数组转化为矩阵。 下面是一个简单的示例,假设有一个 C++ 数组 `a`,包含了一个 2x3 的矩阵: ```c++ // example.cpp #include <iostream> using namespace std; extern "C" { void get_array(double* arr, int m, int n) { double a[2][3] = {{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}}; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { arr[i * n + j] = a[i][j]; } } } } ``` 这是一个简单的函数,将一个 2x3 的矩阵导出为一个 C++ 数组。现在,可以使用 CMake 编译这个函数,生成一个名为 `example.so` 的动态链接库: ```cmake # CMakeLists.txt cmake_minimum_required(VERSION 3.0) project(example) set(CMAKE_CXX_STANDARD 11) set(CMAKE_POSITION_INDEPENDENT_CODE ON) add_library(example SHARED example.cpp) ``` 在 Python 中,可以使用下面的代码加载这个动态链接库,并将其中的数组转化为矩阵: ```python import numpy as np from numpy.ctypeslib import load_library, as_array # 加载动态链接库 lib = load_library('example.so', '.') # 调用函数,获取数组 m, n = 2, 3 arr = np.zeros((m, n)) lib.get_array(arr.ctypes.data_as(np.ctypeslib.c_void_p), m, n) # 将数组转化为矩阵 mat = np.matrix(arr) print(mat) ``` 输出结果如下: ``` [[1. 2. 3.] [4. 5. 6.]] ``` 需要注意的是,这种方法需要掌握 C++Python 的基础知识,如果不熟悉其中的一方,可能会遇到困难。此外,由于涉及到动态链接库的编译和加载,也会增加一定的复杂度。因此,如果在 Python 中处理矩阵是你的主要目的,建议直接使用 NumPy 数组,避免使用 C++ 数组
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值