Anzeige YUV in OpenGl
-
12-09-2019 - |
Frage
Ich habe Probleme eine rohe YUV-Datei anzeigt, die es in NV12-Format ist.
Ich kann einen ausgewählten Rahmen angezeigt wird, ist es jedoch nach wie vor hauptsächlich in schwarz und weiß mit bestimmten Farben rosa und grün ist.
Hier ist, wie meine Ausgabe aussieht
Wie auch immer, hier ist, wie mein Programm funktioniert. (Dies ist in Kakao / Objective-c getan, aber ich brauche Ihre kompetente Beratung über Programmalgorithmus, nicht auf Syntax.)
Vor der Ausführung zu programmieren, die YUV-Datei in einer binären Datei mit dem Namen „test.yuv“ gespeichert. Die Datei ist in NV12-Format, dh der Y-Plan zuerst gespeichert ist, dann wird der UV-Plan verschachtelt ist. Meine Dateiextrahierung hat kein Problem, weil ich viel testings auf es getan hat.
Während der Initiation, erstelle ich eine Lookup-Tabelle, die binäre / 8 Bisse konvertieren / ein Byte / Zeichen in respektiert Y, U, V Float-Werte
Für die Y-Ebene dies ist mein Code
-(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
}
}
Die U-Ebene Lookup-Tabelle
-(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
}
}
Und die V Nachschlagetabelle
-(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
}
}
nach diesem Punkt zu extrahieren ich die Y & UV-Plan und speichere sie in zwei Puffer, yBuffer & uvBuffer
an dieser Stelle versuche ich die YUV-Daten zu konvertieren und es in einen RGB-Puffer-Array gespeichert namens „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];
}
}
}
Dann habe ich versucht, das Bild in OpenGl
zu ziehen-(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();
}
also im Grunde das ist mein Programm in einer Nussschale. im wesentlichen gelesen i die binären Dateien YUV, speichert alle Daten in einem Array char Puffer. i dann diese Werte in ihren respektierten YUV Float-Werte übersetzen.
Dies ist, wo ich die Fehler denken könnten: in der Y-Lookup-Tabelle I die Y-Ebene auf [0,1], in der U-Ebene zu standardisieren standardisierte ich die Werte zwischen [-0.435,0.436] und in dem V Ebene standardisiert ich es bewteen [-0.615,0.615]. Ich tat dies, weil diejenigen, die YUV-Wertebereiche nach wikipedia sind.
Und die YUV auf RGB-Formel ist die gleiche Formel, die aus der Wikipedia. Ich habe auch verschiedene andere Formeln versucht, und dies ist die einzige Formel, die die groben Aussichten des Rahmens gibt. Wer könnte wagen zu erraten, warum mein Programm ist nicht korrekt die YUV-Rahmendaten. Ich denke, es ist etwas mit meiner Standardisierungstechnik zu tun, aber es scheint in Ordnung für mich.
Ich habe eine Menge von testings getan, und ich bin 100% sicher, dass der Fehler verursacht wird, durch durch Tabelle nachschlagen. Ich glaube nicht, meine Einstellung Formeln korrekt sind.
Ein Hinweis an alle, die das Lesen ist diese. Für die längste Zeit, mein Rahmen war nicht richtig, weil ich die Anzeige war nicht in der Lage die Rahmendaten zu extrahieren, richtig.
Als ich zuerst nach Programm gestartet, war ich unter dem Eindruck, dass in einem Clip von 30 Rahmen sagen, alle 30 Daten Y planar wird zunächst in der Datendatei geschrieben, gefolgt dann durch UV-Ebene Daten.
Was ich herausgefunden habe, durch Versuch und Fehler war, dass für eine YUV-Datendatei, speziell NV12, ist die Datendatei in der folgenden Art und Weise gespeichert
Y (1) UV (1) Y (2) UV (2) ... ...
@nschmidt
Ich änderte meinen Code zu dem, was Sie vorgeschlagen
float U = lookupTableU [uvBuffer [ (y * (YUV_WIDTH / 4) + (x/4)) * 2 ] ]
float V = lookupTableU [uvBuffer [ (y * (YUV_WIDTH / 4) + (x/4)) * 2 + 1] ]
und das ist das Ergebnis, das ich bekommen
Hier ist die Druckleitung von der Konsole. Ich bin die Werte für Y, U, V ausdrucken und RGB-Wert, der in der Frameimage Array übersetzt und gespeichert werden auf
YUV: [0.658824, -0,022227, -,045824] RGBFinal: [0.606593,0.694201,0.613655]
YUV: [0.643137, -0,022227, -,045824] RGBFinal: [0.590906,0.678514,0.597969]
YUV: [0.607843, -0,022227, -,045824] RGBFinal: [0.555612,0.643220,0.562675]
YUV: [0.592157, -0,022227, -,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]
Update 13. Juli 2009
Das Problem wurde schließlich dank der Empfehlung gelöst von nschmidt . Es stellt sich heraus, dass meine YUV-Datei in YUV tatsächlich war 4: 1: 1-Format. Ich war ursprünglich gesagt, dass es in YUV NV12 Format ist. Wie auch immer, ich möchte meine Ergebnisse mit Ihnen teilen.
Hier wird ausgegeben
und mein Code für decode ist wie folgt
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();
Im Wesentlichen habe ich NSData für die RAW-Datei-Extraktion. in einem Array char Puffer gespeichert. Für YUV auf RGB-Konvertierung, verwendete ich die obige Formel, danach geklemmt ich die Werte auf [0: 255]. dann habe ich eine 2DTexture in OpenGL für die Anzeige.
Wenn Sie also YUV auf RGB in Zukunft Umwandlung sind, verwenden Sie die Formel von oben. Wenn sich die YUV auf RGB Umrechnungsformel aus der früheren Post verwenden, dann müssen Sie aus den Werten für RGB die Textur in GL_FLOAT angezeigt werden eingespannt zwischen [0: 1]
Lösung
Nächster Versuch :) Ich glaube, Sie sind UV-Puffer nicht verschachtelt ist. Es sieht aus wie die U-Werte kommen zuerst und dann die Anordnung von V-Werten. Ändern der Zeilen
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] ];
könnte darauf hindeuten, ob dies wirklich der Fall ist.
Andere Tipps
Ich glaube, du Adressierung falsch U und V-Werte. Anstatt:
float U = lookupTableU [uvBuffer [ ((y / 2) * (x / 2) + (x/2)) * 2 ] ];
float V = lookupTableV [uvBuffer [ ((y / 2) * (x / 2) + (x/2)) * 2 + 1] ];
Es sollte etwas entlang der Linien von
seinfloat U = lookupTableU [uvBuffer [ ((y / 2) * (YUV_WIDTH / 2) + (x/2)) * 2 ] ];
float V = lookupTableV [uvBuffer [ ((y / 2) * (YUV_WIDTH / 2) + (x/2)) * 2 + 1] ];
Das Bild sieht aus wie Sie haben 4: 1: 1-Format. Sie sollten Ihre Zeilen
ändernfloat U = lookupTableU [uvBuffer [ (y * (YUV_WIDTH / 4) + (x/4)) * 2 ] ]
float V = lookupTableU [uvBuffer [ (y * (YUV_WIDTH / 4) + (x/4)) * 2 + 1] ]
Vielleicht können Sie das Ergebnis veröffentlichen, um zu sehen, was sonst falsch ist. Ich finde es immer schwer, darüber nachzudenken. Es ist viel einfacher, dies iterativ zu nähern.