Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you wrap C++ OpenCV code with Boost::Python?

I want to wrap my C++ OpenCV code with boost::python, and to learn how to do it, I tried a toy example, in which

  • I use the Boost.Numpy project to provide me with boost::numpy::ndarray.

  • The C++ function to be wrapped, square() takes a boost::numpy::ndarray and modifies it in place by squaring each element in it.

  • The exported Python module name is called test.

  • The square() C++ function is exported as the square name in the exported module.

  • I am not using bjam because IMO it is too complicated and just doesn't work for me no matter what. I'm using good old make.

Now, here's the code:

// test.cpp
#include <boost/python.hpp>
#include <boost/numpy.hpp>
#include <boost/scoped_array.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

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

void square(np::ndarray& array)
{
    if (array.get_dtype() != np::dtype::get_builtin<int>())
    {
        PyErr_SetString(PyExc_TypeError, "Incorrect array data type.");
        py::throw_error_already_set();
    }
    size_t rows = array.shape(0), cols = array.shape(1);
    size_t stride_row = array.strides(0) / sizeof(int), 
           stride_col = array.strides(1) / sizeof(int);
    cv::Mat mat(rows, cols, CV_32S);
    int *row_iter = reinterpret_cast<int*>(array.get_data());
    for (int i = 0; i < rows; i++, row_iter += stride_row)
    {
        int *col_iter = row_iter;
        int *mat_row = (int*)mat.ptr(i);
        for (int j = 0; j < cols; j++, col_iter += stride_col)
        {
            *(mat_row + j) = (*col_iter) * (*col_iter); 
        }
    }

    for (int i = 0; i < rows; i++, row_iter += stride_row)
    {
        int *col_iter = row_iter;
        int *mat_row = (int*)mat.ptr(i);
        for (int j = 0; j < cols; j++, col_iter += stride_col)
        {
            *col_iter = *(mat_row + j);
        }
    }
}


BOOST_PYTHON_MODULE(test)
{
   using namespace boost::python;
   def("square", square);
}

And here's the Makefile:

PYTHON_VERSION = 2.7
PYTHON_INCLUDE = /usr/include/python$(PYTHON_VERSION)

BOOST_INC = /usr/local/include
BOOST_LIB = /usr/local/lib
OPENCV_LIB = $$(pkg-config --libs opencv)
OPENCV_INC = $$(pkg-config --cflags opencv)

TARGET = test

$(TARGET).so: $(TARGET).o
        g++ -shared -Wl,--export-dynamic \
        $(TARGET).o -L$(BOOST_LIB) -lboost_python \
        $(OPENCV_LIB) \
        -L/usr/lib/python$(PYTHON_VERSION)/config -lpython$(PYTHON_VERSION) \
        -o $(TARGET).so

$(TARGET).o: $(TARGET).cpp
        g++ -I$(PYTHON_INCLUDE) $(OPENCV_INC) -I$(BOOST_INC) -fPIC -c $(TARGET).cpp

With this scheme, I can type make and test.so gets created. But when I try to import it,

In [1]: import test
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-1-73ae3ffe1045> in <module>()
----> 1 import test

ImportError: ./test.so: undefined symbol:        _ZN5boost6python9converter21object_manager_traitsINS_5numpy7ndarrayEE10get_pytypeEv

In [2]: 

This is a linker error which I can't seem to fix. Can anyone please help me with what's going on? Do you have (links to) code that already does integrate OpenCV, numpy and Boost.Python without things like Py++ or the likes?.

like image 309
yati sagade Avatar asked Oct 20 '25 10:10

yati sagade


1 Answers

Okay I fixed this. It was a simple issue, but a sleepy brain and servings of bjam had made me ignore it. In the Makefile, I'd forgotten to put -lboost_numpy that links the Boost.Numpy libs to my lib. So, the modified Makefile looks like this:

PYTHON_VERSION = 2.7
PYTHON_INCLUDE = /usr/include/python$(PYTHON_VERSION)

BOOST_INC = /usr/local/include
BOOST_LIB = /usr/local/lib
OPENCV_LIB = $$(pkg-config --libs opencv)
OPENCV_INC = $$(pkg-config --cflags opencv)

TARGET = test

$(TARGET).so: $(TARGET).o
        g++ -shared -Wl,--export-dynamic \
        $(TARGET).o -L$(BOOST_LIB) -lboost_python -lboost_numpy \
        $(OPENCV_LIB) \
        -L/usr/lib/python$(PYTHON_VERSION)/config -lpython$(PYTHON_VERSION) \
        -o $(TARGET).so

$(TARGET).o: $(TARGET).cpp
        g++ -I$(PYTHON_INCLUDE) $(OPENCV_INC) -I$(BOOST_INC) -fPIC -c $(TARGET).cpp
like image 154
yati sagade Avatar answered Oct 23 '25 00:10

yati sagade



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!