Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert NumPy ndarray to C++ vector with Boost.Python and back?

I am working on a project where I need to convert an ndarray in Python to a vector in C++ and then return a processed vector from C++ back to Python in an ndarray. I am using Boost.Python with its NumPy extension. My problem specifically lies in converting from ndarray to vector, as I am using an extended class of vector:

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

The ndarray I receive is nx2 and filled with x,y data. Then I process the data in C++ with a function, which returns an std::vector<Vector>. This vector then should be returned to Python as an ndarray, BUT only with the x and y values.

I have written the following piece of code, with inspiration from "how to return numpy.array from boost::python?" and the gaussian.cpp from the Boost NumPy examples.

#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;
}

EDIT: I am aware that this is a (possibly) failed attempt, and I am more interested in a better method to solve this problem, than edits to my code.

So to sum up:

  1. How do I convert an boost::python::numpy::ndarray to a std::vector<Vector>?
  2. How do I convert a std::vector<Vector> to an boost::python::numpy::ndarray, returning only x and y?

As a last note: I know almost nothing about Python, and I am beginner/moderate in C++.

like image 934
Kristian Avatar asked May 03 '17 11:05

Kristian


People also ask

How do I turn Ndarray into a list in Python?

To convert a one-dimensional NumPy array to a list use tolist() function of the ndarray, First, let's create a ndarray using array() function and then use tolist() function to convert it to a list. The array() function takes a Python list as an argument.

What is the difference between NumPy array and Ndarray?

numpy. array is just a convenience function to create an ndarray ; it is not a class itself. You can also create an array using numpy. ndarray , but it is not the recommended way.

How do I save NumPy Ndarray as a picture?

To save the Numpy array as a local image, use the save() function and pass the image filename with the directory where to save it. This will save the Numpy array as a jpeg image.

Is Ndarray and array the same?

The array object in NumPy is called ndarray . We can create a NumPy ndarray object by using the array() function.


1 Answers

I will consider the title of your question to give a more generalized answer to whoever finds this post.

You have a boost::python::numpy::ndarray called input that contains doubles and you want to convert it a std::vector<double> called v:

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);

Now, you have a std::vector<double> called v and you want to convert it back to boost::python::numpy::ndarray of doubles called 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());

Supposing you are wrapping this function, don't forget that you need to create a new reference to this array before returning it to python:

np::ndarray output_array = output.copy();
like image 139
fabda01 Avatar answered Oct 17 '22 00:10

fabda01