这是两个函数,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);
}
======================================================