1. 程式人生 > >YUV420與RGB24相互轉換c++純程式碼

YUV420與RGB24相互轉換c++純程式碼



一幀YUV420P畫素資料一共佔用w*h*3/2 Byte的資料。其中前w*h Byte儲存Y,接著的w*h*1/4 Byte儲存U,最後w*h*1/4 Byte儲存V

RGB到YUV的轉換公式:

Y= 0.299*R+0.587*G+0.114*B

U=-0.147*R-0.289*G+0.463*B

V= 0.615*R-0.515*G-0.100*B

在轉換的過程中有以下幾點需要注意:
1) RGB24儲存方式是Packed,YUV420P儲存方式是Packed。
2) U,V在水平和垂直方向的取樣數是Y的一半

RGB24_TO_YUV420程式碼源自雷神部落格。補充yuv420_to_rgb24.

bool RGB24_TO_YUV420(unsigned char *RgbBuf,int w,int h,unsigned char *yuvBuf)
{
	unsigned char*ptrY, *ptrU, *ptrV, *ptrRGB;
	memset(yuvBuf,0,w*h*3/2);
	ptrY = yuvBuf;
	ptrU = yuvBuf + w*h;
	ptrV = ptrU + (w*h*1/4);
	unsigned char y, u, v, r, g, b;
	for (int j = 0; j<h;j++){
		ptrRGB = RgbBuf + w*j*3 ;
		for (int i = 0;i<w;i++){
			
			r = *(ptrRGB++);
			g = *(ptrRGB++);
			b = *(ptrRGB++);
			y = (unsigned char)( ( 66 * r + 129 * g +  25 * b + 128) >> 8) + 16  ;          
			u = (unsigned char)( ( -38 * r -  74 * g + 112 * b + 128) >> 8) + 128 ;          
			v = (unsigned char)( ( 112 * r -  94 * g -  18 * b + 128) >> 8) + 128 ;
			*(ptrY++) = clip_value(y,0,255);
			if (j%2==0&&i%2 ==0){
				*(ptrU++) =clip_value(u,0,255);
			}
			else{
				if (i%2==0){
				*(ptrV++) =clip_value(v,0,255);
				}
			}
		}
	}
	return true;
}

與YUV420P三個分量分開儲存不同,RGB24格式的每個畫素的三個分量是連續儲存的。一幀寬高分別為w、h的RGB24影象一共佔用w*h*3 Byte的儲存空間。RGB24格式規定首先儲存第一個畫素的R、G、B,然後儲存第二個畫素的R、G、B…以此類推。類似於YUV420P的儲存方式稱為Planar方式,而類似於RGB24的儲存方式稱為Packed方式。

R = Y + 1.4075 *(V-128)
        G = Y – 0.3455 *(U –128) – 0.7169 *(V –128)
        B = Y + 1.779 *(U – 128)

bool yuv420ToRgb(char *yuv,int w,int h,char *rgb)
{
    unsigned char *pBufy = new unsigned char[w*h];
    unsigned char *pBufu = new unsigned char[w*h/4];
    unsigned char *pBufv = new unsigned char[w*h/4];

    memcpy(pBufy,yuv,w*h);
    memcpy(pBufu,yuv+w*h,w*h/4);
    memcpy(pBufv,yuv+w*h*5/4,w*h/4);

    for(int i = 0; i<w*h/4;i++)
    {
        rgb[i*3+2] = pBufy[i]+1.772*(pBufu[i]-128);  //B = Y +1.779*(U-128)
        rgb[i*3+1] = pBufy[i]-0.34413*(pBufu[i]-128)-0.71414*(pBufv[i]-128);//G = Y-0.3455*(U-128)-0.7169*(V-128)
        rgb[i*3+0] = pBufy[i]+1.402*(pBufv[i]-128);//R = Y+1.4075*(V-128)
    }
    free(pBufy);
    free(pBufu);
    free(pBufv);
    return true;
}

親測,兩份程式碼可用。如有問題,歡迎指正。共同學習,共同進步。

資料源自網路。