spillai / numpy-opencv-converter

OpenCV <=> NumPy Converter using Boost::Python
BSD 2-Clause "Simplified" License
131 stars 52 forks source link

did not match C++ signature: #2

Open shixudongleo opened 9 years ago

shixudongleo commented 9 years ago

ArgumentError: Python argument types in cv_module.process_mat(numpy.ndarray) did not match C++ signature: process_mat(cv::Mat)

call from python: import numpy as np from cv_module import process_mat A = np.random.random(shape=(4,3)) B = process_mat(A)

cv_module.cpp // Wrapper for most external modules

include <boost/python.hpp>

include <boost/python/suite/indexing/vector_indexing_suite.hpp>

include

// Opencv includes

include <opencv2/opencv.hpp>

// np_opencv_converter

include "np_opencv_converter.hpp"

cv::Mat process_mat(const cv::Mat& in) { // process matrix, or just plain-simple cloning! cv::Mat out = in.clone(); return out; }

BOOST_PYTHON_MODULE(cv_module) { boost::python::def("process_mat", &process_mat); }

CMakefile.txt project (my-numpy-opencv-converter) cmake_minimum_required (VERSION 2.6.0)

Include package config, boost-python

find_package(PkgConfig REQUIRED) include(cmake/boost-python.cmake)

configure opencv

pkg_check_modules(OpenCV opencv) include_directories(${OpenCV_INCLUDE_DIRS})

Include python (use -D flags instead)

if (NOT PYTHON_INCLUDE_DIRS OR NOT PYTHON_LIBRARY) SET(PYTHON_INCLUDE_DIRS "/usr/include/python2.7") SET(PYTHON_LIBRARY "/usr/lib/python2.7/config-x86_64-linux-gnu/libpython2.7.so") endif()

Build np<=>opencv converter library

boost_python_module(np_opencv_converter np_opencv_converter.cpp utils/conversion.cpp) target_link_libraries(np_opencv_converter boost_system boost_python ${OpenCV_LDFLAGS})

Build test library

include_directories(${CMAKE_CURRENT_SOURCE_DIR}) boost_python_module(cv_module tests/cv_module.cpp) target_link_libraries(cv_module boost_system boost_python np_opencv_converter ${OpenCV_LDFLAGS})

rodrigob commented 8 years ago

I think your example is missing a call to fs::python::init_and_export_converters(); after BOOST_PYTHON_MODULE(cv_module)

spillai commented 8 years ago

Thanks for comment/resolution @rodrigob.

@shixudongleo, As soon as you call from cv_module import process_mat, you should see a PYTHON TYPE CONVERTERS exported printed in the console implying that the np.ndarry<=>cv::Mat converters are registered within the Python runtime. This is done within fs::python::init_and_export_converters(); and it should be called as @rodrigob mentioned

BOOST_PYTHON_MODULE(cv_module)
{
fs::python::init_and_export_converters();
boost::python::def("process_mat", &process_mat);
}
rodrigob commented 8 years ago

ok, so now I got to try it, and it did not work either :(.

I do use

BOOST_PYTHON_MODULE(my_module)
{
    fs::python::init_and_export_converters();
   // here the defs

then I call

 python my_test.py
PYTHON TYPE CONVERTERS exported
Traceback (most recent call last):
  File "my_test.py", line 268, in <module>
    main()
Boost.Python.ArgumentError: Python argument types in
    my_method(numpy.ndarray, str, int, int, int, int, numpy.ndarray)
did not match C++ signature:
    my_method(cv::Mat_<cv::Vec<unsigned char, 3> > image, std::string image_name, int x_min, int y_min, int x_max, int y_max, cv::Mat_<unsigned char> {lvalue} mask)

any idea of what is going on ?

spillai commented 8 years ago

Can you send me the C function you're trying to call and the corresponding my_test.py? It should be an easy fix I think. If my_method is accepting cv::Mat3b and cv::Mat1b then your numpy array need to be called with the appropriate dtypes (np.uint8), and shapes as well. Its much easier to write the API accepting cv::Mat and have the registry handle the conversions for you.

rodrigob commented 8 years ago

I am not sure what you are asking for (that you cannot already see in the previous message), the C++ prototype is

void my_method(const cv::Mat3b &image, const std::string &image_name,
                                   const int x_min, const int y_min, const int x_max, const int y_max, cv::Mat1b &mask);

and the python call is

my_module.my_method(
        image, "a_string",
        x_min, y_min, x_max, y_max,
        mask
    )

where image and mask are numpy arrays of shape (321, 481, 3) and (321, 481) respectively both of dtype uint8.

rodrigob commented 8 years ago

If I change the prototype of the C++ function to use p::object & instead of cv::Mat and then use p::extract<cv::Mat>(...) then things seem to work. But that does not match the examples of the documentation.

spillai commented 8 years ago

You're passing a cv::Mat1b reference (cv::Mat1b&) instead of a const reference (const cv::Mat1b&). Try this: void my_method(const cv::Mat3b &image, const std::string &image_name, const int x_min, const int y_min, const int x_max, const int y_max, const cv::Mat1b &mask)

Unfortunately, I haven't spent too much time on the memory management (since both numpy and opencv have their own memory management policies), and the managing who handles the memory between Python and C can be a little tricky.

Also, if you're dealing with 3-channel images, you'll probably need to set the preprocessor to 1. (see here)

I just realized that this repo needs a little bit of work to get a first example up and running. I'll try to add more test examples in the near future.