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>
结果
在使用GPU的情况下,速度不算很快,还需要进一步优化