您的位置:首页 > 其它

颜色空间系列4: RGB和YDbDr颜色空间的转换及优化算法

2017-12-25 21:09 615 查看
  颜色空间系列代码下载链接: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通道:
    


分类: [09] 图像颜色空间,[03]
图像算法优化
标签: RGBYDbDr颜色空间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: