문제

NV12 형식으로 사용되는 RAW YUV 파일을 표시하는 데 어려움이 있습니다.

선택한 프레임을 표시 할 수 있지만 여전히 핑크색과 녹색의 특정 음영이있는 검은 색과 흰색으로 남아 있습니다.

내 출력의 모습은 다음과 같습니다alt text

어쨌든 여기 내 프로그램이 작동하는 방식이 있습니다. (이것은 Cocoa/Objective-C에서 이루어 지지만 구문이 아닌 프로그램 알고리즘에 대한 전문가의 조언이 필요합니다.)

프로그램 실행 전에 YUV 파일은 "test.yuv"라는 이진 파일에 저장됩니다. 파일은 NV12 형식으로 이루어 지므로 Y 계획이 먼저 저장된 다음 UV 계획이 인터레이스됩니다. 내 파일 추출은 많은 테스트를 수행했기 때문에 아무런 문제가 없습니다.

시작하는 동안 바이너리/8 비트/바이트/숯을 존경받는 y, u, v float 값으로 변환하는 조회 테이블을 만듭니다.

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

그리고 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
    }
}

이 시점 후, 나는 Y & UV 계획을 추출하여 두 버퍼 인 Ybuffer & Uvbuffer에 저장합니다.

이 시점에서 YUV 데이터를 변환하고 "FrameImage"라는 RGB 버퍼 배열에 저장하려고합니다.

-(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 Array 버퍼에 저장합니다. 그런 다음이 값을 존경받는 yuv 플로트 값으로 변환합니다.

이곳은 오류가 될 수 있다고 생각합니다. y 조회 테이블 I에서 y 평면을 [0,1]로 표준화하고 U 평면 I에서 [-0.435,0.436] 사이의 값을 표준화했으며 V 평면 I의 값을 표준화했습니다. 그것은 bewteen [-0.615,0.615]. Wikipedia에 따르면 그것들이 YUV 가치 범위이기 때문에 이것을했습니다.

YUV에서 RGB 공식은 Wikipedia와 동일한 공식입니다. 나는 또한 다양한 다른 공식을 시도했으며, 이것은 프레임의 거친 전망을주는 유일한 공식입니다. 내 프로그램이 왜 YUV 프레임 데이터를 올바르게 표시하지 않는지 추측하기 위해 모험을 할 수 있습니다. 나는 그것이 내 표준화 기술과 관련이 있다고 생각하지만 나에게는 괜찮아 보인다.

나는 많은 테스트를 수행했으며, Orug Up Table에 의해 오류가 발생한다고 100% 확신합니다. 내 설정 공식이 정확하다고 생각하지 않습니다.

이것을 읽는 모든 사람에게 메모. 가장 오랫동안 프레임 데이터를 올바르게 추출 할 수 없었기 때문에 프레임이 제대로 표시되지 않았습니다.

처음 프로그램을 시작했을 때, 30 프레임의 클립에서 30 y 평면 데이터가 먼저 데이터 파일로 작성된 다음 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 값의 값을 인쇄합니다.

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.54799,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.86383,0.591857,0.742314

2009 년 7 월 13 일 업데이트

의 추천 덕분에 문제가 마침내 해결되었습니다. 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]로 클램핑했습니다. 그런 다음 OpenGL에서 2DTexture를 사용하여 디스플레이를 사용했습니다.

따라서 향후 YUV를 RGB로 변환하는 경우 위의 공식을 사용하십시오. 이전 게시물에서 YUV에서 RGB 변환 공식을 사용하는 경우 RGB 값에서 GL_FLOAT의 텍스처를 [0 : 1] 사이에 클램핑해야합니다.

도움이 되었습니까?

해결책

다음 시도 :) UV 버퍼가 인터리브되지 않았다고 생각합니다. u 값이 먼저오고 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] ];

이것이 실제로 사실인지 나타낼 수 있습니다.

다른 팁

나는 당신이 당신과 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