Re: RGB to L*a*b* conversion

Posted by Vladimir Hegyi on
URL: http://imagej.273.s1.nabble.com/RGB-to-L-a-b-Conversion-tp3703729p3703735.html

Hi Duane,
I tried to compile attached java code but without the success.
Would you be so kind to help me again?
Thanks.
Vlado

----- Original Message -----
From: "Duane & Julie" <[hidden email]>
To: <[hidden email]>
Sent: Saturday, February 11, 2006 11:44 PM
Subject: Re: RGB to L*a*b* conversion


> Hi all,
>
> My previous post was rejected, because I had an attached java source  
> file (!?).  This is the repost, with code in line.
> ----
>
> RGB is an uncalibrated space, L*a*b* is a calibrated space.  That  
> said, if you assume the RGB to really be sRGB you can do a conversion  
> that is probably what you want, or close to it.
>
> I wrote a color space converter, which I have attached.  The code  
> converts one pixel.  To convert an image, visit each pixel and set  
> each channel to the output.  As an example, if you want to convert to  
> L*a*b* from RGB you notice that the R is in the first channel, the G  
> in the second and the B in the third.  Simply set the first channel  
> to L*, the second to a* and the third to b*.  Writing a plugin to  
> convert an entire image is straightforward.
>
> Hope that helps!
>
>    duane
>
> ----
> /*
>  * ColorSpaceConverter.java
>  * Created on Jan 15, 2004
>  *
>  */
> package mil.nawcwd.isp;
>
> import java.text.DecimalFormat;
>
> /**
>  * ColorSpaceConverter
>  * @author dvs
>  * Created Jan 15, 2004
>  */
> public class ColorSpaceConverter {
>
>   /**
>    * reference white in XYZ coordinates
>    */
>   public static double[]   D65 = {95.047, 100.0, 108.883};
>
>   /**
>    * sRGB to XYZ conversion matrix
>    */
>   public static double[][] M   = {{0.412424, 0.212656,  0.0193324},
>                                   {0.357579, 0.715158,  0.119193 },
>                                   {0.180464, 0.0721856, 0.950444 }};
>
>   /**
>    * XYZ to sRGB conversion matrix
>    */
>   public static double[][] Mi  = {{3.24071,  -0.969258,  0.0556352},
>                                   {-1.53726,  1.87599,  -0.203996 },
>                                   {-0.498571, 0.0415557, 1.05707  }};
>
>   /**
>    * Main method for testing.
>    * @param args
>    * ColorSpaceConverter [-rgb R G B | -xyz X Y Z | -lab L a b]
>    */
>   public static void main(String[] args) {
>
>     // local variables
>     ColorSpaceConverter csc = new ColorSpaceConverter();
>     int R = 0, G = 0, B = 0;
>     double X = 0, Y = 0, Z = 0;
>     double L = 0, a = 0, b = 0;
>     double[] rf;
>     int[] ri;
>
>     DecimalFormat dfi = new DecimalFormat(" ##0;-##0");
>     DecimalFormat dfd = new DecimalFormat(" #0.000;-#0.000");
>
>     // for each argument
>     for (int i = 0; i < args.length; i++) {
>       try {
>         if (args[i].equalsIgnoreCase("-rgb")) {
>           i++;
>           R = new Integer(args[i]).intValue();
>           i++;
>           G = new Integer(args[i]).intValue();
>           i++;
>           B = new Integer(args[i]).intValue();
>           rf = csc.RGBtoXYZ(R, G, B);
>           X = rf[0];
>           Y = rf[1];
>           Z = rf[2];
>           rf = csc.XYZtoLAB(X, Y, Z);
>           L = rf[0];
>           a = rf[1];
>           b = rf[2];
>         }
>         else if (args[i].equalsIgnoreCase("-xyz")) {
>           i++;
>           X = new Double(args[i]).doubleValue();
>           i++;
>           Y = new Double(args[i]).doubleValue();
>           i++;
>           Z = new Double(args[i]).doubleValue();
>           rf = csc.XYZtoLAB(X, Y, Z);
>           L = rf[0];
>           a = rf[1];
>           b = rf[2];
>           ri = csc.XYZtoRGB(X, Y, Z);
>           R = ri[0];
>           G = ri[1];
>           B = ri[2];
>         }
>         else if (args[i].equalsIgnoreCase("-lab")) {
>           i++;
>           L = new Double(args[i]).doubleValue();
>           i++;
>           a = new Double(args[i]).doubleValue();
>           i++;
>           b = new Double(args[i]).doubleValue();
>           rf = csc.LABtoXYZ(L, a, b);
>           X = rf[0];
>           Y = rf[1];
>           Z = rf[2];
>           ri = csc.LABtoRGB(L, a, b);
>           R = ri[0];
>           G = ri[1];
>           B = ri[2];
>         }
>       }
>       catch (ArrayIndexOutOfBoundsException e) {
>         System.err.println("Invalid input");
>         e.printStackTrace();
>         System.exit(-1);
>       }
>       System.out.println("");
>       System.out.println("RGB: " + dfi.format(R) + ",\t" + dfi.format
> (G)
>           + ",\t" + dfi.format(B));
>       System.out.println("XYZ: " + dfd.format(X) + ",\t" + dfd.format
> (Y)
>           + ",\t" + dfd.format(Z));
>       System.out.println("Lab: " + dfd.format(L) + ",\t" + dfd.format
> (a)
>           + ",\t" + dfd.format(b));
>     }
>   } // main
>
>   /**
>    * Convert LAB to RGB.
>    * @param L
>    * @param a
>    * @param b
>    * @return RGB values
>    */
>   public int[] LABtoRGB(double L, double a, double b) {
>     return XYZtoRGB(LABtoXYZ(L, a, b));
>   }
>
>   /**
>    * @param Lab
>    * @return RGB values
>    */
>   public int[] LABtoRGB(double[] Lab) {
>     return XYZtoRGB(LABtoXYZ(Lab));
>   }
>
>   /**
>    * Convert LAB to XYZ.
>    * @param L
>    * @param a
>    * @param b
>    * @return XYZ values
>    */
>   public double[] LABtoXYZ(double L, double a, double b) {
>     double[] result = new double[3];
>
>     double y = (L + 16.0) / 116.0;
>     double y3 = Math.pow(y, 3.0);
>     double x = (a / 500.0) + y;
>     double x3 = Math.pow(x, 3.0);
>     double z = y - (b / 200.0);
>     double z3 = Math.pow(z, 3.0);
>
>     if (y3 > 0.008856) {
>       y = y3;
>     }
>     else {
>       y = (y - (16.0 / 116.0)) / 7.787;
>     }
>     if (x3 > 0.008856) {
>       x = x3;
>     }
>     else {
>       x = (x - (16.0 / 116.0)) / 7.787;
>     }
>     if (z3 > 0.008856) {
>       z = z3;
>     }
>     else {
>       z = (z - (16.0 / 116.0)) / 7.787;
>     }
>
>     result[0] = x * D65[0];
>     result[1] = y * D65[1];
>     result[2] = z * D65[2];
>
>     return result;
>   }
>
>   /**
>    * Convert LAB to XYZ.
>    * @param Lab
>    * @return XYZ values
>    */
>   public double[] LABtoXYZ(double[] Lab) {
>     return LABtoXYZ(Lab[0], Lab[1], Lab[2]);
>   }
>
>   /**
>    * @param R
>    * @param G
>    * @param B
>    * @return Lab values
>    */
>   public double[] RGBtoLAB(int R, int G, int B) {
>     return XYZtoLAB(RGBtoXYZ(R, G, B));
>   }
>
>   /**
>    * @param RGB
>    * @return Lab values
>    */
>   public double[] RGBtoLAB(int[] RGB) {
>     return XYZtoLAB(RGBtoXYZ(RGB));
>   }
>
>   /**
>    * Convert RGB to XYZ
>    * @param R
>    * @param G
>    * @param B
>    * @return XYZ in double array.
>    */
>   public double[] RGBtoXYZ(int R, int G, int B) {
>     double[] result = new double[3];
>
>     // convert 0..255 into 0..1
>     double r = R / 255.0;
>     double g = G / 255.0;
>     double b = B / 255.0;
>
>     // assume sRGB
>     if (r <= 0.04045) {
>       r = r / 12.92;
>     }
>     else {
>       r = Math.pow(((r + 0.055) / 1.055), 2.4);
>     }
>     if (g <= 0.04045) {
>       g = g / 12.92;
>     }
>     else {
>       g = Math.pow(((g + 0.055) / 1.055), 2.4);
>     }
>     if (b <= 0.04045) {
>       b = b / 12.92;
>     }
>     else {
>       b = Math.pow(((b + 0.055) / 1.055), 2.4);
>     }
>
>     r *= 100.0;
>     g *= 100.0;
>     b *= 100.0;
>
>     // [X Y Z] = [r g b][M]
>     result[0] = (r * M[0][0]) + (g * M[1][0]) + (b * M[2][0]);
>     result[1] = (r * M[0][1]) + (g * M[1][1]) + (b * M[2][1]);
>     result[2] = (r * M[0][2]) + (g * M[1][2]) + (b * M[2][2]);
>
>     return result;
>   }
>
>   /**
>    * Convert RGB to XYZ
>    * @param RGB
>    * @return XYZ in double array.
>    */
>   public double[] RGBtoXYZ(int[] RGB) {
>     return RGBtoXYZ(RGB[0], RGB[1], RGB[2]);
>   }
>
>   /**
>    * @param x
>    * @param y
>    * @param Y
>    * @return XYZ values
>    */
>   public double[] xyYtoXYZ(double x, double y, double Y) {
>     double[] result = new double[3];
>     if (y == 0) {
>       result[0] = 0;
>       result[1] = 0;
>       result[2] = 0;
>     }
>     else {
>       result[0] = (x * Y) / y;
>       result[1] = Y;
>       result[2] = ((1 - x - y) * Y) / y;
>     }
>     return result;
>   }
>
>   /**
>    * @param xyY
>    * @return XYZ values
>    */
>   public double[] xyYtoXYZ(double[] xyY) {
>     return xyYtoXYZ(xyY[0], xyY[1], xyY[2]);
>   }
>
>   /**
>    * Convert XYZ to LAB.
>    * @param X
>    * @param Y
>    * @param Z
>    * @return Lab values
>    */
>   public double[] XYZtoLAB(double X, double Y, double Z) {
>
>     double x = X / D65[0];
>     double y = Y / D65[1];
>     double z = Z / D65[2];
>
>     if (x > 0.008856) {
>       x = Math.pow(x, 1.0 / 3.0);
>     }
>     else {
>       x = (7.787 * x) + (16.0 / 116.0);
>     }
>     if (y > 0.008856) {
>       y = Math.pow(y, 1.0 / 3.0);
>     }
>     else {
>       y = (7.787 * y) + (16.0 / 116.0);
>     }
>     if (z > 0.008856) {
>       z = Math.pow(z, 1.0 / 3.0);
>     }
>     else {
>       z = (7.787 * z) + (16.0 / 116.0);
>     }
>
>     double[] result = new double[3];
>
>     result[0] = (116.0 * y) - 16.0;
>     result[1] = 500.0 * (x - y);
>     result[2] = 200.0 * (y - z);
>
>     return result;
>   }
>
>   /**
>    * Convert XYZ to LAB.
>    * @param XYZ
>    * @return Lab values
>    */
>   public double[] XYZtoLAB(double[] XYZ) {
>     return XYZtoLAB(XYZ[0], XYZ[1], XYZ[2]);
>   }
>
>   /**
>    * Convert XYZ to RGB.
>    * @param X
>    * @param Y
>    * @param Z
>    * @return RGB in int array.
>    */
>   public int[] XYZtoRGB(double X, double Y, double Z) {
>     int[] result = new int[3];
>
>     double x = X / 100.0;
>     double y = Y / 100.0;
>     double z = Z / 100.0;
>
>     // [r g b] = [X Y Z][Mi]
>     double r = (x * Mi[0][0]) + (y * Mi[1][0]) + (z * Mi[2][0]);
>     double g = (x * Mi[0][1]) + (y * Mi[1][1]) + (z * Mi[2][1]);
>     double b = (x * Mi[0][2]) + (y * Mi[1][2]) + (z * Mi[2][2]);
>
>     // assume sRGB
>     if (r > 0.0031308) {
>       r = ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055);
>     }
>     else {
>       r = (r * 12.92);
>     }
>     if (g > 0.0031308) {
>       g = ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055);
>     }
>     else {
>       g = (g * 12.92);
>     }
>     if (b > 0.0031308) {
>       b = ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055);
>     }
>     else {
>       b = (b * 12.92);
>     }
>
>     r = (r < 0) ? 0 : r;
>     g = (g < 0) ? 0 : g;
>     b = (b < 0) ? 0 : b;
>
>     // convert 0..1 into 0..255
>     result[0] = (int) Math.round(r * 255);
>     result[1] = (int) Math.round(g * 255);
>     result[2] = (int) Math.round(b * 255);
>
>     return result;
>   }
>
>   /**
>    * Convert XYZ to RGB
>    * @param XYZ in a double array.
>    * @return RGB in int array.
>    */
>   public int[] XYZtoRGB(double[] XYZ) {
>     return XYZtoRGB(XYZ[0], XYZ[1], XYZ[2]);
>   }
>
>   /**
>    * @param X
>    * @param Y
>    * @param Z
>    * @return xyY values
>    */
>   public double[] XYZtoxyY(double X, double Y, double Z) {
>     double[] result = new double[3];
>     if ((X + Y + Z) == 0) {
>       result[0] = D65[0];
>       result[1] = D65[1];
>       result[2] = D65[2];
>     }
>     else {
>       result[0] = X / (X + Y + Z);
>       result[1] = Y / (X + Y + Z);
>       result[2] = Y;
>     }
>     return result;
>   }
>
>   /**
>    * @param XYZ
>    * @return xyY values
>    */
>   public double[] XYZtoxyY(double[] XYZ) {
>     return XYZtoxyY(XYZ[0], XYZ[1], XYZ[2]);
>   }
>
> }
>
>