YUV與RGB的相互轉(zhuǎn)換一直以來(lái)都是非常常用的基礎(chǔ)算法,如何才能最高效的轉(zhuǎn)換,成為一個(gè)難點(diǎn)問(wèn)題,尤其是目前視頻直播火熱的時(shí)候,這些算法的優(yōu)化也越發(fā)重要。 首先,我們看下最常用的YUV與RGB相互轉(zhuǎn)換的算法公式,如下所示: 注意,RGB取值范圍均為0-255: 1,RGB轉(zhuǎn)YUV Y = 0.299R + 0.587G + 0.114B U = -0.147R - 0.289G + 0.436B V = 0.615R - 0.515G - 0.100B 2,YUV轉(zhuǎn)RGB R = Y + 1.14V G = Y - 0.39U - 0.58V B = Y + 2.03U 我的優(yōu)化方案如下: 優(yōu)化1:看到上述算法,從算法優(yōu)化角度來(lái)看,算法計(jì)算中,最好不要出現(xiàn)浮點(diǎn)運(yùn)算,浮點(diǎn)運(yùn)算比較耗時(shí); 基于這一點(diǎn),我們做如下操作: Y * 256 = 0.299 * 256R + 0.587 * 256G + 0.114 * 256B U * 256 = -0.147 * 256R - 0.289 * 256G + 0.436 * 256B V * 256 = 0.615 * 256R - 0.515 * 256G - 0.100 * 256B R * 256 = Y * 256 + 1.14 * 256V G * 256 = Y * 256 - 0.39 * 256U - 0.58 * 256V B * 256 = Y * 256 + 2.03 * 256U 簡(jiǎn)化上面的公式如下: 256Y = 76.544R + 150.272G + 29.184B 256U = -37.632R - 73.984G + 111.616B 256V = 157.44R - 131.84G - 25.6B 256R = 256Y + 291.84V 256G = 256Y - 99.84U - 148.48V 256B = 256Y + 519.68U 做到這一步,我這里要說(shuō)明一下:我們這里的轉(zhuǎn)換是有損的,適用于追求速度,而對(duì)效果要求不是100%準(zhǔn)確的情況。 然后,我們就可以對(duì)上述公式進(jìn)一步優(yōu)化,徹底干掉小數(shù): 256Y = 77R + 150G + 29B 256U = -38R - 74G + 112B 256V = 158R - 132G - 26B 256R = 256Y + 292V 256G = 256Y - 100U - 149V 256B = 256Y + 520U 實(shí)際上就是四舍五入,為什么要乘以256,這是實(shí)際上是為了縮小誤差,當(dāng)然你這個(gè)地方乘數(shù)越大,誤差越小。 優(yōu)化2:干掉所有乘法,用移位運(yùn)算表示; 上述公式,我們可以用移位進(jìn)行簡(jiǎn)單優(yōu)化: Y = (77R + 150G + 29B) >> 8 U = (-38R - 74G + 112B) >> 8 V = (158R - 132G - 26B) >> 8 R = (256Y + 292V) >> 8 G = (256Y - 100U - 149V) >> 8 B = (256Y + 520U) >> 8 做到此處,已經(jīng)沒(méi)有了浮點(diǎn)運(yùn)算量了,但是我們發(fā)現(xiàn)雖然采用了移位運(yùn)算,但是,公式中還有很多乘法運(yùn)算,乘法跟移位運(yùn)算相比,還是效率太低了,因此,我們將把所有乘法都改成移位運(yùn)算。 如何將常數(shù)乘法改成移位運(yùn)算? 這里給個(gè)例子: Y=Y*9可以改為:Y=(Y<<3)+Y 因此,我們可以講YUV的公式繼續(xù)改為最簡(jiǎn): RGB轉(zhuǎn)YUV: Y = ((R << 6) + (R << 3) + (R << 2) + R + (G << 7) + (G << 4) + (G << 2) + (G << 1) + (B << 4) + (B << 3) + (B << 2) + B) >> 8; U = (-((R << 5) + (R << 2) + (R << 1)) - ((G << 6) + (G << 3) + (G << 1)) + ((B << 6) + (B << 5) + (B << 4))) >> 8; V = ((R << 7) + (R << 4) + (R << 3) + (R << 2) + (R << 1) - ((G << 7) + (G << 2)) - ((B << 4) + (B << 3) + (B << 1))) >> 8; YUV轉(zhuǎn)RGB: R = ((Y << 8) + ((V << 8) + (V << 5) + (V << 2))) >> 8; G = ((Y << 8) - ((U << 6) + (U << 5) + (U << 2)) - ((V << 7) + (V << 4) + (V << 2) + V)) >> 8; B = ((Y << 8) + (U << 9) + (U << 3)) >> 8; 至此,YUV與RGB的相互轉(zhuǎn)換公式就優(yōu)化完畢了,這個(gè)優(yōu)化,在移動(dòng)端,速度會(huì)有很大的提高,至于一些測(cè)試數(shù)據(jù),我就不列舉了,只給個(gè)效果圖吧,大家可以直接試一下就知道了,最后,給出C的代碼如下: static void RGBToYUV(int Red, int Green, int Blue, int* Y,int* U,int* V) { *Y = ((Red << 6) + (Red << 3) + (Red << 2) + Red + (Green << 7) + (Green << 4) + (Green << 2) + (Green << 1) + (Blue << 4) + (Blue << 3) + (Blue << 2) + Blue) >> 8; *U = (-((Red << 5) + (Red << 2) + (Red << 1)) - ((Green << 6) + (Green << 3) + (Green << 1)) + ((Blue << 6) + (Blue << 5) + (Blue << 4))) >> 8; *V = ((Red << 7) + (Red << 4) + (Red << 3) + (Red << 2) + (Red << 1) - ((Green << 7) + (Green << 2)) - ((Blue << 4) + (Blue << 3) + (Blue << 1))) >> 8; }; static void YUVToRGB(int Y, int U, int V, int* Red, int* Green, int* Blue) { *Red = ((Y << 8) + ((V << 8) + (V << 5) + (V << 2))) >> 8; *Green = ((Y << 8) - ((U << 6) + (U << 5) + (U << 2)) - ((V << 7) + (V << 4) + (V << 2) + V)) >> 8; *Blue = ((Y << 8) + (U << 9) + (U << 3)) >> 8; }; 效果圖: 原圖 使用浮點(diǎn)型RGB-YUV-RGB結(jié)果圖 使用優(yōu)化版RGB-YUV-RGB結(jié)果圖 在說(shuō)一下,這個(gè)優(yōu)化純粹是追求速度,當(dāng)然,效果差異很小,如果你需要的是100%的準(zhǔn)確,最好還是要使用浮點(diǎn)計(jì)算。 |
|
來(lái)自: taotao_2016 > 《計(jì)算機(jī)》