Cómo obtener la imagen OpenCV desde Python y utilizarlo en C ++ en pybind11?

Rika:

Estoy tratando de averiguar cómo es posible recibir una OpenCVimagen 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:

  1. How-To-convertir-OpenCV-imagen-datos-de-python-a-c
  2. pasar-imagen-datos-from-python-a-cvmat-en-c
  3. escritura-python-encuadernaciones-para-c-code-que-uso-OpenCV
  4. 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.hcabecera) con y sin Boost.Python.
Así que mi primer intento es saber cómo es posible que en Pybind11sabiendo que tiene soporte para Numpylas matrices, por lo que se espera que puedan hacer las cosas mucho más fácil.

También en el C++lado, OpenCVtiene dos versiones, 3.xy 4.x 4.x, que como he descubierto recientemente, es C++11compatible. en el lado de Python, he utilizado OpenCV 3.xy 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::objecto py::array_t<uint8_t>en lugar de cv::Matno causar ningún error, pero me parece que no puede encontrar una manera de echarlos de nuevo a una cv::Matadecuada!

Me tryied para emitir la serie en una numpy cv::Matcomo 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);
}

resultados en: introducir descripción de la imagen aquí

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 960o algo por el estilo. así que estoy completamente idea de cómo interpretar eso!

Rika:

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_policyque 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 ptrpropiedad expuesta en la numpymatriz, 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 datasostiene 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);
}


Supongo que te gusta

Origin http://10.200.1.11:23101/article/api/json?id=387427&siteId=1
Recomendado
Clasificación