如何在 C 中公开 pybind11::object?
How to expose a pybind11::object in C?
目前我的 C++ 上有这个签名 class :
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 中公开这个 class 功能。这就是我被卡住的地方!
我试过使用:
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 函数签名有任何问题,所以一切都应该没问题!
但我想这个假设在这里不成立,或者我遗漏了一些东西。
我在这里遗漏了什么以及在 C
中公开 pybin11::objects(例如 pybind11::array_t)时我有哪些选择?
这似乎是 Pybind11 的一个错误,我最终使用了委托回调。那就是使用中间回调在两种格式之间进行转换。详细解释.
目前我的 C++ 上有这个签名 class :
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 中公开这个 class 功能。这就是我被卡住的地方!
我试过使用:
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 函数签名有任何问题,所以一切都应该没问题!
但我想这个假设在这里不成立,或者我遗漏了一些东西。
我在这里遗漏了什么以及在 C
中公开 pybin11::objects(例如 pybind11::array_t)时我有哪些选择?
这似乎是 Pybind11 的一个错误,我最终使用了委托回调。那就是使用中间回调在两种格式之间进行转换。详细解释