如何 return 包含 PyObject* 的 boost::python::tuple?

How do I return a boost::python::tuple containing a PyObject*?

我目前有一个 boost.python class 用于从 basler 相机获取图像,将它们转换为 opencv 图像并 return 它们作为 [=26= 的 numpy 数组] 脚本。

我最初有以下有效的代码:

    PyObject *capture()
    {
        PyObject * ret;
        CGrabResultPtr ptrGrabResult;
        CPylonImage pylonImage;
        Mat image;
        //timer t;
        try
        {
            // Set timer to 0
            //t.reset();

            // get a pointer to pylon image
            camera->RetrieveResult( 50000, ptrGrabResult, TimeoutHandling_ThrowException);

            // Get dimensions of image
            int imageWidthPixels = ptrGrabResult->GetWidth();
            int imageHeightPixels = ptrGrabResult->GetHeight();

             if (ptrGrabResult->GrabSucceeded())
             {
                // Convert Grab result from YUV422 to BGR8
                formatConverter->Convert(pylonImage, ptrGrabResult);

                // Convert pylon image to opencv image
                image = Mat(imageHeightPixels, imageWidthPixels, CV_8UC3, (std::uint8_t *) pylonImage.GetBuffer());
                // Convert opencv image to PyObject
                ret = pbcvt::fromMatToNDArray(image);
                return ret;
            }
            else
            {

                //cout << "Error: " << ptrGrabResult->GetErrorCode() << " " << ptrGrabResult->GetErrorDescription() << endl;
            }


         }
        catch (const GenericException &e)
        {
            // Error handling.
            cerr << "An exception occurred." << endl
            << e.GetDescription() << endl;
        }

        // Return empty image if acquisition failed
        return pbcvt::fromMatToNDArray(Mat());
    }

但是我想模拟 opencv 的 VideoCapture 函数和 return 元组的方式 因此,我天真地修改了代码:

    boost::python::tuple capture()
    {
        PyObject * ret;
        CGrabResultPtr ptrGrabResult;
        CPylonImage pylonImage;
        Mat image;
        //timer t;
        try
        {
            // Set timer to 0
            //t.reset();

            // get a pointer to pylon image
            camera->RetrieveResult( 50000, ptrGrabResult, TimeoutHandling_ThrowException);

            // Get dimensions of image
            int imageWidthPixels = ptrGrabResult->GetWidth();
            int imageHeightPixels = ptrGrabResult->GetHeight();

             if (ptrGrabResult->GrabSucceeded())
             {
                // Convert Grab result from YUV422 to BGR8
                formatConverter->Convert(pylonImage, ptrGrabResult);

                // Convert pylon image to opencv image
                image = Mat(imageHeightPixels, imageWidthPixels, CV_8UC3, (std::uint8_t *) pylonImage.GetBuffer());
                // Convert opencv image to PyObject
                ret = pbcvt::fromMatToNDArray(image);
                return boost::python::make_tuple(true, ret);
            }
            else
            {

                //cout << "Error: " << ptrGrabResult->GetErrorCode() << " " << ptrGrabResult->GetErrorDescription() << endl;
            }


         }
        catch (const GenericException &e)
        {
            // Error handling.
            cerr << "An exception occurred." << endl
            << e.GetDescription() << endl;
        }

        // Return opencv image
        return boost::python::make_tuple(false, pbcvt::fromMatToNDArray(Mat()));
    }

但是当我尝试编译时出现以下错误:

In file included from /usr/include/boost/python/call.hpp:15:0,
                 from /usr/include/boost/python/object_core.hpp:14,
                 from /usr/include/boost/python/args.hpp:25,
                 from /usr/include/boost/python.hpp:11,
                 from /home/anand/docker/pybasler/src/pyBasler.cpp:3:
