2012-02-01 15 views
18

voglio ottenere ogni fotogramma OpenGL da un'animazione con glReadPixels() e convertire i dati in OpenCV :: Mat. So che glReadPixels() ottiene i dati da righe da quello inferiore a quello superiore, da sinistra a destra. D'altra parte, OpenCV memorizza i dati in modo diverso.conversione dei dati da glReadPixels() per OpenCV :: Mat

Qualcuno sa qualsiasi libreria o qualsiasi tutorial/esempio che mi aiuta a convertire i dati da glReadPixels ad un OpenCV: Mat in C++?

Sommario

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

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

risposta

42

prima cosa crea un vuoto (o unititialized) cv::Mat per i nostri dati da leggere in direttamente. Questo può essere fatto una volta all'avvio, ma d'altra parte cv::Mat::create non costa molto quando l'immagine ha già dimensioni e tipo corrispondenti. Il tipo dipende dalle tue esigenze, di solito è qualcosa come CV_8UC3 per un'immagine a colori a 24 bit.

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

o

img.create(height, width, CV_8UC3); 

poi si deve tenere conto di cv::Mat non neccessarily memorizzare file di immagine in modo contiguo. Potrebbe esserci un piccolo valore di padding alla fine di ogni riga per rendere le righe allineate a 4 byte (o 8?). Quindi è necessario pasticciare con le modalità di memorizzazione dei pixel:

//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()); 

Avanti, il tipo di matrice influenza i parametri di formato e tipo di glReadPixels. Se vuoi immagini a colori devi tenere presente che OpenCV solitamente memorizza i valori dei colori in ordine BGR, quindi è necessario utilizzare GL_BGR(A) (che sono stati aggiunti con OpenGL 1.2) anziché GL_RGB(A). Per le immagini di un componente utilizzare GL_LUMINANCE (che somma i singoli componenti del colore) o , GL_GREEN, ... (per ottenere un singolo componente). Così per la nostra immagine CV_8UC3 l'ultima chiamata per leggere direttamente nel cv::Mat sarebbe:

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

Infine, memorizza OpenCV immagini da cima a fondo. Quindi potresti aver bisogno di capovolgerli dopo averli catturati o renderli capovolti in OpenGL (questo può essere fatto regolando la matrice di proiezione, ma in questo caso tieni d'occhio l'orientamento del triangolo).Per riflettere una cv::Mat in verticale, è possibile utilizzare cv::flip:

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

Così da tenere a mente OpenCV:

  • memorizza le immagini dall'alto verso il basso, da sinistra a destra
  • negozi immagini a colori in ordine BGR
  • non potrebbe righe immagine negozio fitto
+0

risposta veramente bello. Stavo già lavorando al flipping ma non ho prestato attenzione a glPixelStorei. Grazie –

+0

Non riesco a chiamare GL_BGR, non so perché il linker non riesce a trovarlo perché ho l'ultima versione –

+1

@Jav_Rock È stato introdotto con OpenGL 1.2. Quindi, se l'hardware e il driver lo supportano (il che è molto probabile, a meno che tu non abbia acquistato la tua scheda grafica 20 anni fa), devi solo definire questo simbolo, includendo un [. Glext.h'] ragionevolmente nuovo (http: // www.opengl.org/registry/api/glext.h) o utilizzando una libreria di gestione delle estensioni in primo luogo (come GLEW), che dovrebbe portare la propria intestazione con definizioni costanti. Ciò sarebbe necessario se si desidera utilizzare qualsiasi funzionalità superiore a 1.1, ad ogni modo (come i PBO, che potrebbero velocizzare le prestazioni di lettura che vengono utilizzate correttamente). –

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;