c++ opengl opencv glreadpixels

c++ - Conversión de datos de glReadPixels() a OpenCV:: Mat



opengl (2)

Quiero obtener cada fotograma OpenGL de una animación con glReadPixels () y convertir los datos a OpenCV :: Mat . Sé que glReadPixels () obtiene los datos por filas desde el inferior al superior, de izquierda a derecha. Por otro lado, OpenCV almacena los datos de manera diferente.

¿Alguien conoce alguna biblioteca o tutorial / ejemplo que me ayude a convertir datos de glReadPixels a OpenCV: Mat in C ++?

RESUMEN

OpenGL frame -----------------------> CV::Mat Data from left to right, Data from left to right, bottom to top. top to bottom.


Primero creamos un cv::Mat vacío (o unitizado) para que nuestros datos puedan leerse directamente. Esto se puede hacer una vez al inicio, pero por otro lado, cv::Mat::create realmente no cuesta mucho cuando la imagen ya tiene el mismo tamaño y tipo. El tipo depende de sus necesidades, por lo general es algo así como CV_8UC3 para una imagen a color de 24 bits.

cv::Mat img(height, width, CV_8UC3);

o

img.create(height, width, CV_8UC3);

Luego tiene que dar cuenta de que cv::Mat no necesariamente almacena filas de imágenes contiguamente. Puede haber un pequeño valor de relleno al final de cada fila para alinear las filas de 4 bytes (¿o 8?). Así que debes jugar con los modos de almacenamiento de píxeles:

//use fast 4-byte alignment (default anyway) if possible glPixelStorei(GL_PACK_ALIGNMENT, (img.step & 3) ? 1 : 4); //set length of one complete row in destination data (doesn''t need to equal img.cols) glPixelStorei(GL_PACK_ROW_LENGTH, img.step/img.elemSize());

A continuación, el tipo de matriz influye en el formato y los parámetros de tipo de glReadPixels . Si desea imágenes en color, debe tener en cuenta que OpenCV generalmente almacena los valores de color en orden BGR, por lo que debe usar GL_BGR(A) (que se agregaron con OpenGL 1.2) en lugar de GL_RGB(A) . Para las imágenes de un componente, use GL_LUMINANCE (que resume los componentes de color individuales) o GL_RED , GL_GREEN , ... (para obtener un componente individual). Entonces, para nuestra imagen CV_8UC3 la última llamada para leerla directamente en el cv::Mat sería:

glReadPixels(0, 0, img.cols, img.rows, GL_BGR, GL_UNSIGNED_BYTE, img.data);

Finalmente, OpenCV almacena imágenes de arriba a abajo. Por lo tanto, es posible que necesite voltearlos después de obtenerlos o hacerlos volteados en OpenGL en primer lugar (esto se puede hacer ajustando la matriz de proyección, pero esté atento a la orientación del triángulo en este caso). Para voltear un cv::Mat verticalmente, puede usar cv::flip :

cv::flip(img, flipped, 0);

Para tener en cuenta OpenCV:

  • almacena imágenes de arriba a abajo, de izquierda a derecha
  • almacena imágenes en color en orden BGR
  • podría no almacenar filas de imágenes empaquetadas

unsigned char* getPixelData( int x1, int y1, int x2, int y2 ) { int y_low, y_hi; int x_low, x_hi; if ( y1 < y2 ) { y_low = y1; y_hi = y2; } else { y_low = y2; y_hi = y1; } if ( x1 < x2 ) { x_low = x1; x_hi = x2; } else { x_low = x2; x_hi = x1; } while ( glGetError() != GL_NO_ERROR ) { ; } glReadBuffer( GL_BACK_LEFT ); glDisable( GL_TEXTURE_2D ); glPixelStorei( GL_PACK_ALIGNMENT, 1 ); unsigned char *data = new unsigned char[ ( x_hi - x_low + 1 ) * ( y_hi - y_low + 1 ) * 3 ]; glReadPixels( x_low, y_low, x_hi-x_low+1, y_hi-y_low+1, GL_RGB, GL_UNSIGNED_BYTE, data ); if ( glGetError() != GL_NO_ERROR ) { delete[] data; return 0; } else { return data; } }

utilizar:

CvSize size = cvSize( 320, 240 ); unsigned char *pixel_buf = getPixelData( 0, 0, size.width - 1, size.height - 1 ); if ( pixel_buf == 0 ) return 0; IplImage *result = cvCreateImage( size, IPL_DEPTH_8U, 3 ); memcpy( result->imageData, pixel_buf, size.width * size.height * 3 ); delete[] pixel_buf;