سؤال

أواجه مشكلة في عرض ملف YUV الخام هو في تنسيق NV12.

يمكنني عرض إطار محدد، ومع ذلك، لا يزال بشكل أساسي بالأبيض والأسود مع ظلال معينة من الوردي والأخضر.

وهنا كيف يبدو خرجيalt text

على أي حال، هنا هو كيف يعمل برنامجي. (يتم ذلك في الكاكاو / الهدف - ج، لكنني بحاجة إلى مشورة الخبراء الخاصة بك بشأن خوارزمية البرنامج، وليس على بناء جملة.)

قبل تنفيذ البرنامج، يتم تخزين ملف YUV في ملف ثنائي باسم "Test.yuv". الملف في تنسيق NV12، وهذا يعني أن خطة Y يتم تخزينها أولا، ثم تتداخل خطة الأشعة فوق البنفسجية. استخراج الملفات ليس له مشكلة لأنني فعلت الكثير من الاختبارات عليها.

أثناء البدء، أقوم بإنشاء طاولة بحث يقوم بتحويل Binary / 8 Bites / A / chars إلى محترم Y، U، V تعويم القيم

ل y هذا هو رمز بلدي

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

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

و جدول البحث الخامس

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

بعد هذه النقطة، استخراج خطة Y والأشعة فوق البنفسجية وتخزينها إلى اثنين من المخازن المؤقتة، ybuffer & uvbuffer

في هذه المرحلة، أحاول تحويل بيانات YUV وتخزينها في صفيف مخزن مؤقت RGB يسمى "FrameImImage"

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

        }
    }

}

ثم حاولت رسم الصورة في 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();
}

لذلك في الأساس هذا البرنامج الخاص بي في قذيفة الجوز. أساسا قرأت ملفات yuv الثنائية، يخزن جميع البيانات في مخزن مخزن صفيف char. ثم قمت بترجمة هذه القيم إلى قيم تعويم YuV المحترمة.

هذا هو المكان الذي أعتقد أنه قد يكون الخطأ: في جدول البحث Y، أقوم بتوحيد الطائرة Y إلى [0،1]، في الطائرة التي قمت بتوحيد القيم بين [-0.435،0.436]، وفي الطائرة V أنا موحد إنه بديه [-0.615،0.615]. فعلت هذا لأن تلك هي نطاقات قيمة YUV وفقا ل Wikipedia.

وصيغة YUV إلى RGB هي نفس الصيغة من ويكيبيديا. لقد جربت أيضا العديد من الصيغ الأخرى، وهذه هي الصيغة الوحيدة التي تعطي النظرة الخام للإطار. قد يقوم أي شخص بممارسة التخمين لماذا لا يعرض برنامجي بشكل صحيح بيانات الإطارات YUV بشكل صحيح. أعتقد أن الأمر يتعلق بتقنية التقييس الخاصة بي، لكن يبدو أنه بخير بالنسبة لي.

لقد فعلت الكثير من الاختبارات، وأنا متأكد 100٪ أن الخطأ ناتج عن طريق البحث عن الجدول. لا أعتقد أن صيغ الإعداد صحيحة.

ملاحظة لكل من يقرأ هذا. لأطول وقت، لم يتم عرض إطاري بشكل صحيح لأنني لم أتمكن من استخراج بيانات الإطار بشكل صحيح.

عندما بدأت في البرنامج لأول مرة، كنت تحت الانطباع بأنه في مقطع من أقول 30 إطارات، تتم كتابة جميع 30 y Planar Datas أولا في ملف البيانات، متبوعة ثم بواسطة Datas الطائرة UV.

ما اكتشفته من خلال التجربة والخطأ هو أنه بالنسبة لملف بيانات YUV، وتحديدا NV12، يتم تخزين ملف البيانات في الأزياء التالية

y (1) uv (1) y (2) uv (2) ...

@ nschmidt.

غيرت الرمز الخاص بي إلى ما اقترحته

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

وهذا هو النتيجة التي أحصل عليهاalt text

هنا هو خط الطباعة من وحدة التحكم. أنا أطبع قيم قيمة Y و U و V و RGB التي يتم ترجمتها وتخزينها في صفيف FrameImImage

YuV: [0.658824، -0.022227، -0.045824] RGBFINAL: [0.606593،0.694201.0.613655

YUV: [0.643137، -0.022227، -0.045824] RGBILL: [0.590906،0.678514،0.597969

YUV: [0.607843، -0.022227، -0.045824] RGBILL: [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.151947.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

تحديث 13 يوليو 2009

تم حل المشكلة أخيرا بفضل التوصية nschmidt. وبعد اتضح أن ملف YUV الخاص بي كان بالفعل في تنسيق YUV 4: 1: 1. لقد قيل لي في الأصل أنه في شكل YUV NV12. على أي حال، أود أن أشارك نتائجي معك.

هنا هو الإخراج

alt text

وشدفي فك التشفير كما يلي

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

أساسا، استخدمت NSDATA لاستخراج الملفات الخام. تخزينها في مجموعة مخزنة على مجموعة. بالنسبة إلى YuV لتحويل RGB، استخدمت الصيغة المذكورة أعلاه، بعد ذلك، فقد فرضت القيم إلى [0: 255]. ثم استخدمت 2dTexture في OpenGL لعرضها.

لذلك إذا كنت تتحول YuV إلى RGB في المستقبل، فاستخدم الصيغة من الأعلى. إذا كنت تستخدم YUV To RGB تحويل الصيغة من المنشور السابق، فأنت بحاجة إلى عرض الملمس في gl_float من قيم RGB محصنة بين [0: 1

هل كانت مفيدة؟

المحلول

حاول التالي :) أعتقد أنك مخزن مؤقت للأشعة فوق البنفسجية غير مشعوذ. يبدو أن قيمك تأتي أولا ثم صفيف قيم V. تغيير الخطوط إلى

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

قد تشير إذا كان هذا هو الحال حقا.

نصائح أخرى

أعتقد أنك تعالج القيم U و V غير صحيحة. بدلا من:

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

يجب أن يكون شيئا على غرار

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

تبدو الصورة مثلك على شكل 4: 1: 1. يجب عليك تغيير خطوطك إلى

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

ربما يمكنك نشر النتيجة لمعرفة، ماذا هو الخطأ. أجد أنه من الصعب دائما التفكير في الأمر. من الأسهل بكثير الاقتراب من هذا تكرارا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top