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}