/usr/include/boost/python/converter/arg_to_python.hpp: In instantiation of ‘static void boost::python::converter::detail::reject_raw_object_helper<T, Convertibility>::error(Convertibility) [with T = _object; Convertibility = char*]’:
/usr/include/boost/python/converter/arg_to_python.hpp:189:57:   required from ‘void boost::python::converter::detail::reject_raw_object_ptr(T*) [with T = _object]’
/usr/include/boost/python/converter/arg_to_python.hpp:217:36:   required from ‘boost::python::converter::detail::pointer_deep_arg_to_python<Ptr>::pointer_deep_arg_to_python(Ptr) [with Ptr = _object*]’
/usr/include/boost/python/converter/arg_to_python.hpp:256:13:   required from ‘boost::python::converter::arg_to_python<T>::arg_to_python(const T&) [with T = _object*]’
/usr/include/boost/python/object_core.hpp:292:44:   required from ‘static PyObject* boost::python::api::object_initializer_impl<is_proxy, is_object_manager>::get(const T&, mpl_::false_) [with T = _object*; bool is_proxy = false; bool is_object_manager = false; PyObject = _object; mpl_::false_ = mpl_::bool_<false>]’
/usr/include/boost/python/object_core.hpp:235:13:   required from ‘PyObject* boost::python::api::object_base_initializer(const T&) [with T = _object*; PyObject = _object]’
/usr/include/boost/python/object_core.hpp:250:46:   required from ‘boost::python::api::object::object(const T&) [with T = _object*]’
/usr/include/boost/python/detail/make_tuple.hpp:25:9:   required from ‘boost::python::tuple boost::python::make_tuple(const A0&, const A1&) [with A0 = bool; A1 = _object*]’
/home/anand/docker/pybasler/src/pyBasler.cpp:130:63:   required from here
/usr/include/boost/python/converter/arg_to_python.hpp:181:72: error: incomplete type ‘boost::python::converter::detail::cannot_convert_raw_PyObject<_object*>’ used in nested name specifier
           cannot_convert_raw_PyObject<T*>::to_python_use_handle_instead();
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
/usr/include/boost/python/converter/arg_to_python.hpp: In instantiation of ‘static void boost::python::converter::detail::reject_raw_object_helper<T, Convertibility>::error(Convertibility) [with T = _object; Convertibility = int*]’:
/usr/include/boost/python/converter/arg_to_python.hpp:194:56:   required from ‘void boost::python::converter::detail::reject_raw_object_ptr(T*) [with T = _object]’
/usr/include/boost/python/converter/arg_to_python.hpp:217:36:   required from ‘boost::python::converter::detail::pointer_deep_arg_to_python<Ptr>::pointer_deep_arg_to_python(Ptr) [with Ptr = _object*]’
/usr/include/boost/python/converter/arg_to_python.hpp:256:13:   required from ‘boost::python::converter::arg_to_python<T>::arg_to_python(const T&) [with T = _object*]’
/usr/include/boost/python/object_core.hpp:292:44:   required from ‘static PyObject* boost::python::api::object_initializer_impl<is_proxy, is_object_manager>::get(const T&, mpl_::false_) [with T = _object*; bool is_proxy = false; bool is_object_manager = false; PyObject = _object; mpl_::false_ = mpl_::bool_<false>]’
/usr/include/boost/python/object_core.hpp:235:13:   required from ‘PyObject* boost::python::api::object_base_initializer(const T&) [with T = _object*; PyObject = _object]’
/usr/include/boost/python/object_core.hpp:250:46:   required from ‘boost::python::api::object::object(const T&) [with T = _object*]’
/usr/include/boost/python/detail/make_tuple.hpp:25:9:   required from ‘boost::python::tuple boost::python::make_tuple(const A0&, const A1&) [with A0 = bool; A1 = _object*]’
/home/anand/docker/pybasler/src/pyBasler.cpp:130:63:   required from here
/usr/include/boost/python/converter/arg_to_python.hpp:181:72: error: incomplete type ‘boost::python::converter::detail::cannot_convert_raw_PyObject<_object*>’ used in nested name specifier
CMakeFiles/pbcvt.dir/build.make:62 : la recette pour la cible « CMakeFiles/pbcvt.dir/src/pyBasler.cpp.o » a échouée
make[2]: *** [CMakeFiles/pbcvt.dir/src/pyBasler.cpp.o] Erreur 1
CMakeFiles/Makefile2:67 : la recette pour la cible « CMakeFiles/pbcvt.dir/all » a échouée
make[1]: *** [CMakeFiles/pbcvt.dir/all] Erreur 2
Makefile:129 : la recette pour la cible « all » a échouée
make: *** [all] Erreur 2

我做错了什么?我怎样才能得到想要的结果?

问题的关键指标是编译错误中的这一行:

/usr/include/boost/python/converter/arg_to_python.hpp:181:72: error: incomplete type ‘boost::python::converter::detail::cannot_convert_raw_PyObject<_object*>’ used in nested name specifier
       cannot_convert_raw_PyObject<T*>::to_python_use_handle_instead();

这说明您不能直接将 PyObject* 转换为 object。您需要告诉它如何处理 PyObject* 的所有权。这是通过 boost::python::handle 类型完成的。

因此,更改此行:

return boost::python::make_tuple(true, ret);

至:

boost::python::make_tuple(true, boost::python::handle<>(ret));

将解决错误。