視訊播放過程中,由于涉及到不同的色域和色彩描述,到底如何做才是最科學的了。
而且顔色的轉換涉及到播放效率問題,是播放器開發過程中非常重要的環節。
更好的了解顔色轉換需要對編碼和播放有較深入的了解才能保證其正确性。
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);
}