顏色空間系列程式碼下載連結:http://files.cnblogs.com/Imageshop/ImageInfo.rar (同文章同步更新)
YDbDr顏色空間和YCbCr顏色空間類似,其和RGB空間之間的相互轉換公式裡取http://en.wikipedia.org/wiki/YDbDr 所描述的。
RGB轉為YDbDr為:
(1)
對應的YDbDr轉換為RGB的公式為:
(2)
由式(1)可知Y的範圍是[0,255],Db的範圍是[-1.333*255,1.333*255],Dr的範圍亦為[-1.333*255,1.333*255]。
為了使Db,Dr的變換量程也為255-0大小,需要將上述Db/Dr壓縮1.333*2倍,即將各系數處理( 1.333*2),得到新的轉換:
[Y ] [0.2990 -0.1688 -0.5000 ] [R]
[Db] = [0.5870 -0.3312 0.4186 ] [G]
[Dr] [0.1140 0.5000 0.0814 ] [B]
對應的逆變換可用matlab求上述矩陣的逆陣即可:
[R] [ 1.000000000000000 0.000246081707249 -1.402083073344533 ] [Y]
[G] = [ 1.000000000000000 -0.344268308442098 0.714219609001458 ] [Db]
[B] [ 1.000000000000000 1.772034373903893 -0.000211153981059 ] [Dr]
理論上 YDbDr和RGB之間的轉換時完全無損可逆的。不過如果YDbDr採用byte型別表達會有一定的精度損失。
附上最終的程式碼供大家參考:
sealed unsafe class RGBYDbDr { //const float YDbDrYRF = 0.299F; // RGB轉YDbDr的係數(浮點型別) //const float YDbDrYGF = 0.587F; //const float YDbDrYBF = 0.114F; //const float YDbDrDbRF = -0.450F; //const float YDbDrDbGF = -0.883F; //const float YDbDrDbBF = 1.333F; //const float YDbDrDrRF = -1.333F; //const float YDbDrDrGF = 1.116F; //const float YDbDrDrBF = 0.217F; //const float RGBRYF = 1.00000F; // YDbDr轉RGB的係數(浮點型別) //const float RGBRDbF = 0.000092303716148F; //const float RGBRDrF = -0.525912630661865F; //const float RGBGYF = 1.00000F; //const float RGBGDbF = -0.129132898890509F; //const float RGBGDrF = 0.267899328207599F; //const float RGBBYF = 1.00000F; //const float RGBBDbF = 0.664679059978955F; //const float RGBBDrF = -0.000079202543533F; const float YDbDrYRF = 0.299F; // RGB轉YDbDr的係數(浮點型別) const float YDbDrYGF = 0.587F; const float YDbDrYBF = 0.114F; const float YDbDrDbRF = -0.1688F; const float YDbDrDbGF = -0.3312F; const float YDbDrDbBF = 0.5F; const float YDbDrDrRF = -0.5F; const float YDbDrDrGF = 0.4186F; const float YDbDrDrBF = 0.0814F; const float RGBRYF = 1.00000F; // YDbDr轉RGB的係數(浮點型別) const float RGBRDbF = 0.0002460817072494899F; const float RGBRDrF = -1.402083073344533F; const float RGBGYF = 1.00000F; const float RGBGDbF = -0.344268308442098F; const float RGBGDrF = 0.714219609001458F; const float RGBBYF = 1.00000F; const float RGBBDbF = 1.772034373903893F; const float RGBBDrF = 0.0002111539810593343F; const int Shift = 20; const int HalfShiftValue = 1 << (Shift - 1); const int YDbDrYRI = (int)(YDbDrYRF * (1 << Shift) + 0.5); // RGB轉YDbDr的係數(整數型別) const int YDbDrYGI = (int)(YDbDrYGF * (1 << Shift) + 0.5); const int YDbDrYBI = (int)(YDbDrYBF * (1 << Shift) + 0.5); const int YDbDrDbRI = (int)(YDbDrDbRF * (1 << Shift) + 0.5); const int YDbDrDbGI = (int)(YDbDrDbGF * (1 << Shift) + 0.5); const int YDbDrDbBI = (int)(YDbDrDbBF * (1 << Shift) + 0.5); const int YDbDrDrRI = (int)(YDbDrDrRF * (1 << Shift) + 0.5); const int YDbDrDrGI = (int)(YDbDrDrGF * (1 << Shift) + 0.5); const int YDbDrDrBI = (int)(YDbDrDrBF * (1 << Shift) + 0.5); const int RGBRYI = (int)(RGBRYF * (1 << Shift) + 0.5); // YDbDr轉RGB的係數(整數型別) const int RGBRDbI = (int)(RGBRDbF * (1 << Shift) + 0.5); const int RGBRDrI = (int)(RGBRDrF * (1 << Shift) + 0.5); const int RGBGYI = (int)(RGBGYF * (1 << Shift) + 0.5); const int RGBGDbI = (int)(RGBGDbF * (1 << Shift) + 0.5); const int RGBGDrI = (int)(RGBGDrF * (1 << Shift) + 0.5); const int RGBBYI = (int)(RGBBYF * (1 << Shift) + 0.5); const int RGBBDbI = (int)(RGBBDbF * (1 << Shift) + 0.5); const int RGBBDrI = (int)(RGBBDrF * (1 << Shift) + 0.5); public static void ToYDbDr(byte* From, byte* To, int Length = 1) { if (Length < 1) return; byte* End = From + Length * 3; int Red, Green, Blue; while (From != End) { Blue = *From; Green = *(From + 1); Red = *(From + 2); // 無需判斷是否存在溢位,因為測試過整個RGB空間的所有顏色值,無顏色存在溢位 *To = (byte)((YDbDrYRI * Red + YDbDrYGI * Green + YDbDrYBI * Blue + HalfShiftValue) >> Shift); // YDbDr和YUV的Y相同 *(To + 1) = (byte)(128 + ((YDbDrDbRI * Red + YDbDrDbGI * Green + YDbDrDbBI * Blue + HalfShiftValue) >> Shift)); *(To + 2) = (byte)(128 + ((YDbDrDrRI * Red + YDbDrDrGI * Green + YDbDrDrBI * Blue + HalfShiftValue) >> Shift)); From += 3; To += 3; } } public static void ToRGB(byte* From, byte* To, int Length = 1) { if (Length < 1) return; byte* End = From + Length * 3; int Red, Green, Blue; int Y, Db, Dr; while (From != End) { Y = *From; Db = *(From + 1) - 128; Dr = *(From + 2) - 128; Red = Y + ((RGBRDbI * Db + RGBRDrI * Dr + HalfShiftValue) >> Shift); Green = Y + ((RGBGDbI * Db + RGBGDrI * Dr + HalfShiftValue) >> Shift); Blue = Y + ((RGBBDbI * Db + RGBBDrI * Dr + HalfShiftValue) >> Shift); if (Red > 255) Red = 255; else if (Red < 0) Red = 0; if (Green > 255) Green = 255; else if (Green < 0) Green = 0; if (Blue > 255) Blue = 255; else if (Blue < 0) Blue = 0; *To = (byte)Blue; *(To + 1) = (byte)Green; *(To + 2) = (byte)Red; From += 3; To += 3; } } }
由於有些轉換系數很小,建議Shift 常數取值不得小於10,否則會有更多的損失。
照例附上一些效果:
原圖:
YDbDr綜合效果圖:
Y通道圖:
Db通道:
Dr通道: