RGB色彩變換到Lab空間代碼

這是兩個函數,CIE標準的變換;和Adobe的不一樣

Step1:
XYZ to RGB (採用 D65 白點):

   [ R ]   [  3.240479 -1.537150 -0.498535 ]   [ X ]
   [ G ] = [ -0.969256  1.875992  0.041556 ] * [ Y ]
   [ B ]   [  0.055648 -0.204043  1.057311 ]   [ Z ].

    R, G, B 在 [0,1]. 

逆變換:

   [ X ]   [  0.412453  0.357580  0.180423 ]   [ R ] 
   [ Y ] = [  0.212671  0.715160  0.072169 ] * [ G ]
   [ Z ]   [  0.019334  0.119193  0.950227 ]   [ B ]

Step2:
XYZ to CIE L*a*b* (CIELAB) & CIELAB to XYZ

L* = 116 * (Y/Yn)1/3 - 16    若 Y/Yn > 0.008856
L* = 903.3 * Y/Yn            其他

a* = 500 * ( f(X/Xn) - f(Y/Yn) )
b* = 200 * ( f(Y/Yn) - f(Z/Zn) )
    其中 f(t) = t1/3                 若 t > 0.008856
         f(t) = 7.787 * t + 16/116   其他

其中Xn, Yn 和 Zn是參考白的三刺激值。

逆變換( Y/Yn > 0.008856) :

X = Xn * ( P + a* / 500 ) 3
Y = Yn * P 3
Z = Zn * ( P - b* / 200 ) 3
    其中 P = (L* + 16) / 116
====================================================================

這是我的代碼:按照CIE走的,出來的結果和大家常用的PhotoShop的是不一樣的;

不過有一種算法的計算結果很逼近photoshop的,再整理出來吧;


double BLACK = 20;
double YELLOW = 70;
void RGB2Lab(double R, double G, double B, double &L, double &a, double &b)
{
 double X, Y, Z, fX, fY, fZ;
 
    X = 0.412453*R + 0.357580*G + 0.180423*B;
    Y = 0.212671*R + 0.715160*G + 0.072169*B;
    Z = 0.019334*R + 0.119193*G + 0.950227*B;
    
    X /= (255 * 0.950456);
    Y /=  255;
    Z /= (255 * 1.088754);
    
    if (Y > 0.008856)
    {
     fY = pow(Y, 1.0/3.0);
     L = 116.0*fY - 16.0;
    }
    else
    {
     fY = 7.787*Y + 16.0/116.0;
     L = 903.3*Y;
    }
    
    if (X > 0.008856)
     fX = pow(X, 1.0/3.0);
    else
     fX = 7.787*X + 16.0/116.0;
    
    if (Z > 0.008856)
     fZ = pow(Z, 1.0/3.0);
    else
     fZ = 7.787*Z + 16.0/116.0;
    
    a = 500.0*(fX - fY);
    b = 200.0*(fY - fZ);
    
    if (L < BLACK) 
    {
     a *= exp((L - BLACK) / (BLACK / 4));
     b *= exp((L - BLACK) / (BLACK / 4));
     L = BLACK;
    }
    if (b > YELLOW)
     b = YELLOW;
    

}


void Lab2RGB(double L, double a, double b, double &R, double &G, double &B)
{
 double X, Y, Z, fX, fY, fZ;
 double RR, GG, BB;

    fY = pow((L + 16.0) / 116.0, 3.0);
    if (fY < 0.008856)
     fY = L / 903.3;
    Y = fY;
    
    if (fY > 0.008856)
     fY = pow(fY, 1.0/3.0);
    else
     fY = 7.787 * fY + 16.0/116.0;
    
    fX = a / 500.0 + fY;      
    if (fX > 0.206893)
     X = pow(fX, 3.0);
    else
     X = (fX - 16.0/116.0) / 7.787;
    
    fZ = fY - b /200.0;      
    if (fZ > 0.206893)
     Z = pow(fZ, 3.0);
    else
     Z = (fZ - 16.0/116.0) / 7.787;
    
    X *= (0.950456 * 255);
    Y *=             255;
    Z *= (1.088754 * 255);
    
    RR =  3.240479*X - 1.537150*Y - 0.498535*Z;
    GG = -0.969256*X + 1.875992*Y + 0.041556*Z;
    BB =  0.055648*X - 0.204043*Y + 1.057311*Z;
    
    R = (float)(RR < 0 ? 0 : RR > 255 ? 255 : RR);
    G = (float)(GG < 0 ? 0 : GG > 255 ? 255 : GG);
    B = (float)(BB < 0 ? 0 : BB > 255 ? 255 : BB);
}

======================================================

下面是我找到的一個代碼,還沒仔細看,是從一個讀取Adobe PSD文件的類裏面找到的;

原址在這裏http://www.codeproject.com/bitmap/MyPSD.asp

我試了一下,與Adobe的還是不一樣

void CPSD::LabToRGB(const int L, const int a, const int b, int &R, int &G, int &B )
{
 // For the conversion we first convert values to XYZ and then to RGB
 // Standards used Observer = 2, Illuminant = D65
 // ref_X = 95.047, ref_Y = 100.000, ref_Z = 108.883
 const double ref_X = 95.047;
 const double ref_Y = 100.000;
 const double ref_Z = 108.883;

 double var_Y = ( (double)L + 16.0 ) / 116.0;
 double var_X = (double)a / 500.0 + var_Y;
 double var_Z = var_Y - (double)b / 200.0;

 if ( pow(var_Y, 3) > 0.008856 )
  var_Y = pow(var_Y, 3);
 else
  var_Y = ( var_Y - 16 / 116 ) / 7.787;

 if ( pow(var_X, 3) > 0.008856 )
  var_X = pow(var_X, 3);
 else
  var_X = ( var_X - 16 / 116 ) / 7.787;

 if ( pow(var_Z, 3) > 0.008856 )
  var_Z = pow(var_Z, 3);
 else
  var_Z = ( var_Z - 16 / 116 ) / 7.787;

 double X = ref_X * var_X;
 double Y = ref_Y * var_Y;
 double Z = ref_Z * var_Z;

 XYZToRGB(X, Y, Z, R, G, B);
};

void CPSD::XYZToRGB(const double X, const double Y, const double Z, int &R, int &G, int &B)
{
 // Standards used Observer = 2, Illuminant = D65
 // ref_X = 95.047, ref_Y = 100.000, ref_Z = 108.883
 const double ref_X = 95.047;
 const double ref_Y = 100.000;
 const double ref_Z = 108.883;

 double var_X = X / 100.0;
 double var_Y = Y / 100.0;
 double var_Z = Z / 100.0;

 double var_R = var_X * 3.2406 + var_Y * (-1.5372) + var_Z * (-0.4986);
 double var_G = var_X * (-0.9689) + var_Y * 1.8758 + var_Z * 0.0415;
 double var_B = var_X * 0.0557 + var_Y * (-0.2040) + var_Z * 1.0570;

 if ( var_R > 0.0031308 )
  var_R = 1.055 * ( pow(var_R, 1/2.4) ) - 0.055;
 else
  var_R = 12.92 * var_R;

 if ( var_G > 0.0031308 )
  var_G = 1.055 * ( pow(var_G, 1/2.4) ) - 0.055;
 else
  var_G = 12.92 * var_G;

 if ( var_B > 0.0031308 )
  var_B = 1.055 * ( pow(var_B, 1/2.4) )- 0.055;
 else
  var_B = 12.92 * var_B;

 R = (int)(var_R * 256.0);
 G = (int)(var_G * 256.0);
 B = (int)(var_B * 256.0);
};

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章