2009-07-09 15 views
11

Ho problemi a visualizzare un file YUV grezzo che è in formato NV12.Ho bisogno di aiuto con il display YUV in OpenGl

Posso visualizzare una cornice selezionata, tuttavia, è ancora principalmente in bianco e nero con alcune sfumature di rosa e verde.

Ecco come la mia uscita sembra alt text http://i32.tinypic.com/hv0vih.png

In ogni modo, ecco come funziona il mio programma. (Questo è fatto in cacao/oggettivo-c, ma ho bisogno del tuo consiglio esperto sull'algoritmo del programma, non sulla sintassi.)

Prima dell'esecuzione del programma, il file YUV è memorizzato in un file binario chiamato "test.yuv" . Il file è in formato NV12, il che significa che il piano Y viene memorizzato per primo, quindi il piano UV è interlacciato. La mia estrazione di file non ha alcun problema perché ho eseguito molti test su di esso.

Durante iniziazione, che crea una tabella di ricerca che converte binari/8 punture/un byte/caratteri nel rispettato Y, U, V galleggiante valori

Per piano Y è il mio codice

-(void)createLookupTableY //creates a lookup table for converting a single byte into a float between 0 and 1 
{ 
    NSLog(@"YUVFrame: createLookupTableY"); 
    lookupTableY = new float [256]; 

    for (int i = 0; i < 256; i++) 
    { 
     lookupTableY[i] = (float) i /255; 
     //NSLog(@"lookupTableY[%d]: %f",i,lookupTableY[i]);//prints out the value of each float 
    } 
} 

U aereo tabella di ricerca

-(void)createLookupTableU //creates a lookup table for converting a single byte into a float between 0 and 1 
{ 
    NSLog(@"YUVFrame: createLookupTableU"); 
    lookupTableU = new float [256]; 

    for (int i = 0; i < 256; i++) 
    { 
     lookupTableU[i] = -0.436 + (float) i/255* (0.436*2); 
     NSLog(@"lookupTableU[%d]: %f",i,lookupTableU[i]);//prints out the value of each float 
    } 
} 

e la tabella di ricerca V

-(void)createLookupTableV //creates a lookup table for converting a single byte into a float between 0 and 1 
{ 
    NSLog(@"YUVFrame: createLookupTableV"); 
    lookupTableV = new float [256]; 

    for (int i = 0; i < 256; i++) 
    { 
     lookupTableV[i] = -0.615 + (float) i /255 * (0.615*2); 
     NSLog(@"lookupTableV[%d]: %f",i,lookupTableV[i]);//prints out the value of each float 
    } 
} 

dopo questo punto, estrarre il piano UV Y & e memorizzare in due buffer, yBuffer & uvBuffer

a questo punto, tento di convertire i dati YUV e memorizzati in una matrice buffer RGB chiamato " frameImage"

-(void)sortAndConvert//sort the extracted frame data into an array of float 
{ 
    NSLog(@"YUVFrame: sortAndConvert"); 
    int frameImageCounter = 0; 
    int pixelCounter = 0; 
    for (int y = 0; y < YUV_HEIGHT; y++)//traverse through the frame's height 
    { 
     for (int x = 0; x < YUV_WIDTH; x++)//traverse through the frame's width 
     { 

      float Y = lookupTableY [yBuffer [y*YUV_WIDTH + x] ]; 
      float U = lookupTableU [uvBuffer [ ((y/2) * (YUV_WIDTH/2) + (x/2)) * 2 ] ]; 
      float V = lookupTableV [uvBuffer [ ((y/2) * (YUV_WIDTH/2) + (x/2)) * 2 + 1] ]; 

      float RFormula = Y + 1.13983f * V; 
      float GFormula = Y - 0.39465f * U - 0.58060f * V; 
      float BFormula = Y + 2.03211f * U; 

      frameImage [frameImageCounter++] = [self clampValue:RFormula]; 
      frameImage [frameImageCounter++] = [self clampValue:GFormula]; 
      frameImage [frameImageCounter++] = [self clampValue:BFormula]; 

     } 
    } 

} 

poi ho cercato di disegnare l'immagine in OpenGL

-(void)drawFrame:(int)x 
{ 

    GLuint texture; 

    glGenTextures(1, &texture); 
    glBindTexture(GL_TEXTURE_2D, texture); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, YUV_WIDTH, YUV_HEIGHT, 0, GL_RGB, GL_FLOAT, frameImage); 

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 

    glEnable(GL_TEXTURE_2D); 
    glBindTexture(GL_TEXTURE_2D, texture); 
    glRotatef(180.0f, 1.0f, 0.0f, 0.0f); 

    glBegin(GL_QUADS); 
    glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0); 
    glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0); 
    glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0); 
    glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0); 
    glEnd(); 

    glFlush(); 
} 

