2009-07-09 14 views
11

Tengo problemas para visualizar un archivo YUV sin procesar que está en formato NV12.Necesito ayuda con la visualización de YUV en OpenGl

Puedo mostrar un marco seleccionado, sin embargo, sigue siendo principalmente en blanco y negro con ciertos tonos de rosa y verde.

Aquí es cómo mi salida parece alt text http://i32.tinypic.com/hv0vih.png

De todas formas, aquí es cómo funciona mi programa. (Esto se hace en cocoa/object-c, pero necesito su consejo experto sobre algoritmo de programa, no sobre sintaxis.)

Antes de la ejecución del programa, el archivo YUV se almacena en un archivo binario llamado "test.yuv" . El archivo está en formato NV12, lo que significa que el plan Y se almacena primero, luego el plan UV se entrelaza. La extracción de mi archivo no tiene ningún problema porque hice muchas pruebas al respecto.

Durante la iniciación, puedo crear una tabla de búsqueda que convertirá binarios/8 picaduras/un byte/caracteres en respetado Y, U, V flotador valora

Para el plano Y esto es mi código

-(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 
    } 
} 

el T Plano tabla de búsqueda

-(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 
    } 
} 

Y la tabla V de búsqueda

-(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 
    } 
} 

después de este punto, extraer el plan de UV Y & y almacenarlos en dos tampones, yBuffer & uvBuffer

en este punto, intento para convertir los datos YUV y se almacenan en una matriz de tampón de RGB llamado " 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]; 

     } 
    } 

} 

entonces trató de dibujar la imagen en 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(); 
} 

así que básicamente esta mi programa en una cáscara de nuez Básicamente, leí los archivos binarios YUV, almacena todos los datos en un búfer de arreglo de caracteres. Luego traduzco estos valores en sus respetados valores de flotación YUV.

Aquí es donde creo que podría estar el error: en la tabla de búsqueda Y estandarizo el plano Y a [0,1], en el plano U estandaricé los valores entre [-0.435,0.436] y en el Plano V lo estandaricé entre [-0.615.0.615]. Lo hice porque esos son los rangos de valores de YUV según wikipedia.

Y la fórmula YUV a RGB es la misma fórmula de Wikipedia. También probé otras fórmulas, y esta es la única fórmula que ofrece la perspectiva aproximada del marco. Cualquiera podría aventurarse a adivinar por qué mi programa no muestra correctamente los datos del marco YUV. Creo que tiene algo que ver con mi técnica de estandarización, pero a mí me parece bien.

He hecho muchas pruebas, y estoy 100% seguro de que el error está causado por la tabla de búsqueda. No creo que mis fórmulas de configuración sean correctas.

Una nota a todos los que están leyendo este .Durante más tiempo, mi cuadro no se mostraba correctamente porque I no pudo extraer correctamente los datos de trama .

Cuando empecé a programar, yo era bajo la impresión de que en un clip de dicen 30 cuadros, todos los datas más planas 30 Y se escriben primero en el archivo de datos, seguido por datas más planas UV.

Lo que descubrí a través de ensayo y error fue que para un archivo de datos YUV, específicamente NV12, el archivo de datos es almacena en la siguiente manera

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

@nschmidt

he cambiado mi código para lo que usted sugiere

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

y esto es el resultado de que me sale alt text http://i26.tinypic.com/kdtilg.png

aquí es la línea de impresión desde la consola. i soy imprimir los valores de Y, U, V y valor RGB que se está traduciendo y almacenados en la matriz frameImage

YUV: [0.658824, -0.022227, -0.045824] RGBFinal: [0.606593,0.694201,0.613655 ]

YUV: [0.643137, -0.022227, -0.045824] RGBFinal: [0.590906,0.678514,0.597969]

YUV: [0.607843, -0.022227, -0.045824] RGBFinal: [0.555612,0.643220,0.562675]

YUV: [0.592157, -0.022227, -0.045824] RGBFinal: [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,690196 , 0.025647,0.151941] RGBFinal: [0.863383,0.591857,0.742314]

actualización 13 de julio de, 2009

el problema fue finalmente resuelto gracias a la recomendación de nschmidt. Resultó que mi archivo YUV estaba realmente en formato YUV 4: 1: 1. Originalmente me dijeron que estaba en formato YUV NV12. De todos modos, me gustaría compartir mis resultados con usted.

Aquí se emite

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

y mi código para decodificar es el siguiente

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

esencialmente, solía NSData para la extracción de archivos en bruto. almacenado en un búfer de matriz char. Para la conversión de YUV a RGB, utilicé la fórmula anterior, luego, fijé los valores en [0: 255]. luego usé una textura 2D en OpenGL para mostrar.

Así que si está convirtiendo YUV a RGB en el futuro, use la fórmula de arriba. Si usa la fórmula de conversión YUV a RGB de la publicación anterior, necesita visualizar la textura en GL_Float a partir de los valores para RGB que están sujetos entre [0: 1]

Respuesta

8

Siguiente intento :) Creo que tu buffer uv no está entrelazado. Parece que los valores U vienen primero y luego la matriz de valores V. Cambiar las líneas a

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] ]; 

puede indicar si este es realmente el caso.

+0

guau, probé mi programa con su ajuste y finalmente funcionó. Muchas gracias amigo. Resulta que tenías razón, el avión de U & V no está entrelazado como me dijeron originalmente. muchas gracias nschmidt. Te estoy clasificando – ReachConnection

+0

no hay problema :). para el registro, la primera suposición acerca de que el formato era 4: 1: 1 era realmente incorrecta. Tienes formato 4: 2: 2. El problema real era solo que sus datos no estaban entrelazados. – nschmidt

+0

@ReachConnection: ¿Puedes decirme qué [auto clampValue: RFormula] esta función está haciendo? Estoy planeando utilizar tu código para obtener UIImage de YUV422. –

3

Creo que está abordando los valores U y V incorrectamente. En lugar de:

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

Debe ser algo en la línea de

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

gracias, me perdí este error. sin embargo, realicé los cambios y el marco mostrado sigue siendo principalmente en blanco y negro, con matices rosas y verdes aquí y allá. – ReachConnection

+0

Acabo de agregar una imagen para mostrar cómo mi salida se ve como – ReachConnection

0

La imagen parece que tiene el formato 4: 1: 1. Debe cambiar sus líneas a

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

Quizás pueda publicar el resultado para ver qué más está mal. Encuentro siempre difícil pensar en eso. Es mucho más fácil abordar esto de forma iterativa.

Cuestiones relacionadas