edmBernard / pybind11_opencv_numpy

Implementation of cv::Mat conversion to numpy.array for pybind11
Apache License 2.0
198 stars 41 forks source link

How can I convert other types like: cv2.KeyPoint to cv::KeyPoint ? #14

Closed Cenbylin closed 4 years ago

Cenbylin commented 4 years ago

This repo is really helpful to me.

edmBernard commented 4 years ago

I'm glad this repos can help you. For KeyPoint did you really need to convert KeyPoint or did you just need Point2f ?

Cenbylin commented 4 years ago

I need to convert the whole KeyPoint object, which was obtained via feature extractor in opencv-python. The current solution is to unpack these objects (cv2.KeyPoint) into tuple (x, y, size, angle, response, octave), and in c++ we construct back to cv::KeyPoint. Do you have more straightaway method?

edmBernard commented 4 years ago

I would propose the same approach. If you don't need to interprete Keypoint in python but you just use python to pass object from c++ function to another. I think there is a way to store C++ object without interpretation.

edmBernard commented 4 years ago

If you really want to do a proper type convertion. You have to define a python class that mimic the KeyPoint structure and implement a custom type convertion : https://pybind11.readthedocs.io/en/stable/advanced/cast/custom.html

Cenbylin commented 4 years ago

You are right. That would be easier if cv2.KeyPoint provide some interface to obtain the original c++ object. But I am afraid it didn't. Thanks for your idea and helpful document.

edmBernard commented 4 years ago

sorry I think I misunderstand you, you want to convert object from the opencv python binding to the opencv c++. from my previous version, I think we just have to implement custom convertion between the two existing type cv2.KeyPoint and cv::KeyPoint

Cenbylin commented 4 years ago

Yes, that's exactly what I call "more straightaway method" 😃. I don't know how to implement such a custom convertor. The reason why I unpack to a tuple in Python, is because tuple is build-in conversion. This process is too slow in python.

A custom convertor, could be much quicker than current solution, although it is still slower than getting the original c++ Object (If we can).

Cenbylin commented 4 years ago

I have used pybind11 for a very short time. I don't know how to access member value of "PyObject".

edmBernard commented 4 years ago

I haven't use them. There is pybind11 function : py::hasattr and py::getattr to access member

Cenbylin commented 4 years ago

Great! That is what I want. Searching these keywords, I know how to implement the converter now. Thanks!

Cenbylin commented 4 years ago

I try to implement this converter, and it works.

#include <Python.h>
#include <opencv2/core/core.hpp>
#include <pybind11/pybind11.h>

namespace py = pybind11;
namespace pybind11 { namespace detail {

template <> struct type_caster<cv::KeyPoint> {
    public:

    PYBIND11_TYPE_CASTER(cv::KeyPoint, _("cv2.KeyPoint"));

        bool load(handle src, bool) {
            py::tuple pt = reinterpret_borrow<py::tuple>(src.attr("pt"));
            auto x = pt[0].cast<float>();
            auto y = pt[1].cast<float>();
            auto size = src.attr("size").cast<float>();
            auto angle = src.attr("angle").cast<float>();
            auto response = src.attr("response").cast<float>();
            auto octave = src.attr("octave").cast<int>();
            auto class_id = src.attr("class_id").cast<int>();
            // (float x, float y, float _size, float _angle, float _response, int _octave, int _class_id)
            value = cv::KeyPoint(x, y, size, angle, response, octave, class_id);

            return true;
        }

        static handle cast(const cv::KeyPoint &kp, return_value_policy, handle defval) {
            py::object classKP = py::module::import("cv2.KeyPoint");
            py::object cvKP = classKP(kp.pt.x, kp.pt.y, kp.size, kp.angle, kp.response, kp.octave, kp.class_id);

            // equal to: return handle(cvKP.ptr());
            return {cvKP.ptr()};
        }
};

}} // namespace pybind11::detail
edmBernard commented 4 years ago

nice