2012-02-01 17 views
18

que quieren conseguir cada cuadro 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.datos de conversión de glReadPixels() para OpenCV :: Mat

¿Alguien sabe cualquier biblioteca o cualquier tutorial/ejemplo que me ayuda a convertir los datos de glReadPixels a un OpenCV : Mat en C++?

RESUMEN

OpenGL frame  ----------------------->  CV::Mat 

Data from left to right,     Data from left to right, 
bottom to top.        top to bottom. 

Respuesta

42

En primer lugar, crear un vacío (o unititialized) cv::Mat para nuestros datos para ser leídos en forma directa. Esto se puede hacer una vez al inicio, pero por otro lado, cv::Mat::create 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); 

entonces usted tiene que dar cuenta de cv::Mat no necesariamente siempre el almacenamiento de filas imagen contigua. Puede haber un pequeño valor de relleno al final de cada fila para alinear las filas de 4 bytes (¿o 8?). Así que hay que meterse 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 la matriz influye en los parámetros de formato y tipo de glReadPixels. Si desea imágenes en color, debe tener en cuenta que, por lo general, OpenCV almacena 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 imágenes de un componente, utilice GL_LUMINANCE (que resume los componentes de color individuales) o GL_RED, GL_GREEN, ... (para obtener un componente individual). Así que para nuestra imagen CV_8UC3 el último momento para leer directamente en el cv::Mat sería:

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

Por último, tiendas de OpenCV 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 una cv::Mat verticalmente, puede utilizar cv::flip:

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

Así que tener en cuenta OpenCV:

  • almacena las imágenes de arriba a abajo, de izquierda a derecha
  • almacena imágenes en color con el fin BGR
  • no podría filas imagen de la tienda apretada
+0

muy, muy agradable respuesta. Ya estaba trabajando en el volteo, pero no le presté atención a glPixelStorei. Gracias –

+0

No puedo llamar a GL_BGR, no sé por qué el enlazador no puede encontrarlo porque tengo la última versión –

+1

@Jav_Rock Se introdujo con OpenGL 1.2. Entonces, si su hardware y controlador lo admiten (lo cual es muy probable, a menos que haya comprado su tarjeta gráfica hace 20 años), solo necesita definir este símbolo, incluyendo un ['glext.h'] razonablemente nuevo (http: // www.opengl.org/registry/api/glext.h) o mediante el uso de una biblioteca de administración de extensiones en primer lugar (como GLEW), que debe traer su propio encabezado con definiciones constantes. Esto sería necesario una vez que desee utilizar cualquier funcionalidad superior a 1.1, de todos modos (como las PBO, lo que puede acelerar su rendimiento de lectura si se usa correctamente). –

1
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; 
    } 
} 

uso:

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; 
Cuestiones relacionadas