gbh*_*gbh 13 c++ arrays numpy vector
我正在尝试传递一个双打向量,我在我的C++代码中生成一个pythonnumpy数组.Python一旦我填充了numpy数组,我希望做一些下游处理并想要使用一些python工具.我想要做的最重要的事情之一是能够绘制事物,而C++在这方面有点笨拙.此外,我希望能够利用Python的统计能力.
虽然我不清楚如何做到这一点.我花了很多时间浏览Python C API文档.我遇到了一个函数PyArray_SimpleNewFromData,显然可以做到这一点.就代码的整体设置而言,我仍然不清楚.我正在构建一些非常简单的测试用例来帮助我理解这个过程.我在Visual Studio Express 2012中生成了以下代码作为一个Standlone Empty项目.我将此文件称为Project1
#include <Python.h>
#include "C:/Python27/Lib/site-packages/numpy/core/include/numpy/arrayobject.h"
PyObject * testCreatArray()
{
float fArray[5] = {0,1,2,3,4};
npy_intp m = 5;
PyObject * c = PyArray_SimpleNewFromData(1,&m,PyArray_FLOAT,fArray);
return c;
}
Run Code Online (Sandbox Code Playgroud)
我的目标是能够在Python中读取PyObject.我被困了,因为我不知道如何在Python中引用这个模块.特别是我如何从Python导入这个项目,我试图从python中的项目路径进行导入Project1,但失败了.一旦我理解了这个基本情况,我的目标是找出一种方法将我在main函数中计算的向量容器传递给Python.我不知道该怎么做.
任何可以帮助我的专家,或者可能发布一个简单的包含一些代码的例子,这些代码读入并从一个简单的c ++向量中填充一个numpy数组,我将不胜感激.提前谢谢了.
我不是cpp-hero,但想为我的解决方案提供一个用于1D和2D向量的模板函数.这是一个用于使用l8ter的内容,通过模板化1D和2D向量,编译器可以为您的矢量形状采用正确的版本.在2D的情况下,如果形状不规则,则抛出一个字符串.例程在这里复制数据,但是可以很容易地修改它以获取输入向量的第一个元素的地址,以使其只是一个"表示".
用法如下:
// Random data
vector<float> some_vector_1D(3,1.f); // 3 entries set to 1
vector< vector<float> > some_vector_2D(3,vector<float>(3,1.f)); // 3 subvectors with 1
// Convert vectors to numpy arrays
PyObject* np_vec_1D = (PyObject*) vector_to_nparray(some_vector_1D);
PyObject* np_vec_2D = (PyObject*) vector_to_nparray(some_vector_2D);
Run Code Online (Sandbox Code Playgroud)
您还可以通过可选参数更改numpy数组的类型.模板功能是:
/** Convert a c++ 2D vector into a numpy array
*
* @param const vector< vector<T> >& vec : 2D vector data
* @return PyArrayObject* array : converted numpy array
*
* Transforms an arbitrary 2D C++ vector into a numpy array. Throws in case of
* unregular shape. The array may contain empty columns or something else, as
* long as it's shape is square.
*
* Warning this routine makes a copy of the memory!
*/
template<typename T>
static PyArrayObject* vector_to_nparray(const vector< vector<T> >& vec, int type_num = PyArray_FLOAT){
// rows not empty
if( !vec.empty() ){
// column not empty
if( !vec[0].empty() ){
size_t nRows = vec.size();
size_t nCols = vec[0].size();
npy_intp dims[2] = {nRows, nCols};
PyArrayObject* vec_array = (PyArrayObject *) PyArray_SimpleNew(2, dims, type_num);
T *vec_array_pointer = (T*) PyArray_DATA(vec_array);
// copy vector line by line ... maybe could be done at one
for (size_t iRow=0; iRow < vec.size(); ++iRow){
if( vec[iRow].size() != nCols){
Py_DECREF(vec_array); // delete
throw(string("Can not convert vector<vector<T>> to np.array, since c++ matrix shape is not uniform."));
}
copy(vec[iRow].begin(),vec[iRow].end(),vec_array_pointer+iRow*nCols);
}
return vec_array;
// Empty columns
} else {
npy_intp dims[2] = {vec.size(), 0};
return (PyArrayObject*) PyArray_ZEROS(2, dims, PyArray_FLOAT, 0);
}
// no data at all
} else {
npy_intp dims[2] = {0, 0};
return (PyArrayObject*) PyArray_ZEROS(2, dims, PyArray_FLOAT, 0);
}
}
/** Convert a c++ vector into a numpy array
*
* @param const vector<T>& vec : 1D vector data
* @return PyArrayObject* array : converted numpy array
*
* Transforms an arbitrary C++ vector into a numpy array. Throws in case of
* unregular shape. The array may contain empty columns or something else, as
* long as it's shape is square.
*
* Warning this routine makes a copy of the memory!
*/
template<typename T>
static PyArrayObject* vector_to_nparray(const vector<T>& vec, int type_num = PyArray_FLOAT){
// rows not empty
if( !vec.empty() ){
size_t nRows = vec.size();
npy_intp dims[1] = {nRows};
PyArrayObject* vec_array = (PyArrayObject *) PyArray_SimpleNew(1, dims, type_num);
T *vec_array_pointer = (T*) PyArray_DATA(vec_array);
copy(vec.begin(),vec.end(),vec_array_pointer);
return vec_array;
// no data at all
} else {
npy_intp dims[1] = {0};
return (PyArrayObject*) PyArray_ZEROS(1, dims, PyArray_FLOAT, 0);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
由于对此没有答案,这实际上对可能正在寻找此类事情的人有帮助,因此我想我会提出一个简单的解决方案。
首先,您需要在 C++ 中创建一个 python 扩展模块,这很容易做到,并且都在 python c-api 文档中,所以我不打算深入研究。
现在将 c++ std::vector 转换为 numpy 数组非常简单。您首先需要导入 numpy 数组头
#include <numpy/arrayobject.h>
Run Code Online (Sandbox Code Playgroud)
在你的初始化函数中你需要 import_array()
PyModINIT_FUNC
inittestFunction(void){
(void) Py_InitModule("testFunction". testFunctionMethods);
import_array();
}
Run Code Online (Sandbox Code Playgroud)
现在您可以使用提供的 numpy 数组函数。你想要的就是 OP 几年前说的 PyArray_SimpleNewFromData,它使用起来非常简单。您只需要一个类型为 npy_intp 的数组,这是要创建的数组的形状。使用 testVector.size() 确保它与您的向量相同(对于多个维度,请执行 testVector[0].size(), testVector[0][0].size() 等。向量保证是连续的在 c++11 中,除非它是一个布尔值)。
//create testVector with data initialised to 0
std::vector<std::vector<uint16_t>> testVector;
testVector.resize(width, std::vector<uint16_t>(height, 0);
//create shape for numpy array
npy_intp dims[2] = {width, height}
//convert testVector to a numpy array
PyArrayObject* numpyArray = (PyArrayObject*)PyArray_SimpleNewFromData(2, dims, NPY_UINT16, (uint16_t*)testVector.data());
Run Code Online (Sandbox Code Playgroud)
通过参数。首先你需要将它转换为一个 PyArrayObject,否则它将是一个 PyObject 并且当返回到 python 时不会是一个 numpy 数组。2, 是数组中的维数。dims,是数组的形状。这必须是类型 npy_intp NPY_UINT16 是数组将在 python 中的数据类型。然后使用 testVector.data() 获取数组的数据,将其转换为 void* 或与向量具有相同数据类型的指针。
希望这可以帮助任何可能需要它的人。
(此外,如果您不需要纯粹的速度,我建议避免使用 C-API,它会导致很多问题,而 cython 或 swig 仍然可能是您的最佳选择。还有 c 类型可能会非常有用。
我在尝试做类似的事情时看到了你的帖子。我能够拼凑出一个解决方案,整个解决方案都在我的 Github 上。它生成两个 C++ 向量,将它们转换为 Python 元组,将它们传递给 Python,将它们转换为 NumPy 数组,然后使用 Matplotlib 绘制它们。
大部分代码来自 Python 文档。
以下是 .cpp 文件中的一些重要部分:
//Make some vectors containing the data
static const double xarr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14};
std::vector<double> xvec (xarr, xarr + sizeof(xarr) / sizeof(xarr[0]) );
static const double yarr[] = {0,0,1,1,0,0,2,2,0,0,1,1,0,0};
std::vector<double> yvec (yarr, yarr + sizeof(yarr) / sizeof(yarr[0]) );
//Transfer the C++ vector to a python tuple
pXVec = PyTuple_New(xvec.size());
for (i = 0; i < xvec.size(); ++i) {
pValue = PyFloat_FromDouble(xvec[i]);
if (!pValue) {
Py_DECREF(pXVec);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert array value\n");
return 1;
}
PyTuple_SetItem(pXVec, i, pValue);
}
//Transfer the other C++ vector to a python tuple
pYVec = PyTuple_New(yvec.size());
for (i = 0; i < yvec.size(); ++i) {
pValue = PyFloat_FromDouble(yvec[i]);
if (!pValue) {
Py_DECREF(pYVec);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert array value\n");
return 1;
}
PyTuple_SetItem(pYVec, i, pValue); //
}
//Set the argument tuple to contain the two input tuples
PyTuple_SetItem(pArgTuple, 0, pXVec);
PyTuple_SetItem(pArgTuple, 1, pYVec);
//Call the python function
pValue = PyObject_CallObject(pFunc, pArgTuple);
Run Code Online (Sandbox Code Playgroud)
以及Python代码:
def plotStdVectors(x, y):
import numpy as np
import matplotlib.pyplot as plt
print "Printing from Python in plotStdVectors()"
print x
print y
x = np.fromiter(x, dtype = np.float)
y = np.fromiter(y, dtype = np.float)
print x
print y
plt.plot(x, y)
plt.show()
return 0
Run Code Online (Sandbox Code Playgroud)
这导致由于我的声誉我无法在此处发布该情节,但在此处发布在我的博客文章中。