Java:如何将RGB颜色转换为CIE Lab

如何在CIE Lab颜色模型中显示对象颜色。

Color c = ... float[] lab = {0,0,0}; ... c.getColorComponents(ColorSpace.getInstance(???), lab); 

但是我无法用CIE Lab强制这项工作(尽管TYPE_Lab是在ColorSpace类中呈现的)

请注意。

这是我的实现:

 import java.awt.color.ColorSpace; public class CIELab extends ColorSpace { public static CIELab getInstance() { return Holder.INSTANCE; } @Override public float[] fromCIEXYZ(float[] colorvalue) { double l = f(colorvalue[1]); double L = 116.0 * l - 16.0; double a = 500.0 * (f(colorvalue[0]) - l); double b = 200.0 * (l - f(colorvalue[2])); return new float[] {(float) L, (float) a, (float) b}; } @Override public float[] fromRGB(float[] rgbvalue) { float[] xyz = CIEXYZ.fromRGB(rgbvalue); return fromCIEXYZ(xyz); } @Override public float getMaxValue(int component) { return 128f; } @Override public float getMinValue(int component) { return (component == 0)? 0f: -128f; } @Override public String getName(int idx) { return String.valueOf("Lab".charAt(idx)); } @Override public float[] toCIEXYZ(float[] colorvalue) { double i = (colorvalue[0] + 16.0) * (1.0 / 116.0); double X = fInv(i + colorvalue[1] * (1.0 / 500.0)); double Y = fInv(i); double Z = fInv(i - colorvalue[2] * (1.0 / 200.0)); return new float[] {(float) X, (float) Y, (float) Z}; } @Override public float[] toRGB(float[] colorvalue) { float[] xyz = toCIEXYZ(colorvalue); return CIEXYZ.toRGB(xyz); } CIELab() { super(ColorSpace.TYPE_Lab, 3); } private static double f(double x) { if (x > 216.0 / 24389.0) { return Math.cbrt(x); } else { return (841.0 / 108.0) * x + N; } } private static double fInv(double x) { if (x > 6.0 / 29.0) { return x*x*x; } else { return (108.0 / 841.0) * (x - N); } } private Object readResolve() { return getInstance(); } private static class Holder { static final CIELab INSTANCE = new CIELab(); } private static final long serialVersionUID = 5027741380892134289L; private static final ColorSpace CIEXYZ = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); private static final double N = 4.0 / 29.0; } 

我在@finw的答案中使用代码时遇到了一些问题。 我相信它们主要是因为要进行CIELab转换,你应该指定一个光源:

http://en.wikipedia.org/wiki/Standard_illuminant

其中一个流行的标准是D50 ,它基本上只是标准的日光。 因为@ finw的代码没有照明校正,所以应该是中性灰色的颜色会略微着色。 检查这种方法的一种方法是尝试:

  float[] g = { 50.0f, 0f, 0f }; CIELab.getInstance().toRGB(g); for (float f : g) System.out.println(f); 

您应该在所有三个通道上获得大致相同的数字,但最终会得到明显(尽管略微)蓝色的RGB配置文件。 我确信有可能在@ finw的代码中纠正这个问题,但经过一段时间的游戏和搜索后,我发现了一些优秀的转换代码:

http://www.f4.fhtw-berlin.de/~barthel/ImageJ/ColorInspector//HTMLHelp/farbraumJava.htm

为了完整,这里是。

 public void rgb2lab(int R, int G, int B, int[] lab) { //http://www.brucelindbloom.com float r, g, b, X, Y, Z, fx, fy, fz, xr, yr, zr; float Ls, as, bs; float eps = 216.f/24389.f; float k = 24389.f/27.f; float Xr = 0.964221f; // reference white D50 float Yr = 1.0f; float Zr = 0.825211f; // RGB to XYZ r = R/255.f; //R 0..1 g = G/255.f; //G 0..1 b = B/255.f; //B 0..1 // assuming sRGB (D65) if (r <= 0.04045) r = r/12; else r = (float) Math.pow((r+0.055)/1.055,2.4); if (g <= 0.04045) g = g/12; else g = (float) Math.pow((g+0.055)/1.055,2.4); if (b <= 0.04045) b = b/12; else b = (float) Math.pow((b+0.055)/1.055,2.4); X = 0.436052025f*r + 0.385081593f*g + 0.143087414f *b; Y = 0.222491598f*r + 0.71688606f *g + 0.060621486f *b; Z = 0.013929122f*r + 0.097097002f*g + 0.71418547f *b; // XYZ to Lab xr = X/Xr; yr = Y/Yr; zr = Z/Zr; if ( xr > eps ) fx = (float) Math.pow(xr, 1/3.); else fx = (float) ((k * xr + 16.) / 116.); if ( yr > eps ) fy = (float) Math.pow(yr, 1/3.); else fy = (float) ((k * yr + 16.) / 116.); if ( zr > eps ) fz = (float) Math.pow(zr, 1/3.); else fz = (float) ((k * zr + 16.) / 116); Ls = ( 116 * fy ) - 16; as = 500*(fx-fy); bs = 200*(fy-fz); lab[0] = (int) (2.55*Ls + .5); lab[1] = (int) (as + .5); lab[2] = (int) (bs + .5); } 

在我的测试中,它产生适当无色度的灰度值,并且启动速度更快。

有一个TYPE_Lab ,但没有相应的CS_Lab 。 您将需要扩展ColorSpace并覆盖抽象方法以在XYZ,RGB和Lab之间进行转换。 可以在Lab色彩空间(维基百科)中找到所需的转换。

CIELAB似乎只受当前Java库中的name支持 – 如果查看java.awt.color.Colorspace的源代码,您将看到只支持少数几个命名的颜色空间。

我使用了这段代码并且它有效:

 public double[] rgbToLab(int R, int G, int B) { double r, g, b, X, Y, Z, xr, yr, zr; // D65/2° double Xr = 95.047; double Yr = 100.0; double Zr = 108.883; // --------- RGB to XYZ ---------// r = R/255.0; g = G/255.0; b = B/255.0; if (r > 0.04045) r = Math.pow((r+0.055)/1.055,2.4); else r = r/12.92; if (g > 0.04045) g = Math.pow((g+0.055)/1.055,2.4); else g = g/12.92; if (b > 0.04045) b = Math.pow((b+0.055)/1.055,2.4); else b = b/12.92 ; r*=100; g*=100; b*=100; X = 0.4124*r + 0.3576*g + 0.1805*b; Y = 0.2126*r + 0.7152*g + 0.0722*b; Z = 0.0193*r + 0.1192*g + 0.9505*b; // --------- XYZ to Lab --------- // xr = X/Xr; yr = Y/Yr; zr = Z/Zr; if ( xr > 0.008856 ) xr = (float) Math.pow(xr, 1/3.); else xr = (float) ((7.787 * xr) + 16 / 116.0); if ( yr > 0.008856 ) yr = (float) Math.pow(yr, 1/3.); else yr = (float) ((7.787 * yr) + 16 / 116.0); if ( zr > 0.008856 ) zr = (float) Math.pow(zr, 1/3.); else zr = (float) ((7.787 * zr) + 16 / 116.0); double[] lab = new double[3]; lab[0] = (116*yr)-16; lab[1] = 500*(xr-yr); lab[2] = 200*(yr-zr); return lab; } 

对于上面的代码,我使用了这里提供的公式,以便从rgb转换为XYZ,然后从XYZ转换为CIELab。 我得到的结果与此在线转换器相同。