quindi fondamentalmente questo il mio programma in un guscio di noce. essenzialmente leggo i file YUV binari, memorizza tutti i dati in un buffer di array di caratteri. quindi traduco questi valori nei rispettivi valori float YUV rispettati.

Questo è dove penso che l'errore potrebbe essere: nella tabella di ricerca Y ho standardizzato il piano Y su [0,1], nel piano U ho standardizzato i valori tra [-0.435,0.436], e nel Piano V l'ho standardizzato tra [-0,615,0,615]. L'ho fatto perché quelli sono gli intervalli di valori YUV secondo wikipedia.

E la formula da YUV a RGB è la stessa formula di Wikipedia. Ho anche provato varie altre formule, e questa è l'unica formula che dà l'aspetto approssimativo del fotogramma. Chiunque potrebbe azzardarsi a indovinare perché il mio programma non sta visualizzando correttamente i dati del frame YUV. Penso che abbia a che fare con la mia tecnica di standardizzazione, ma mi sembra giusto.

Ho eseguito molti test e sono sicuro al 100% che l'errore sia causato dalla tabella di ricerca. Non penso che le mie formule di impostazione siano corrette.

Una nota per tutti coloro che stanno leggendo questo.Per il tempo più lungo, il mio frame non veniva visualizzato correttamente perché I non era in grado di estrarre correttamente i dati del frame .

Quando ho iniziato a programmare, ero l'impressione che in una clip di dicono 30 fotogrammi, tutti i 30 Y dati planari sono prima scritto nel file di dati, seguita poi da UV dati aereo.

Quello che ho scoperto attraverso tentativi ed errore è stato che per un file di dati YUV, specificamente NV12, il file di dati è memorizzati nel modo seguente

Y (1) UV (1) Y (2) UV (2) ... ...

@nschmidt

ho cambiato il mio codice a quello che lei ha suggerito

float U = lookupTableU [uvBuffer [ (y * (YUV_WIDTH/4) + (x/4)) * 2 ] ] 
float V = lookupTableU [uvBuffer [ (y * (YUV_WIDTH/4) + (x/4)) * 2 + 1] ] 

e questo è il risultato che ottengo alt text http://i26.tinypic.com/kdtilg.png

Ecco la linea di stampa dalla console. io sono stampare i valori per Y, U, V e valore RGB che vengono tradotti e salvati nella matrice frameImage

YUV: [0,658,824 mila, -0,022227, -0,045824] RGBFinal: [0.606593,0.694201,0.613655 ]

YUV: [0,643,137 mila, -0,022227, -,045824] RGBFinal: [0.590906,0.678514,0.597969]

YUV: [0,607,843 mila, -0,022227, -,045824] RGBFinal: [0.555612,0.643220,0.562675]

YUV: [0,592157, -0,022227, -0,045824] RGBFinale: [0,539926,0.627534,0,546988]

YUV: [0.643137,0.025647,0.151941] RGBFinal: [0.816324,0.544799,0.695255]

YUV: [0.662745,0.025647,0.151941] RGBFinal: [0.835932,0.564406,0.714863]

YUV: [0,690,196 mila , 0.025647,0.151941] RGBFinal: [0.863383,0.591857,0.742314]

Aggiornamento 13 luglio 2009

il problema è stato finalmente risolto grazie alla raccomandazione da nschmidt. Risulta che il mio file YUV era in realtà nel formato YUV 4: 1: 1. Inizialmente mi è stato detto che era in formato YUV NV12. Ad ogni modo, vorrei condividere i miei risultati con voi.

Ecco uscita

alt text http://i32.tinypic.com/35b9xf8.png

