首页 > 解决方案 > 如何在 C 中公开 pybind11::object?

问题描述

目前我在我的 C++ 类上有这个签名:

typedef void(*CallbackFn)(bool, std::string, py::array_t<uint8_t>&);
void AddCallback(CallbackFn callback);

在我的客户代码中,我只有:

void default_callback(bool status, std::string id, py::array_t<uint8_t>& img)
{
    auto rows = img.shape(0);
    auto cols = img.shape(1);
    auto type = CV_8UC3;

    cv::Mat img1(rows, cols, type, img.mutable_data());

    cv::imshow("from callback", img1);
    auto timenow = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    std::cout << "\narg1: " << status << " arg2: " << id << " arg3: " << typeid(img).name() << " " << ctime(&timenow) << std::endl;
}

这适用于C++. 但现在我决定用它制作一个 DLL,因此需要在 C 中公开这个类的功能。这就是我卡住的地方!
我试过使用:

typedef void(*CCallbackFn)(bool, char*, unsigned char);
typedef void(*CCallbackFn)(bool, char*, void*);

但它们不起作用,因为我在 Python 部分遇到异常:
使用时unsigned char

TypeError: (): incompatible function arguments. The following argument types are supported:
    1. (arg0: bool, arg1: str, arg2: int) -> None

Invoked with: True, '5', array([[[193, 218, 237],
        [193, 218, 237],
        [192, 217, 235],
        ...,

       [[193, 218, 237],
        [193, 218, 237],
        [192, 217, 235],
        ...,
        [ 68,  51,  88],
        [ 69,  54,  88],
        [ 72,  58,  92]]], dtype=uint8)

当使用 void* 我得到:

TypeError: (): incompatible function arguments. The following argument types are supported:
    1. (arg0: bool, arg1: str, arg2: capsule) -> None

Invoked with: True, '5', array([[[195, 216, 239],
        [195, 216, 239],
        [193, 214, 236],
        ...,

       [[131, 147, 153],
        [124, 140, 146],
        [116, 126, 136],
        ...,
        [100, 108, 144],
        [104, 112, 148],
        [104, 112, 148]]], dtype=uint8)

我假设因为我正在处理OpenCV图像,这是一个对象(更多的应该传递PyObject给我,对吗?), void* 可能是一个可行的选择,并且C++我可以将它重铸为 PyObject 以获得指向缓冲区的底层指针,然后使用它。
由于它是一个 void *,我也不会在将它用作 C 函数签名时遇到任何问题,所以一切都应该没问题!
但我想这个假设在这里不成立,或者我错过了一些东西。
我在这里遗漏了什么,在暴露 pybin11::objects(如 pybind11::array_t in )时我有哪些选择C

标签: c++pybind11

解决方案


这似乎是一个 Pybind11 错误,我最终使用了委托回调。那就是使用中间回调在两种格式之间进行转换。这里有详细解释。


推荐阅读