2008. 9. 29. 18:27

YUV(YCbCr) 변환에 대하여


YUV와 YIQ는 TV에 사용되는 색 표현방식이다.
YUV방식은 사람의 눈이 색상보다는 밝기에 민감하다는 사실에 착안한
방식으로,
색을 밝기(Luminance)인 Y성분과 색상(Chrominance)인 U(Cb)V(Cr) 성분으로

구분한다.
Y성분은 오차에 민감하므로 색상성분인 U와 V보다 많은 비트를 코딩한다.

전형적인 Y:U:V의 비율은 4:2:2 이다.
YUV 방식은 CD-I와 DYI (Digital Video Interactive)에서도 사용된다.

(Y 성분은 이미지를 Gray로 만든 것과 같다)

 

왜 RGB 정보를 그냥 이용하지 않고 YUV로 포맷을 변화시키냐면,

단순히 RGB 정보로 그 값을 기록했을 경우보다 YUV를 통하면 더 작은 데이터를 

만들어내서, 특히 대역폭(bandwidth)이 낮은

경우에 적합하게 표현할 수 있기 때문이다

 

+주의점+

YUV 파일 형식은, U,V data의 배열에 따라 Direction이 존재하는데 보통

Direction Vertical의 YUV420을 주로 사용한다.

그래서 파일로 저장할때는, Direction을 염두에 두고, 파일에 저장해야 하는데-

Direction Vertical은 Y에 덧붙여 U를 쓰고, V를 모두 쓴다

Direction Horizontal은 Y에 덧붙여서 U를 width/2 화소만큼, 

V를 width/2 화소만큼 번갈아가며 저장하게 된다

저장방법이 복잡해서 Direction Vertical을 주로 쓴다

 

 

 

(1) 전형적 Y:U:V 비율은 4:2:2로,, Y 4픽셀당 U, V는 2픽셀씩이라는 의미임.

ex> YUYV,YUYV,YUYV..

 

변환식은-

______________________________________________

Y = 0.3*R + 0.59*G + 0.11*B
U = (B-Y) x 0.493
V = (R-Y) x 0.877

..or..

Y = 0.299f * R + 0.587f * G + 0.114f * B;
U = -0.1687f * R - 0.3313f * G + 0.5f * B + 128;
V = 0.5f*R - 0.4187f*G - 0.0813f*B + 128; 

 

 

R = Y + 0.956*U + 0.621*V
G = Y + 0.272*U + 0.647*V
B = Y + 1.1061*U + 1.703*V

 

R = 1.00000*Y + 1.40200*V;
G = 1.00000*Y - 0.34414*U - 0.71414*V;
B = 1.00000*Y + 1.77200*U;

R = 1.164*(Y - 16.0) + 1.596*(V - 128.0);
G = 1.164*(Y - 16.0) - 0.813*(V - 128.0) - 0.391*(U - 128.0);
B = 1.164*(Y - 16.0) + 2.018*(U - 128.0);
───────────────────────────────

...

 

 

(2) Y:U:V 비율이 4:2:0인 경우,, Y 4픽셀 당 U, V는 가로/세로 2픽셀당

1픽셀씩이라는 의미임.

ex> 4x4 이미지일 경우,,

 Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8 Y9 Y10 Y11 Y12 Y13 Y14 Y15 Y16  U1 U2 U3 U4 

  V1 V2 V3 V4..

 

 

(3) Y:U:V 4:1:1은 화상을 구성하는 화소를 4개씩 묶어서 각각의 휘도(Y)를 샘플링하고, 색차(U,V)는 4개의 화소의 평균값을 취한다.

그러므로 4개의 화소에 4개의 휘도( Y)와 각 1개씩의 색차(U,V)가 있으므로

전체 6개의 샘플이 된다

ex > U2 Y0 Y1 V2 Y2 Y3
 

 

(4) YUV444에서 YUV420으로 변환하는 경우,, UV의 4화소를 평균하여 1화소로

바꿔 줄여준다

bool Yuv4442Yuv420(BYTE*U444,BYTE*V444,BYTE *U,BYTE *V,int wid,int hei)
{
    int i, j;
    register int addr;
    register int pos0, pos1, pos2, pos3;
 
    addr = 0;
 
    for (i=0; i<hei; i+=2) for(j=0; j<wid; j+=2)
    {
        pos0 = i*wid + j;       pos1 = pos0 + 1;
        pos2 = pos0 + wid;      pos3 = pos2 + 1;

 

        //오른쪽 쉬프트 연산 2번

        U[addr] = (BYTE)MyClip(((int)

           U444[pos0]+(int)U444[pos1]+(int)U444[pos2]+(int)U444[pos3])>>2); 

        //즉 나누기 4 : 평균내기
        V[addr] = (BYTE)MyClip(((int)

           V444[pos0]+(int)V444[pos1]+(int)V444[pos2]+(int)V444[pos3])>>2);  
        addr++;
    }
    return  true;
}