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;