1. 程式人生 > >視訊播放過程中關於顏色的轉換YUV2RGB

視訊播放過程中關於顏色的轉換YUV2RGB

視訊播放過程中,由於涉及到不同的色域和色彩描述,到底如何做才是最科學的了。

而且顏色的轉換涉及到播放效率問題,是播放器開發過程中非常重要的環節。

更好的理解顏色轉換需要對編碼和播放有較深入的理解才能保證其正確性。

1)輸入:Blu-ray節目源:其編碼採用的顏色空間是YUV420

2)輸出:顯示裝置:RGB PCLevel模式

目前由於藍光節目源的高碼流特性,現在節目源的顏色空間都是YUV420,我們解碼出NV12或YV12就能保證在解碼端不損失訊號精度。即可以理解為無損解碼。

如果我們解碼完成後,要對顏色進行各種後處理,可以在yuv空間下進行,也可以轉rgb空間進行,但無論在什麼空間一定要從uint轉到float下進行處理,避免精度丟失。

從yuv空間轉到rgb是有訊號丟失的,如果你在處理影象的過程中在yuv和rgb來回轉換就存在著每轉一次就損失一次精度問題。

現在的投影或電視為了相容pc,其都是預設pc level rgb模式即8bit的時候,灰階為【0,255】,而不是【16,235】

所以我們在輸出的時候,yuv轉rgb的時候注意轉換系數,即轉換矩陣。

廣播電視對與節目製作有特定的標準,yuv轉rgb,bt.601標清 bt.709高清1080P bt.2020高清4k,這些標準都是針對yuv來說,

每種標準對應的yuv轉rgb係數也是不同的。

我們大部分電視目前實際上都是sRGB空間的電視,即標準rgb空間的電視,即要求輸入內容為gamma2.2,灰階為0-255的rgb訊號,現在最新的電視開始支援hdr,hdr要求更高的顏色解析度,最低10bit/12bit/16bit,10bit描述的顏色0-1024,16bit:0-65535

下面給出yuv轉rgb矩陣生成函式:

該轉換實際為yuv轉rgb(tv level 16-235)在轉rgb pc level

