Y = 0.299 R + 0.587 G + 0.114 B
Cb = - 0.1687 R - 0.3313 G + 0.5 B + 128
Cr = 0.5 R - 0.4187 G - 0.0813 B + 128
反過來也可以:
R = Y + 1.402 (Cr-128)
G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
B = Y + 1.772 (Cb-128)
由於上述公式需要用到浮點計算,嚴重影響速度,因此需要進行計算優化
1、整形計算
u = YUVdata[UPOS] - 128;
v = YUVdata[VPOS] - 128;
rdif = v + ((v * 103) >> 8);
invgdif = ((u * 88) >> 8) +((v * 183) >> 8);
bdif = u +( (u*198) >> 8);
r = YUVdata[YPOS] + rdif;
g = YUVdata[YPOS] - invgdif;
b = YUVdata[YPOS] + bdif;
r g b值要保證在0~255之間
2、查表法
查表法首先可以想到的就是用查表替代上述整型算法中的乘法運算。
rdif = fac_1_4075[u];
invgdif = fac_m_0_3455[u] + fac_m_0_7169[v];
bdif = fac_1_779[u];
這裏一共需要4個1維數組,下標從0開始到255,表格共佔用約1K的內存空間。uv可以不需要做減128的操作了。在事先計算對應的數組元素的值的時候計算在內就好了。
對於每個像素,部分查表法用查表替代了2次減法運算和4次乘法運算,4次移位運算。但是,依然需要多次加法運算和6次比較運算和可能存在的賦值操作,相對第一種方法運算速度提高並不明顯。
3、完全查表法
那麼是否可以由YUV直接查表得到對應的RGB值呢?乍一看似乎不太可能,以最複雜的G的運算為例,因為G與YUV三者都相關,所以類似 G=YUV2G[Y][U][V]這樣的算法,一個三維下標尺寸都為256的數組就需要佔用2的24次方約16兆空間,絕對是沒法接受的。所以目前多數都是採用部分查表法。
但是,如果我們仔細分析就可以發現,對於G我們實際上完全沒有必要採用三維數組,因為Y只與UV運算的結果相關,與UV的個體無關,所以我們可以採用二次查表的方法將G的運算簡化為對兩個二維數組的查表操作,如下:
G = yig2g_table[ y ][ uv2ig_table[ u ][ v ] ];
而RB本身就只和YU或YV相關,所以這樣我們一共需要4個8*8的二維表格,需要佔用4乘2的16次方共256K內存。基本可以接受。但是對於手機這樣的嵌入式運用來説,還是略有些大了。
進一步分析,我們可以看到,因為在手機等嵌入式運用上我們最終是要把數據轉換成RGB565格式送到LCD屏上顯示的,所以,對於RGB三分量來説,我們根本不需要8bit這麼高的精度,為了簡單和運算的統一起見,對每個分量我們其實只需要高6bit的數據就足夠了,所以我們可以進一步把表格改為4個6*6的二維表格,這樣一共只需要佔用16K內存!在計算表格元素值的時候還可以把最終的溢出判斷也事先做完。最後的算法如下:
y = (YUVdata[Y1POS] >> 2);
u = (YUVdata[UPOS] >> 2);
v = (YUVdata[VPOS] >> 2);
r = yv2r_table[ y ][ v ];
g = yig2g_table[ y ][ uv2ig_table[ u ][ v ] ];
b = yu2b_table[ y ][ u ];
RGBdata[1] =( (r & 0xF8) | ( g >> 5) );
RGBdata[0] =( ((g & 0x1C) << 3) | ( b >> 3) );
這樣相對部分查表法,我們增加了3次移位運算,而進一步減少了4次加法運算和6次比較賦值操作。
在計算表格元素數值的時候,要考慮舍入和偏移等因數使得計算的中間結果滿足數組下標非負的要求,需要一定的技巧。