package fr.unistra.pelican.util.lut; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import fr.unistra.pelican.AlgorithmException; import fr.unistra.pelican.Image; public class ThreeBandByteConversionLUT implements Serializable { private static final long serialVersionUID = 200911131007L; /** * LUT for band 0 */ public byte[][][] lut0= new byte[256][256][256]; /** * LUT for band 1 */ public byte[][][] lut1= new byte[256][256][256]; /** * LUT for band 2 */ public byte[][][] lut2= new byte[256][256][256]; /** * Constructor */ public ThreeBandByteConversionLUT() {} /** * Create the LUT for converting RGB image to Lab Image * @return LUT RGBToLab */ public static ThreeBandByteConversionLUT getRGBToLabLUT() { ThreeBandByteConversionLUT tbclut = new ThreeBandByteConversionLUT(); double[][][] xyz0 = new double[256][256][256]; double[][][] xyz1 = new double[256][256][256]; double[][][] xyz2 = new double[256][256][256]; //RGBToXYZ for(int r=0;r<256;r++) for(int g=0;g<256;g++) for(int b=0;b<256;b++) { double rN = r * 0.003921; double gN = g * 0.003921; double bN = b * 0.003921; xyz0[r][g][b]=0.412453 * rN + 0.357580 * gN + 0.180423 * bN; xyz1[r][g][b]=0.212671 * rN + 0.715160 * gN + 0.072169 * bN; xyz2[r][g][b]=0.019334 * rN + 0.119193 * gN + 0.950227 * bN; } //XYZToLab double Xn = 0.950456; double Yn = 1.0; double Zn = 1.088754; for(int r=0;r<256;r++) for(int g=0;g<256;g++) for(int b=0;b<256;b++) { double Xfrac = xyz0[r][g][b] / Xn; double Yfrac = xyz1[r][g][b] / Yn; double Zfrac = xyz2[r][g][b] / Zn; if (Xfrac > 0.008856) Xfrac = Math.pow(Xfrac, 0.333333); else Xfrac = 7.787 * Xfrac + 16.0 / 116.0; if (Yfrac > 0.008856) Yfrac = Math.pow(Yfrac, 0.333333); else Yfrac = 7.787 * Yfrac + 16.0 / 116.0; if (Zfrac > 0.008856) Zfrac = Math.pow(Zfrac, 0.333333); else Zfrac = 7.787 * Zfrac + 16.0 / 116.0; tbclut.lut0[r][g][b] = Image.unsignedByteToSignedByte((int)Math.round((116 * Yfrac - 16.0)*2.55)); tbclut.lut1[r][g][b] = Image.unsignedByteToSignedByte((int)Math.round(500 * (Xfrac - Yfrac))+128); tbclut.lut2[r][g][b] = Image.unsignedByteToSignedByte((int)Math.round(200 * (Yfrac - Zfrac))+128); } return tbclut; } /** * Create the LUT for converting RGB image to LSH Image * @return LUT RGBToLSH */ public static ThreeBandByteConversionLUT getRGBToLSHLUT() { ThreeBandByteConversionLUT tbclut = new ThreeBandByteConversionLUT(); for(int R=0;R<256;R++) for(int G=0;G<256;G++) for(int B=0;B<256;B++) { double r = Image.unsignedByteToDouble(R); double g = Image.unsignedByteToDouble(G); double b = Image.unsignedByteToDouble(B); double[] lsh = new double[3]; lsh[0] = lsh[1] = lsh[2] = 0.0; double max = 0.0, med = 0.0, min = 0.0; if( r >= g && r >= b ) { max = r; if ( g >= b ) { med = g; min = b; } else { med = b; min = g; } } else if( g >= r && g >= b ) { max = g; if( r >= b ) { med = r; min = b; } else { med = b; min = r; } } else if( b >= r && b >= g ) { max = b; if( r >= g ) { med = r; min = g; } else { med = g; min = r; } } // fi // luminance lsh[0] = ( max + med + min ) / 3.0; // saturation if( lsh[0] >= med ) lsh[1] = 1.5 * ( max - lsh[0] ); else lsh[1] = 1.5 * ( lsh[0] - min ); // hue double k = 1.0/6.0; int lambda = 0; if( r > g && g >= b ) lambda = 0; else if( g >= r && r > b ) lambda = 1; else if( g > b && b >= r ) lambda = 2; else if( b >= g && g > r ) lambda = 3; else if( b > r && r >= g ) lambda = 4; else if( r >= b && b > g ) lambda = 5; if ( lsh[1] > 0.0 ) lsh[2] = k * ( lambda + 0.5 - Math.pow(-1,lambda) * ( max+min-2*med ) / ( 2*lsh[1] ) ); else lsh[2] = 0; if( lsh[2] < 0 ) lsh[2] = 0; tbclut.lut0[R][G][B] = Image.doubleToSignedByte(lsh[0]); tbclut.lut1[R][G][B] = Image.doubleToSignedByte(lsh[1]); tbclut.lut2[R][G][B] = Image.doubleToSignedByte(lsh[2]); } return tbclut; } /** * Create the LUT for converting RGB image to HSV Image * @return LUT RGBToLab */ public static ThreeBandByteConversionLUT getRGBToHSVLUT() { ThreeBandByteConversionLUT tbclut = new ThreeBandByteConversionLUT(); for(int R=0;R<256;R++) for(int G=0;G<256;G++) for(int B=0;B<256;B++) { double rN = R * 0.003921; double gN = G * 0.003921; double bN = B * 0.003921; double H, S, V; double min = rN; if (gN < min) min = gN; if (bN < min) min = bN; double max = rN; if (gN > max) max = gN; if (bN > max) max = bN; S = H = 0.0; V = max; double delta = max - min; if (max != 0 && delta != 0.0) { S = delta / max; if (rN == max) H = 60 * (gN - bN) / delta; else if (gN == max) H = 60 * (bN - rN) / delta + 120; else H = 60 * (rN - gN) / delta + 240; // bN == max if (H < 0.0) H += 360; if (H > 360) H -= 360; H = H / 360.0; } tbclut.lut0[R][G][B] = Image.doubleToSignedByte(H); tbclut.lut1[R][G][B] = Image.doubleToSignedByte(S); tbclut.lut2[R][G][B] = Image.doubleToSignedByte(V); } return tbclut; } /** * Create the LUT for converting RGB image to HSL Image * @return LUT RGBToLab */ public static ThreeBandByteConversionLUT getRGBToHSLLUT() { ThreeBandByteConversionLUT tbclut = new ThreeBandByteConversionLUT(); for(int R=0;R<256;R++) for(int G=0;G<256;G++) for(int B=0;B<256;B++) { // normalise to [0,1] double rN = R * 0.003921; double gN = G * 0.003921; double bN = B * 0.003921; double H, S, L; H = S = L = 0.0; double min = rN; if (gN < min) min = gN; if (bN < min) min = bN; double max = rN; if (gN > max) max = gN; if (bN > max) max = bN; double delta = max - min; L = (max + min) * 0.5; if (delta >= 0.0 && delta <= 0.0) { H = S = 0.0; } else { if (L < 0.5) S = delta / (max + min); else S = delta / (2 - max - min); } double _R = (((max - rN) / 6.0) + delta * 0.5) / delta; double _G = (((max - gN) / 6.0) + delta * 0.5) / delta; double _B = (((max - bN) / 6.0) + delta * 0.5) / delta; if (rN == max) H = _B - _G; else if (gN == max) H = 1.0 / 3.0 + _R - _B; else if (bN == max) H = 2.0 / 3.0 + _G - _R; if (H < 0.0) H += 1.0; if (H > 1.0) H -= 1.0; tbclut.lut0[R][G][B] = Image.doubleToSignedByte(H); tbclut.lut1[R][G][B] = Image.doubleToSignedByte(S); tbclut.lut2[R][G][B] = Image.doubleToSignedByte(L); } return tbclut; } /** * Save the LUT on the specified filename * @param filename */ public void save(String filename) { try { ObjectOutputStream f = null; f = new ObjectOutputStream(new GZIPOutputStream(new FileOutputStream(filename))); f.writeObject(this); f.close(); } catch (IOException ex) { System.err.println(ex.getMessage()); throw new AlgorithmException("file writing error with file: " + filename); } } /** * Load a LUT from a specified filename * @param filename * @return LUT */ public static ThreeBandByteConversionLUT load(String filename) { ThreeBandByteConversionLUT lut=null; try { ObjectInputStream f = null; f = new ObjectInputStream(new GZIPInputStream(new FileInputStream( filename))); lut = (ThreeBandByteConversionLUT) f.readObject(); f.close(); } catch (IOException ex) { throw new AlgorithmException("file reading error with file: " + filename,ex); } catch (ClassNotFoundException ex) { throw new AlgorithmException("file reading error with file: " + filename,ex); } return lut; } }