というわけでRGB色空間とCIELAB色空間の相互変換。
流れとしては、RGB → リニアRGB → XYZ → CIELAB と地味にめんどくさい…。
double r; // 0以上1以下の値。 double g; double b; double lr = r <= 0.04045d ? r / 12.92d : Math.pow((r + 0.055d) / 1.055d, 2.4d); double lg = g <= 0.04045d ? g / 12.92d : Math.pow((g + 0.055d) / 1.055d, 2.4d); double lb = b <= 0.04045d ? b / 12.92d : Math.pow((b + 0.055d) / 1.055d, 2.4d); double x = 0.4124d * lr + 0.3576d * lg + 0.1805d * lb; double y = 0.2126d * lr + 0.7152d * lg + 0.0722d * lb; double z = 0.0193d * lr + 0.1192d * lg + 0.9505d * lb; double xn = x / 0.95047d; double yn = y / 1.00000d; double zn = z / 1.08883d; double fx = xn > FD ? Math.pow(xn, 1d / 3d) : FK * xn + FV; double fy = yn > FD ? Math.pow(yn, 1d / 3d) : FK * yn + FV; double fz = zn > FD ? Math.pow(zn, 1d / 3d) : FK * zn + FV; double l = 116d * fy - 16d; double a = 500d * (fx - fy); double b = 200d * (fy - fz);
double yn = (l + 16d) / 116d; double xn = yn + a / 500d; double zn = yn - b / 200d; double fxn = xn > TD ? Math.pow(xn, 3d) : TK * (xn + TV); double fyn = yn > TD ? Math.pow(yn, 3d) : TK * (yn + TV); double fzn = zn > TD ? Math.pow(zn, 3d) : TK * (zn + TV); double x = fxn * 0.95047d; double y = fyn * 1.00000d; double z = fzn * 1.08883d; double lr = 3.24062547732005470d * x - 1.53720797221031910d * y - 0.49862859869824794d * z; double lg = - 0.96893071472931970d * x + 1.87575606088524200d * y + 0.04151752384295397d * z; double lb = 0.05571012044551063d * x - 0.20402105059848677d * y + 1.05699594225438860d * z; double r = lr <= 0.0031308d ? lr * 12.92d : Math.pow(lr, 1d / 2.4d) * 1.055d - 0.055d; double g = lg <= 0.0031308d ? lg * 12.92d : Math.pow(lg, 1d / 2.4d) * 1.055d - 0.055d; double b = lb <= 0.0031308d ? lb * 12.92d : Math.pow(lb, 1d / 2.4d) * 1.055d - 0.055d;
http://en.wikipedia.org/wiki/SRGB
http://en.wikipedia.org/wiki/Illuminant_D65
http://en.wikipedia.org/wiki/Lab_color_space