【问题标题】:How to convert NumPy ndarray to C++ vector with Boost.Python and back?如何使用 Boost.Python 将 NumPy ndarray 转换为 C++ 向量并返回?
【发布时间】:2017-05-03 11:26:01
【问题描述】:

我正在做一个项目,我需要将 Python 中的 ndarray 转换为 C++ 中的 vector,然后将处理后的 vector 从 C++ 返回到 ndarray 中的 Python。我正在使用 Boost.Python 及其 NumPy 扩展。我的问题特别在于从ndarray 转换为vector,因为我使用的是向量的扩展类:

class Vector
{
   public:
      Vector();
      Vector(double x, double y, double z);
      /* ... */
      double GetLength(); // Return this objects length.
      /* ... */
      double x, y, z;
};

我收到的 ndarraynx2 并填充了 x,y 数据。然后我用一个函数在 C++ 中处理数据,该函数返回一个std::vector<Vector>。然后,该向量应作为 ndarray 返回给 Python,但仅包含 x 和 y 值。

我编写了以下代码,灵感来自“how to return numpy.array from boost::python?”和 Boost NumPy 示例中的 gaussian.cpp

#include <vector>
#include "Vector.h"
#include "ClothoidSpline.h"

#include <boost/python/numpy.hpp>

namespace py = boost::python;
namespace np = boost::python::numpy;

std::vector<Vector> getFineSamples(std::vector<Vector> data)
{
    /* ... */
}

np::ndarray wrapper(np::ndarray const & input)
{
    std::vector<Vector> data;

    /* Python ndarray --> C++ Vector */
    Py_intptr_t const* size = input.get_shape();
    Py_intptr_t const* strides = input.get_strides();

    double x;
    double y;
    double z = 0.0;

    for (int i = 0; i < size[0]; i++)
    {
        x = *reinterpret_cast<double const *>(input.get_data() + i * strides[0] + 0 * strides[1]);
        y = *reinterpret_cast<double const *>(input.get_data() + i * strides[0] + 1 * strides[1]);
        data.push_back(Vector::Vector(x,y,z));
    }

    /* Run Algorithm */
    std::vector<Vector> v = getFineSamples(data);

    /* C++ Vector --> Python ndarray */
    Py_intptr_t shape[1] = { v.size() };
    np::ndarray result = np::zeros(2, shape, np::dtype::get_builtin<std::vector<Vector>>());
    std::copy(v.begin(), v.end(), reinterpret_cast<double*>(result.get_data()));

    return result;
}

编辑:我知道这是一次(可能)失败的尝试,我对解决这个问题的更好方法更感兴趣,而不是编辑我的代码。

总结一下

  1. 如何将boost::python::numpy::ndarray 转换为std::vector&lt;Vector&gt;
  2. 如何将 std::vector&lt;Vector&gt; 转换为 boost::python::numpy::ndarray,只返回 x 和 y?

最后一点:我对 Python 几乎一无所知,而且我是 C++ 的初学者/中等水平。

【问题讨论】:

    标签: python c++ numpy vector boost


    【解决方案1】:

    我会考虑你的问题的标题,以便为找到这篇文章的人提供更笼统的答案。

    您有一个名为 inputboost::python::numpy::ndarray 包含 doubles,并且您希望将其转换为名为 vstd::vector&lt;double&gt;

    int input_size = input.shape(0);
    double* input_ptr = reinterpret_cast<double*>(input.get_data());
    std::vector<double> v(input_size);
    for (int i = 0; i < input_size; ++i)
        v[i] = *(input_ptr + i);
    

    现在,您有一个名为 vstd::vector&lt;double&gt;,并且您希望将其转换回名为 doublesboost::python::numpy::ndarray,名为 output

    int v_size = v.size();
    py::tuple shape = py::make_tuple(v_size);
    py::tuple stride = py::make_tuple(sizeof(double));
    np::dtype dt = np::dtype::get_builtin<double>();
    np::ndarray output = np::from_data(&v[0], dt, shape, stride, py::object());
    

    假设你包装了这个函数,别忘了在返回给 python 之前你需要创建一个对这个数组的新引用:

    np::ndarray output_array = output.copy();
    

    【讨论】:

    • 为什么我们必须创建一个对该数组的新引用?现有的会被删除吗?我看不出确切的原因,如果您能解释原因,我将不胜感激
    • @T-800 是的,我曾经遇到过 python 在动态数组超出范围时删除动态数组的问题。您是否尝试过不创建新引用以查看是否仍然存在此问题?你可以在这里查看更多Memory Management
    • 好吧,我遇到了另一个问题:当我使用您提出的实现时,向量的第一个元素始终为空。指针可能不存在,但我不知道为什么。复制输出数组不是补救措施。因此,我创建了一个空的 ndarray 并在循环中填充了值。
    • @yellow01 如果 boost::python::numpy::ndarray 引用了一个在内存中不连续的 numpy 数组,这将不起作用。
    猜你喜欢
    • 2019-03-26
    • 2015-12-17
    • 2020-06-27
    • 2021-02-24
    • 1970-01-01
    • 1970-01-01
    • 2011-08-11
    • 2017-12-14
    • 2015-08-07
    相关资源
    最近更新 更多