/*
M : bit num 8bit 10bit 12bit 16bit
Z: RGB的zero點位置 正常的RGB是0,
S:RGB的跨度,對於8bit的RGB是255
*/
void get_matrix(int colorspace, int M, int Z, int S)
{
	float Kr = 0.2627f;
	float Kb = 0.0593f;

	switch (colorspace)
	{
	case CS_601:
		Kr = 0.299f;
		Kb = 0.114f;
		break;
	case CS_709:
		Kr = 0.2126f;
		Kb = 0.0722f;
		break;
	case CS_2020:
		Kr = 0.2627f;
		Kb = 0.0593f;
		break;
	default:;
	}

	float Kg = 1.0f - Kr - Kb;

	int R = 0;
	int G = 0;
	int B = 0;

	int L = Kr*R + Kb*B + Kg*G;

	int Y = pow(2, M - 8) * (219 * (L - Z) / S + 16) + 0.5;
	Y = (pow(2, M - 8) * 219 * Kr / S) *R + (pow(2, M - 8) * 219 * Kb / S)*B + (pow(2, M - 8) * 219 * Kg / S)*G - pow(2, M - 8) * (219 * Z / S - 16) + 0.5;

	//int U = clip3(0, pow(2, M) - 1, floor(pow(2, (M - 8)) * (112 * (B - L) / ((1 - Kb)*S) + 128) + 0.5));
	int U = pow(2, (M - 8)) * (112 * (B - L) / ((1 - Kb)*S) + 128) + 0.5;
	U = -(pow(2, (M - 8)) * 112 * Kr / ((1 - Kb)*S))*R - (pow(2, (M - 8)) * 112 * (Kb - 1) / ((1 - Kb)*S))*B - (pow(2, (M - 8)) * 112 * Kg / ((1 - Kb)*S))*G + pow(2, (M - 8)) * 128 + 0.5;

	//int	V = clip3(0, pow(2, M) - 1, floor(pow(2, (M - 8)) * (112 * (R - L) / ((1 - Kr)*S) + 128) + 0.5));
	int V = -(pow(2, (M - 8)) * 112 * (Kr - 1) / ((1 - Kr)*S))*R - (pow(2, (M - 8)) * 112 * Kb / ((1 - Kr)*S))*B - (pow(2, (M - 8)) * 112 * Kg / ((1 - Kr)*S))*G + pow(2, (M - 8)) * 128 + 0.5;

	float a[3][4] = {
		{ (pow(2, M - 8) * 219 * Kr / S) , (pow(2, M - 8) * 219 * Kg / S) , (pow(2, M - 8) * 219 * Kb / S) , -pow(2, M - 8) * (219 * Z / S - 16) + 0.5 },
		{ -(pow(2, (M - 8)) * 112 * Kr / ((1 - Kb)*S)) ,-(pow(2, (M - 8)) * 112 * Kg / ((1 - Kb)*S)) ,-(pow(2, (M - 8)) * 112 * (Kb - 1) / ((1 - Kb)*S)) , pow(2, (M - 8)) * 128 + 0.5 },
		{ -(pow(2, (M - 8)) * 112 * (Kr - 1) / ((1 - Kr)*S)) , -(pow(2, (M - 8)) * 112 * Kg / ((1 - Kr)*S)) , -(pow(2, (M - 8)) * 112 * Kb / ((1 - Kr)*S)) , pow(2, (M - 8)) * 128 + 0.5 }
	};

	//RGB係數
	_debugTrace("|%.6ff, %.6ff, %.6ff, %.6ff|\n", a[0][0], a[0][1], a[0][2], a[0][3]);
	_debugTrace("|%.6ff, %.6ff, %.6ff, %.6ff|\n", a[1][0], a[1][1], a[1][2], a[1][3]);
	_debugTrace("|%.6ff, %.6ff, %.6ff, %.6ff|\n", a[2][0], a[2][1], a[2][2], a[2][3]);

	//YUV係數
	float D = a[0][0] * a[1][1] * a[2][2] + a[0][1] * a[1][2] * a[2][0] + a[0][2] * a[1][0] * a[2][1] - a[0][0] * a[1][2] * a[2][1] - a[0][1] * a[1][0] * a[2][2] - a[0][2] * a[1][1] * a[2][0];
	//float b[3] = {
	//	Y - a[0][3],
	//	U - a[1][3],
	//	V - a[2][3]
	//};
	float D1 = (Y - a[0][3]) * a[1][1] * a[2][2] +
		a[0][1] * a[1][2] * (V - a[2][3]) +
		a[0][2] * (U - a[1][3]) * a[2][1] -
		(Y - a[0][3]) * a[1][2] * a[2][1] -
		a[0][1] * (U - a[1][3]) * a[2][2] -
		a[0][2] * a[1][1] * (V - a[2][3]);

	D1 = a[1][1] * a[2][2] * Y - a[1][1] * a[2][2] * a[0][3] +
		a[0][1] * a[1][2] * V - a[0][1] * a[1][2] * a[2][3] +
		a[0][2] * a[2][1] * U - a[0][2] * a[1][3] * a[2][1] -
		a[1][2] * a[2][1] * Y + a[1][2] * a[2][1] * a[0][3] -
		a[0][1] * a[2][2] * U + a[0][1] * a[1][3] * a[2][2] -
		a[0][2] * a[1][1] * V + a[0][2] * a[1][1] * a[2][3];
	D1 = Y*(a[1][1] * a[2][2] - a[1][2] * a[2][1]) +
		U*(a[0][2] * a[2][1] - a[0][1] * a[2][2]) +
		V*(a[0][1] * a[1][2] - a[0][2] * a[1][1]) +
		(-a[1][1] * a[2][2] * a[0][3] - a[0][1] * a[1][2] * a[2][3] - a[0][2] * a[1][3] * a[2][1] + a[1][2] * a[2][1] * a[0][3] + a[0][1] * a[1][3] * a[2][2] + a[0][2] * a[1][1] * a[2][3]);

	float D2 = a[0][0] * (U - a[1][3]) * a[2][2] +
		(Y - a[0][3]) * a[1][2] * a[2][0] +
		a[0][2] * a[1][0] * (V - a[2][3]) -
		a[0][0] * a[1][2] * (V - a[2][3]) -
		(Y - a[0][3]) * a[1][0] * a[2][2] -
		a[0][2] * (U - a[1][3]) * a[2][0];

	D2 = Y*(a[1][2] * a[2][0] - a[1][0] * a[2][2]) +
		U*(a[0][0] * a[2][2] - a[0][2] * a[2][0]) +
		V*(a[0][2] * a[1][0] - a[0][0] * a[1][2]) +
		(a[0][0] * (-a[1][3])* a[2][2]) - a[0][3] * a[1][2] * a[2][0] - a[0][2] * a[1][0] * a[2][3] + a[0][0] * a[1][2] * a[2][3] + a[0][3] * a[1][0] * a[2][2] + a[0][2] * a[1][3] * a[2][0];


	float D3 = a[0][0] * a[1][1] * (V - a[2][3]) +
		a[0][1] * (U - a[1][3]) * a[2][0] +
		(Y - a[0][3]) * a[1][0] * a[2][1] -
		a[0][0] * (U - a[1][3]) * a[2][1] -
		a[0][1] * a[1][0] * (V - a[2][3]) -
		(Y - a[0][3]) * a[1][1] * a[2][0];

	D3 = Y*(a[1][0] * a[2][1] - a[1][1] * a[2][0]) +
		U*(a[0][1] * a[2][0] - a[0][0] * a[2][1]) +
		V*(a[0][0] * a[1][1] - a[0][1] * a[1][0]) +
		a[0][0] * a[1][1] * (-a[2][3]) + a[0][1] * (-a[1][3]) * a[2][0] + (-a[0][3]) * a[1][0] * a[2][1] - a[0][0] * (-a[1][3]) * a[2][1] - a[0][1] * a[1][0] * (-a[2][3]) - (-a[0][3]) * a[1][1] * a[2][0];

	R = D1 / D;
	G = D2 / D;
	B = D3 / D;

	float b[3][4] = {
		{ (a[1][1] * a[2][2] - a[1][2] * a[2][1]) / D, (a[0][2] * a[2][1] - a[0][1] * a[2][2]) / D, (a[0][1] * a[1][2] - a[0][2] * a[1][1]) / D, ((-a[1][1] * a[2][2] * a[0][3] - a[0][1] * a[1][2] * a[2][3] - a[0][2] * a[1][3] * a[2][1] + a[1][2] * a[2][1] * a[0][3] + a[0][1] * a[1][3] * a[2][2] + a[0][2] * a[1][1] * a[2][3])) / D },
		{ (a[1][2] * a[2][0] - a[1][0] * a[2][2]) / D, (a[0][0] * a[2][2] - a[0][2] * a[2][0]) / D, (a[0][2] * a[1][0] - a[0][0] * a[1][2]) / D, ((a[0][0] * (-a[1][3])* a[2][2]) - a[0][3] * a[1][2] * a[2][0] - a[0][2] * a[1][0] * a[2][3] + a[0][0] * a[1][2] * a[2][3] + a[0][3] * a[1][0] * a[2][2] + a[0][2] * a[1][3] * a[2][0]) / D },
		{ (a[1][0] * a[2][1] - a[1][1] * a[2][0]) / D, (a[0][1] * a[2][0] - a[0][0] * a[2][1]) / D, (a[0][0] * a[1][1] - a[0][1] * a[1][0]) / D,(a[0][0] * a[1][1] * (-a[2][3]) + a[0][1] * (-a[1][3]) * a[2][0] + (-a[0][3]) * a[1][0] * a[2][1] - a[0][0] * (-a[1][3]) * a[2][1] - a[0][1] * a[1][0] * (-a[2][3]) - (-a[0][3]) * a[1][1] * a[2][0]) / D }
	};

	//RGB係數
	_debugTrace("YUV coef matrix :\n");
	_debugTrace("|%.6ff, %.6ff, %.6ff, %.6ff|\n", b[0][0], b[0][1], b[0][2], b[0][3] / 255);
	_debugTrace("|%.6ff, %.6ff, %.6ff, %.6ff|\n", b[1][0], b[1][1], b[1][2], b[1][3] / 255);
	_debugTrace("|%.6ff, %.6ff, %.6ff, %.6ff|\n", b[2][0], b[2][1], b[2][2], b[2][3] / 255);

	/*
	|1.164384, -0.000000, 1.792741, -249.579559|
	|1.164383, -0.213249, -0.532909, 76.668961|
	|1.164383, 2.112402, -0.000000, -290.655945|
	*/

	Y = 82;
	U = 90;
	V = 240;

	R = 1.164384*Y + 1.792741*V - 249.579559;
	G = 1.164384*Y - 0.213249 *U - 0.532909*V + 76.668961;
	B = 1.164384*Y + 2.112402*U - 290.655945;

	_debugTrace("R = %d G = %d B = %d\n", R, G, B);
}