Conversión de C ++ de la matriz NumPy a Mat (OpenCV)

Estoy escribiendo una envoltura delgada alrededor de la biblioteca de realidad aumentada ArUco (que se basa en OpenCV). Una interfaz que estoy tratando de construir es muy simple:

  • Python pasa la imagen al código C ++;
  • El código C ++ detecta marcadores y devuelve sus ubicaciones y otra información a Python como una tupla de dictados.

Sin embargo, no pude averiguar cómo representar una imagen en Python para pasarla a C ++. Para la GUI y la gestión de la cámara voy a usar PyQt, así que inicialmente será QImage, pero no puedo simplemente pasarlo a OpenCV (¿o puedo?). Al principio, intenté usar tuplas anidadas para representar la fila, la columna y el color de cada píxel, así que terminé con este código de ejemplo:

using namespace cv; namespace py = boost::python; void display(py::tuple pix) { /* Receive image from Python and display it. */ Mat img(py::len(pix), py::len(pix[0]), CV_8UC3, Scalar(0, 0, 255)); for (int y = 0; y < py::len(pix); y++) for (int x = 0; x < py::len(pix[y]); x++) { Vec3b rgb; for (int i = 0; i < 3; i++) rgb[i] = py::extract(pix[y][x][i]); img.at(Point(x, y)) = rgb; } imshow("Image", img); waitKey(0); } BOOST_PYTHON_MODULE(aruco) { py::def("display", display); } 

Resultó ser muy lento (unos segundos para un solo fotogtwig), así que busqué en Google y encontré una solución que debería ser mucho más rápida: use matrices NumPy, de modo que el código se vería así:

 void display(py::object array) { Mat img; // ... some magic here to convert NumPy array to Mat ... imshow("Image", img); waitKey(0); } 

Sin embargo, no tengo idea de cómo convertir NumPy Array (que en el nivel de C ++ es solo un objeto de Python) a OpenCV Mat. Apreciaría cualquier ayuda aquí.

Alternativamente, tal vez NumPy no sea realmente necesario, ¿así que podría pasar el objeto Python de QImage directamente a la capa C ++? O tal vez hay un enfoque diferente a este problema? Cualquier consejo es apreciado!

La mejor solución en su situación es usar el boost personalizado :: python converter for cv :: Mat object. OpenCV tiene un envoltorio de Python y cuando está usando este envoltorio está operando en matrices Numpy, ni siquiera necesita saber que esas matrices se convierten en objetos cv :: Mat mientras “cruzan el borde de python c ++ <->“. Escribir este convertidor para un tipo simple es bastante fácil, sin embargo, crear convertidor para cv :: Mat no es simple. Afortunadamente, alguien más ya hizo esto: aquí está la versión para OpenCV 2.xy aquí para 3.x. Si no está familiarizado con boost :: python converters, este artículo le ayudará.
Espero que ayude, si tiene algún problema, háganoslo saber.

Opcionalmente, si no te gusta usar envoltorios, y quieres usar el módulo de extensión Python nativo, puedes hacerlo de esta manera.

python3:

 my_image = cv.imread("my_image.jpg", 1) # reads colorfull image in python dims = my_image.shape # get image shape (h, w, c) my_image = my_image.ravel() # flattens 3d array into 1d cppextenionmodule.np_to_mat(dims, my_image) 

c ++:

 static PyObject *np_to_mat(PyObject *self, PyObject *args){ PyObject *size; PyArrayObject *image; if (!PyArg_ParseTuple(args, "O!O!", &PyTuple_Type, &size, &PyArray_Type, &image)) { return NULL; } int rows = PyLong_AsLong(PyTuple_GetItem(size ,0)); int cols = PyLong_AsLong(PyTuple_GetItem(size ,1)); int nchannels = PyLong_AsLong(PyTuple_GetItem(size ,2)); char my_arr[rows * nchannels * cols]; for(size_t length = 0; length<(rows * nchannels * cols); length++){ my_arr[length] = (*(char *)PyArray_GETPTR1(image, length)); } cv::Mat my_img = cv::Mat(cv::Size(cols, rows), CV_8UC3, &my_arr); ... whatever with the image }