Estoy tratando de averiguar cómo es posible recibir una OpenCV
imagen a partir de una serpiente pitón en C++
. Estoy intentando enviar una llamada de retorno, desde C ++ para mi módulo de Python, y luego cuando llamo a un método específico de Python en mi aplicación C ++, puedo acceder a la imagen necesaria.
Antes de añadir más detalles, tengo que añadir que ya hay varias preguntas en este sentido, incluyendo:
- How-To-convertir-OpenCV-imagen-datos-de-python-a-c
- pasar-imagen-datos-from-python-a-cvmat-en-c
- escritura-python-encuadernaciones-para-c-code-que-uso-OpenCV
- c-conversión-from-numpy-array-a-mat-opencv
pero ninguno de ellos tiene nada acerca Pybind11
. De hecho, están todas ellas con las PyObject
(de Python.h
cabecera) con y sin Boost.Python
.
Así que mi primer intento es saber cómo es posible que en Pybind11
sabiendo que tiene soporte para Numpy
las matrices, por lo que se espera que puedan hacer las cosas mucho más fácil.
También en el C++
lado, OpenCV
tiene dos versiones, 3.xy 4.x 4.x, que como he descubierto recientemente, es C++11
compatible. en el lado de Python, he utilizado OpenCV 3.x
y estoy en una encrucijada de cuál elegir y qué implicaciones tiene cuando se trata de Pybind11
.
Lo que he intentado hasta ahora:
hice una devolución de llamada ficticia rápida y trató de pasar un simple cv::Mat&
como esto:
#include <pybind11/embed.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
namespace py = pybind11;
...
void cpp_callback1(bool i, std::string id, cv::Mat img)
{
auto timenow = chrono::system_clock::to_time_t(chrono::system_clock::now());
cout <<"arg1: " << i << " arg2: " << id<<" arg3: " << typeid(img).name() <<" " << ctime(&timenow)<<endl;
}
y se utiliza de esta manera:
py::list callback_lst;
callback_lst.attr("append")(py::cpp_function(cpp_callback1));
py::dict core_kwargs = py::dict("callback_list"_a = callback_lst,
"debug_show_feed"_a = true);
py::object core_obj = core_cls(**core_kwargs);
core_obj.attr("start")();
pero falla con una excepción por parte de pitón, que dice:
29/03/2020 21:56:47 : exception occured ("(): incompatible function arguments. The following argument types are supported:\n 1. (arg0: bool, arg1: str, arg2: cv::Mat) -> None\n\nInvoked with: True, '5', array([[[195, 217, 237],\n [195, 217, 237],\n [196, 218, 238],\n ...,\n [211, 241, 255],\n [211, 241, 255],\n [211, 241, 255]],\n\n [[195, 217, 237],\n [195, 217, 237],\n [195, 217, 237],\n ...,\n [211, 241, 255],\n [211, 241, 255],\n [211, 241, 255]],\n\n [[195, 217, 237],\n [195, 217, 237],\n [195, 217, 237],\n ...,\n [211, 241, 255],\n [211, 241, 255],\n [211, 241, 255]],\n\n ...,\n\n [[120, 129, 140],\n [110, 120, 130],\n [113, 122, 133],\n ...,\n [196, 209, 245],\n [195, 207, 244],\n [195, 207, 244]],\n\n [[120, 133, 142],\n [109, 121, 130],\n [114, 120, 131],\n ...,\n [195, 208, 242],\n [195, 208, 242],\n [195, 208, 242]],\n\n [[121, 134, 143],\n [106, 119, 128],\n [109, 114, 126],\n ...,\n [194, 207, 241],\n [195, 208, 242],\n [195, 208, 242]]], dtype=uint8)",)
Traceback (most recent call last):
File "C:\Users\Master\Anaconda3\Lib\site-packages\F\utils.py", line 257, in start
self._main_loop()
File "C:\Users\Master\Anaconda3\Lib\site-packages\F\utils.py", line 301, in _main_loop
self._execute_callbacks(is_valid, name, frame)
File "C:\Users\Master\Anaconda3\Lib\site-packages\F\utils.py", line 142, in _execute_callbacks
callback(*args)
TypeError: (): incompatible function arguments. The following argument types are supported:
1. (arg0: bool, arg1: str, arg2: cv::Mat) -> None
Invoked with: True, '5', array([[[195, 217, 237],
[195, 217, 237],
[196, 218, 238],
...,
[211, 241, 255],
[211, 241, 255],
[211, 241, 255]],
[[195, 217, 237],
[195, 217, 237],
[195, 217, 237],
...,
El uso py::object
o py::array_t<uint8_t>
en lugar de cv::Mat
no causar ningún error, pero me parece que no puede encontrar una manera de echarlos de nuevo a una cv::Mat
adecuada!
Me tryied para emitir la serie en una numpy cv::Mat
como se indica en los comentarios, pero la salida es basura:
void cpp_callback1(bool i, std::string id, py::array_t<uint8_t>& img)
{
auto im = img.unchecked<3>();
auto rows = img.shape(0);
auto cols = img.shape(1);
auto type = CV_8UC3;
//py::buffer_info buf = img.request();
cv::Mat img2(rows, cols, type, img.ptr());
cv::imshow("test", img2);
}
Me parece, los pasos, o algo en esa dirección está en mal estado que la imagen está mostrando como este. ¿Qué estoy haciendo mal aquí? Me podía usar los img.strides () sin embargo! cuando se imprimen usando py :: impresión, se muestra 960
o algo por el estilo. así que estoy completamente idea de cómo interpretar eso!
Yo en última instancia, podría conseguir con éxito este trabajo gracias a que @ DanMasek y este enlace :
void cpp_callback1(bool i, std::string id, py::array_t<uint8_t>& img)
{
py::buffer_info buf = img.request();
cv::Mat mat(buf.shape[0], buf.shape[1], CV_8UC3, (unsigned char*)buf.ptr);
cv::imshow("test", mat);
}
en cuenta que el elenco es necesario, o de otra manera, se obtendría una pantalla de color negruzco solamente!
Sin embargo, si de alguna manera había una manera como py::return_value_policy
que podríamos usar para cambiar el tipo de referencia, por lo que a pesar de que los extremos de piezas de Python, C ++ lado no se estrellaría sería grande.
nota al margen:
parece que la ptr
propiedad expuesta en la numpy
matriz, no es en realidad una py::handle
, sino una PyObject*&
. No podía tener una conversión con éxito y por lo tanto recurrido a la solución que he publicado anteriormente. Voy a actualizar esta respuesta, cuando a resolver esto.
Actualizar:
Descubrí, las matrices data
sostiene un puntero a la memoria intermedia subyacente y se pueden utilizar fácilmente también. De <pybind11/numpy.h>
L681:
/// Pointer to the contained data. If index is not provided, points to the
/// beginning of the buffer. May throw if the index would lead to out of bounds access.
Así que mi código original que utiliza img.ptr()
, puede funcionar utilizando img.data()
la siguiente manera:
void cpp_callback1(bool i, std::string id, py::array_t<uint8_t>& img)
{
//auto im = img.unchecked<3>();
auto rows = img.shape(0);
auto cols = img.shape(1);
auto type = CV_8UC3;
cv::Mat img2(rows, cols, type, (unsigned char*)img.data());
cv::imshow("test", img2);
}