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