2009-07-09 3 views
11

원시 YUV 파일을 NV12 형식으로 표시하는 데 문제가 있습니다.OpenGl에서 YUV 디스플레이에 대한 도움이 필요합니다.

내가 선택한 프레임을 표시 할 수 있지만, 여전히 주로 핑크와 녹색의 특정 음영이있는 흑백으로되어 있습니다. 여기

내 출력이 어쨌든 alt text http://i32.tinypic.com/hv0vih.png

과 같은 방법 여기, 내 프로그램이 작동하는 방법이다. (이것은 코코아/objective-c에서 행해지지만, 문법이 아닌 프로그램 알고리즘에 대한 전문가의 조언이 필요합니다.)

프로그램 실행에 앞서 YUV 파일은 "test.yuv"라는 이진 파일에 저장됩니다. . 파일은 NV12 형식으로되어 있습니다. 즉, Y 계획이 먼저 저장되고 UV 계획이 인터레이스됩니다. 필자가 테스트를 많이했기 때문에 파일 추출에 문제가 없습니다.

가 시작하는 동안, 나는 Y는, U는, V 플로트이는 Y 평면

값 존중에 진/8 바이트/바이트/문자로 변환하는 룩업 테이블을 생성하는 것은 내 코드입니다

-(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 룩업 테이블

는 "I가 YUV 데이터로 변환하려고하고 불리는 RGB 버퍼 배열로 저장이 시점 이후, I는 Y & UV 계획을 추출하고이 시점에서, 두 개의 버퍼에 yBuffer & uvBuffer

를 저장할 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]; 

     } 
    } 

} 

는 그래서 기본적으로
-(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(); 
} 

A의이 내 프로그램 OpenGL을

의 이미지를 그리는 시도 너트 쉘. 본질적으로 이진 YUV 파일을 읽고 모든 데이터를 char 배열 버퍼에 저장합니다. 그런 다음이 값을 존중받는 YUV 부동 소수점 값으로 변환합니다.

여기 내가 생각하는 오류는 다음과 같습니다. Y 룩업 테이블에서 나는 Y 평면을 [0,1]로 표준화하고 U 평면에서는 [-0.435,0.436] 사이의 값을 표준화했으며 V 비행기 I는 그것을 표준화했다 [-0.615,0.615]. 위키피디아에 따르면 YUV 값 범위이기 때문에이 작업을 수행했습니다.

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

많은 테스트를 해본 결과 오류를 조회하는 테이블이 100 % 확실하다는 것을 확신합니다. 나는 나의 설정 공식이 옳다고 생각하지 않는다.

읽고있는 사람에게 보내는 메모입니다. 입니다.가장 긴 시간 동안 프레임 데이터를 올바르게 추출 할 수 없기 때문에 프레임이 올바르게 표시되지 않았습니다. . 프레임 데이터를 올바르게 추출 할 수 없었습니다. 처음 프로그램을 시작할 때

, 제가 의 클립의 30 프레임 먼저 데이터 파일에 기입 된 모든 30 Y 평면 datas 말하는 것으로 인상 이었다 는 UV 평면 datas하여 다음 하였다.

I 재판 통해 발견 오류가 YUV 데이터 파일, 구체적 NV12는, 상기 데이터 파일은 다음 방식으로 저장 것이 무엇 이었는가

Y (1) UV (1) Y (2) UV (2) ... ... 난 당신이

float U = lookupTableU [uvBuffer [ (y * (YUV_WIDTH/4) + (x/4)) * 2 ] ] 
float V = lookupTableU [uvBuffer [ (y * (YUV_WIDTH/4) + (x/4)) * 2 + 1] ] 
을 제안 무엇에 내 코드를 변경

@nschmidt

는이 내가 여기 alt text http://i26.tinypic.com/kdtilg.png

콘솔에서 인쇄 라인 얻을 결과입니다. 난 번역 및 frameImage 어레이에 저장되는 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] RGB 최종 : [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]

업데이트 문제는 결국 nschmidt에서 추천 덕분에 해결되었다 2009

7 월 13 일. 내 YUV 파일은 실제로 YUV 4 : 1 : 1 형식이었습니다. 원래 YUV NV12 형식이라고 들었습니다. 어쨌든, 나는 결과를 당신과 공유하고 싶습니다. 여기

출력

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

이고

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

본질적, I 원시 파일 추출을 NSData 사용 다음 디코드 내 코드이다. char 배열 버퍼에 저장된다. YUV에서 RGB 로의 변환의 경우 위의 공식을 사용하여 값을 [0 : 255]로 고정했습니다. 그런 다음 OpenGL에서 2DTexture를 사용하여 표시했습니다.

미래에 YUV를 RGB로 변환하는 경우 위 공식을 사용하십시오. 이전 게시물에서 YUV - RGB 변환 공식을 사용하는 경우 RGB 값이 [0 : 1] 사이에 고정되어있는 값에서 GL_Float의 텍스처를 표시해야합니다.

답변

8

다음 시도 : 나는 당신이 버퍼가 인터리브되지 않았다고 생각합니다. 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] ]; 

으로 변경하면 실제 상황인지 여부를 나타낼 수 있습니다.

+0

인 것처럼 보이도록 이미지를 추가했습니다. 조정으로 내 프로그램을 테스트 한 결과 마침내 효과가있었습니다. 고마워요. 당신이 옳았다는 것이 드러났습니다. U & V 비행기는 원래 내가 말했던 것처럼 비월 주사가 아닙니다. 정말 감사드립니다. 나는 – ReachConnection

+0

아무런 문제가 없다고 평가하고 있습니다 :). 레코드의 경우 4 : 1 : 1 인 형식에 대한 첫 번째 추측은 실제로 올바르지 않습니다. 당신은 4 : 2 : 2 형식입니다. 실제 문제는 데이터가 인터리브되지 않는 것뿐이었습니다. – nschmidt

+0

@ReachConnection : [self clampValue : RFormula]가 무엇을하고 있는지 말해 줄 수 있습니까? 당신의 코드를 사용하여 YUV422에서 UIImage를 얻을 계획입니다. –

3

U 및 V 값을 처리한다고 생각합니다. 틀리게. 보다는 : 1 : 1 형식

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

그것은 당신이 4를 가지고있는 것처럼 사진이 보이는

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

감사합니다. 나는이 실수를 놓쳤습니다. 그러나 나는 변화를 만들었고, 표시된 프레임은 여전히 ​​주로 흑백으로, 여기 저기에 분홍색과 초록색 음영이 있습니다. – ReachConnection

+0

방금 ​​출력이 – ReachConnection

0

의 라인을 따라 뭔가해야합니다. 회선을

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

으로 변경해야 할 수도 있습니다. 그 밖의 결과를 게시 할 수 있습니다. 나는 항상 그것에 대해 생각하기가 어렵다는 것을 안다. 반복적으로 접근하는 것이 훨씬 쉽습니다.

관련 문제