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-2023 Wilhelm Burger, Mark J. Burge. All rights reserved. 007 * Visit https://imagingbook.com for additional details. 008 ******************************************************************************/ 009 010package imagingbook.common.color.cie; 011 012import imagingbook.common.math.Arithmetic; 013 014/** 015 * <p> 016 * Defines static methods for converting between CIE-XYZ coordinates (3D) and xy chromaticity values (2D). See Sec. 017 * 14.1.2 of [1] for details. 018 * </p> 019 * <p> 020 * [1] W. Burger, M.J. Burge, <em>Digital Image Processing – An Algorithmic Introduction</em>, 3rd ed, Springer 021 * (2022). 022 * </p> 023 * 024 * @author WB 025 */ 026public abstract class CieUtils { 027 028 private CieUtils() { 029 } 030 031 /** 032 * Calculates the XYZ coordinates for a given point (x,y) in the CIE xy-color diagram. XYZ is located on the 3D 033 * plane X + Y + Z = 1. Returns (0,0,0) for y = 0; 034 * 035 * @param x x-coordinate (in the 2D xy-diagram) 036 * @param y y-coordinate (in the 2D xy-diagram) 037 * @return the associated XYZ coordinate 038 */ 039 public static double[] xyToXYZ(double x, double y) { 040 return xyYToXYZ(x, y, 1.0); 041 } 042 043 /** 044 * Float version of {@link #xyToXYZ(double, double)}. 045 * 046 * @param x x-coordinate (in the 2D xy-diagram) 047 * @param y y-coordinate (in the 2D xy-diagram) 048 * @return the associated XYZ coordinate 049 */ 050 public static float[] xyToXYZ(float x, float y) { 051 return xyYToXYZ(x, y, 1.0f); 052 } 053 054 /** 055 * Calculates the XYZ coordinates for a given point (x,y) in the CIE xy-color diagram, with Y explicitly specified. 056 * 057 * @param x x-coordinate (in the 2D xy-diagram) 058 * @param y y-coordinate (in the 2D xy-diagram) 059 * @param Y the Y-coordinate (in 3D color space) 060 * @return the associated XYZ coordinate 061 */ 062 public static double[] xyYToXYZ(double x, double y, double Y) { 063 if (Arithmetic.isZero(y)) { 064 return new double[]{0, 0, 0}; 065 } else { 066 double X = x * Y / y; 067 double Z = (1 - x - y) * Y / y; 068 return new double[]{X, Y, Z}; 069 } 070 } 071 072 /** 073 * Float version of {@link #xyYToXYZ(double, double, double)}. 074 * 075 * @param x x-coordinate (in the 2D xy-diagram) 076 * @param y y-coordinate (in the 2D xy-diagram) 077 * @param Y the Y-coordinate (in 3D color space) 078 * @return the associated XYZ coordinate 079 */ 080 public static float[] xyYToXYZ(float x, float y, float Y) { 081 if (Arithmetic.isZero(y)) { 082 return new float[]{0, 0, 0}; 083 } else { 084 float X = x * Y / y; 085 float Z = (1 - x - y) * Y / y; 086 return new float[]{X, Y, Z}; 087 } 088 } 089 090 /** 091 * Calculates the 2D (x,y) color diagram coordinates for 3D XYZ color coordinates (X,Y,Z). 092 * 093 * @param XYZ the XYZ coordinate (3D) 094 * @return the xy-coordinate (2D) 095 */ 096 public static double[] XYZToxy(double[] XYZ) { 097 double X = XYZ[0]; 098 double Y = XYZ[1]; 099 double Z = XYZ[2]; 100 double mag = X + Y + Z; 101 return (Arithmetic.isZero(mag)) ? 102 new double[]{0, 0} : new double[]{X / mag, Y / mag}; 103 } 104 105 /** 106 * Calculates the 3D (x,y,z) color diagram coordinates for 3D XYZ color coordinates (X,Y,Z). 107 * 108 * @param XYZ the XYZ coordinate (3D) 109 * @return the xyz-coordinate (3D) 110 */ 111 public static double[] XYZToxyz(double[] XYZ) { 112 double X = XYZ[0]; 113 double Y = XYZ[1]; 114 double Z = XYZ[2]; 115 double mag = X + Y + Z; 116 return (Arithmetic.isZero(mag)) ? 117 new double[]{0, 0, 0} : new double[]{X / mag, Y / mag, Z / mag}; 118 } 119 120 /** 121 * Float version of {@link #XYZToxy(double[])}. 122 * 123 * @param XYZ the XYZ coordinate (3D) 124 * @return the xy-coordinate (2D) 125 */ 126 public static float[] XYZToxy(float[] XYZ) { 127 double X = XYZ[0]; 128 double Y = XYZ[1]; 129 double Z = XYZ[2]; 130 double mag = X + Y + Z; 131 return (Arithmetic.isZero(mag)) ? 132 new float[]{0, 0} : new float[]{(float) (X / mag), (float) (Y / mag)}; 133 } 134 135 /** 136 * Float version of {@link #XYZToxyz(double[])}. 137 * 138 * @param XYZ the XYZ coordinate (3D) 139 * @return the xyz-coordinate (§D) 140 */ 141 public static float[] XYZToxyz(float[] XYZ) { 142 double X = XYZ[0]; 143 double Y = XYZ[1]; 144 double Z = XYZ[2]; 145 double mag = X + Y + Z; 146 return (Arithmetic.isZero(mag)) ? 147 new float[]{0, 0, 0} : new float[]{(float) (X / mag), (float) (Y / mag), (float) (Z / mag)}; 148 } 149 150}