e il mio codice per la decodifica è la seguente

 float Y = (float) yBuffer [y*YUV_WIDTH + x] ; 
     float U = (float) uvBuffer [ ((y/2) * (YUV_WIDTH/2) + (x/2)) ] ; 
     float V = (float) uvBuffer [ ((y/2) * (YUV_WIDTH/2) + (x/2)) + UOffset] ; 

     float RFormula = (1.164*(Y-16) + (1.596* (V - 128))); 
     float GFormula = ((1.164 * (Y - 16)) - (0.813 * ((V) - 128)) - (0.391 * ((U) - 128))); 
     float BFormula = ((1.164 * (Y - 16)) + (2.018 * ((U) - 128))); 


     frameImage [frameImageCounter] = (unsigned char)((int)[self clampValue:RFormula]); 
     frameImageCounter ++; 
     frameImage [frameImageCounter] = (unsigned char)((int)[self clampValue:GFormula]); 
     frameImageCounter++; 
     frameImage [frameImageCounter] = (unsigned char)((int) [self clampValue:BFormula]); 
     frameImageCounter++; 



GLuint texture; 

glGenTextures(1, &texture); 
glEnable(GL_TEXTURE_2D); 

glBindTexture(GL_TEXTURE_2D, texture); 
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); 

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, YUV_WIDTH, YUV_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, frameImage); 

//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE_SGIS); 
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE_SGIS); 
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); 

glRotatef(180.0f, 1.0f, 0.0f, 0.0f); 

glBegin(GL_QUADS); 
glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0); 
glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0); 
glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0); 
glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0); 
glEnd(); 

NSLog(@"YUVFrameView: drawRect complete"); 
glFlush(); 

essenzialmente, ho usato NSData per l'estrazione di file RAW. memorizzato in un buffer di array di caratteri. Per la conversione da YUV a RGB, ho usato la formula precedente, successivamente ho bloccato i valori su [0: 255]. quindi ho usato una 2DTexture in OpenGL per la visualizzazione.

Quindi, se si converte YUV in RGB in futuro, utilizzare la formula dall'alto. Se stai utilizzando la formula di conversione da YUV a RGB dal post precedente, devi visualizzare la trama in GL_Float dai valori per RGB sono bloccati tra [0: 1]

risposta

8

Prossimo tentativo :) Penso che il buffer uv non sia interlacciato. Sembra che vengano prima i valori U e poi l'array di valori V. Modificare le linee in

unsigned int voffset = YUV_HEIGHT * YUV_WIDTH/2; 
float U = lookupTableU [uvBuffer [ y * (YUV_WIDTH/2) + x/2] ]; 
float V = lookupTableV [uvBuffer [ voffset + y * (YUV_WIDTH/2) + x/2] ]; 

potrebbe indicare se questo è veramente il caso.

+0

wow, ho provato il mio programma con la regolazione e alla fine ha funzionato. Grazie mille man.it ha scoperto che avevi ragione, l'aereo U & V non è interlacciato come mi era stato originariamente detto. grazie mille nschmidt. Sto valutando – ReachConnection

+0

nessun problema :). per la cronaca, la prima ipotesi sul formato 4: 1: 1 era in realtà errata. Hai il formato 4: 2: 2. Il vero problema era che i tuoi dati non erano interlacciati. – nschmidt

+0

@ReachConnection: Puoi dirmi cosa sta facendo [self clampValue: RFormula]? Sto pensando di usare il tuo codice per ottenere UIImage da YUV422. –

3

Penso che stai affrontando i valori U e V in modo non corretto. Piuttosto che:

float U = lookupTableU [uvBuffer [ ((y/2) * (x/2) + (x/2)) * 2 ] ]; 
float V = lookupTableV [uvBuffer [ ((y/2) * (x/2) + (x/2)) * 2 + 1] ]; 

Dovrebbe essere qualcosa sulla falsariga di

float U = lookupTableU [uvBuffer [ ((y/2) * (YUV_WIDTH/2) + (x/2)) * 2 ] ]; 
float V = lookupTableV [uvBuffer [ ((y/2) * (YUV_WIDTH/2) + (x/2)) * 2 + 1] ]; 
+0

grazie, ho perso questo errore. tuttavia, ho apportato le modifiche e la cornice visualizzata è ancora principalmente in bianco e nero, con sfumature rosa e verde qua e là. – ReachConnection

+0

Ho appena aggiunto un'immagine per mostrare come il mio output assomiglia a – ReachConnection

0

L'immagine appare come avete formato 4: 1: 1. Dovresti cambiare le tue linee a

float U = lookupTableU [uvBuffer [ (y * (YUV_WIDTH/4) + (x/4)) * 2 ] ] 
float V = lookupTableU [uvBuffer [ (y * (YUV_WIDTH/4) + (x/4)) * 2 + 1] ] 

Forse puoi pubblicare il risultato per vedere, che altro è sbagliato. Trovo sempre difficile pensarci. È molto più facile avvicinarsi a questo in modo iterativo.

Problemi correlati