001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 *  image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause 
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 
006 * Copyright (c) 2006-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 
007 * Visit http://imagingbook.com for additional details.
008 *******************************************************************************/
009
010package imagingbook.pub.color.image;
011
012/*
013 * This class represents a linear chromatic adaptation transform.
014 * The transformation is specified by the matrix 'Mfwd' and its
015 * inverse 'Minv'.
016 */
017
018public class BradfordAdaptation extends ChromaticAdaptation {
019        
020        // CAT transform matrices (forward and inverse)
021        static protected double[][] Mfwd = new double[][] {
022            { 0.8951,  0.2664, -0.1614},
023            {-0.7502,  1.7135,  0.0367},
024            { 0.0389, -0.0685,  1.0296}};
025        static protected double[][] Minv = new double[][] {     
026                { 0.9869929055, -0.1470542564, 0.1599626517}, 
027                { 0.4323052697,  0.5183602715, 0.0492912282},
028                {-0.0085286646,  0.0400428217, 0.9684866958}};
029        
030        //      the complete color adaptation transformation matrix
031        protected double[][] Mcat = null;
032        
033        public BradfordAdaptation(float[] white1, float[] white2) {
034                super(white1, white2);
035                double[] rgb1 = mult(Mfwd, white1);
036                double[] rgb2 = mult(Mfwd, white2);
037                double[][] Mrgb = rgbMatrix(rgb1, rgb2);
038                Mcat = mult(Minv, mult(Mrgb,Mfwd));
039        }
040        
041        public BradfordAdaptation(Illuminant illum1, Illuminant illum2) {
042                this(illum1.getXyzFloat(), illum2.getXyzFloat());
043        }
044        
045        // transformation of color coordinates
046        public float[] apply (float[] XYZ1) {
047                float[] XYZ2 = new float[3];
048                for (int i=0; i<3; i++) {
049                        XYZ2[i] = (float) (Mcat[i][0] * XYZ1[0] + Mcat[i][1] * XYZ1[1] + Mcat[i][2] * XYZ1[2]);
050                }
051                return XYZ2;
052        }
053        
054        // matrix utility methods:
055        
056        // multiply matrices: (m1 * m2)
057        static double[][] mult (double[][] m1, double[][] m2) {
058                // m1 is of size (p,q)
059                // m2 is of size (q,r)
060                int p = m1.length;              // m1 has p rows
061                int q = m1[0].length;   // m1 has q colums
062                int r = m2[0].length;   // m2 has q rows, r columns
063                if (q != m2.length) throw new IllegalArgumentException();
064                double[][] result = new double[p][r];
065                for (int i=0; i<p; i++) {
066                        for (int j=0; j<r; j++) {
067                                double s = 0.0;
068                                for (int k=0; k<q; k++) {
069                                        s = s + m1[i][k] * m2[k][j];
070                                }
071                                result[i][j] = s;
072                        }
073                }
074                return result;
075        }
076        
077        // multiply matrix M with float vector x
078        static double[] mult (double[][] M, float[] x) {
079                int p = M.length;
080                int q = M[0].length;
081                if (x.length != q) throw new IllegalArgumentException();
082                double[] y = new double[p];
083                for (int i=0; i<p; i++) {
084                        for (int k=0; k<q; k++) {
085                                y[i] = y[i] + M[i][k] * x[k];
086                        }
087                }
088                return y;
089        }
090        
091        // returns a diagonal matrix with the ratios of the rgb components
092        // obtained by transforming the two white points
093        double[][] rgbMatrix(double[] rgb1, double[] rgb2) {
094                if (rgb1.length != rgb2.length) throw new IllegalArgumentException();
095                int n = rgb1.length;
096                double[][] Madapt = new double[n][n];
097                for (int i=0; i<n; i++) {
098                        Madapt[i][i] = rgb2[i] / rgb1[i];
099                }
100                return Madapt;
101        }
102
103        // prints the composite transformation matrix
104        public void printCAT () {
105                for (int i=0; i<Mcat.length; i++) {
106                        for (int j=0; j<Mcat[0].length; j++) {
107                                System.out.printf(java.util.Locale.US, "%8.6f ", Mcat[i][j]);
108                        }
109                        System.out.println();
110                }
111        }
112}