001 package ui.recognizer; 002 003 import java.awt.Color; 004 //import java.awt.color.ColorSpace; 005 006 /** Represents the color of visible light for a given wavelenth between 007 * between 380 nm and 780 nm. Originally from a program by Dan Bruton at 008 * http://www.physics.sfasu.edu/astro/color/spectra.html 009 * 010 * @author John Talbot 011 */ 012 public class MonochromaticColor extends Color { 013 014 public static final double MINIMUM_WAVELENGTH = 380.0 * Units.NANOMETERS; 015 public static final double WAVELENGTH_BLUE = 440.0 * Units.NANOMETERS; 016 public static final double WAVELENGTH_CYAN = 490.0 * Units.NANOMETERS; 017 public static final double WAVELENGTH_GREEN = 510.0 * Units.NANOMETERS; 018 public static final double WAVELENGTH_YELLOW = 580.0 * Units.NANOMETERS; 019 public static final double WAVELENGTH_RED = 645.0 * Units.NANOMETERS; 020 public static final double MAXIMUM_WAVELENGTH = 780.0 * Units.NANOMETERS; 021 022 public static final double BLUE_SENSITIVITY_DROP = 420.0 * Units.NANOMETERS; 023 public static final double RED_SENSITIVITY_DROP = 700.0 * Units.NANOMETERS; 024 025 public static final double TYPICAL_GAMMA = 0.80d; 026 public static final double MAXIMUM_INTENSITY = 1.0d; 027 028 private double wavelength; 029 private double gamma = TYPICAL_GAMMA; 030 031 /** Construct a monochromatic color based on a wavelength between 380 nm and 780 nm 032 * @param aWavelength the wavelength of the visible radiation in meters 033 */ 034 public MonochromaticColor(double aWavelength) { 035 this(aWavelength, MAXIMUM_INTENSITY); 036 } 037 038 /** Construct a monochromatic color based on a wavelength between 380 nm and 780 nm and enhance the contrast using a gamma value. 039 * @param aWavelength the wavelength of the visible radiation in meters 040 * @param intensity a number between 0 and 1.0 (MAXIMUM_INTENSITY) which is to multiply the color 041 */ 042 public MonochromaticColor(double aWavelength, double intensity) { 043 this(aWavelength, intensity, TYPICAL_GAMMA); 044 } 045 046 /** Construct a monochromatic color based on a wavelength between 380 nm and 780 nm and enhance the contrast using a gamma value. 047 * @param aWavelength the wavelength of the visible radiation in meters 048 * @param intensity a number between 0 and 1.0 (MAXIMUM_INTENSITY) which is to multiply the color 049 * @param aGamma a number which can be used to enhance the contrast of darker colors 050 */ 051 public MonochromaticColor(double aWavelength, double intensity, double aGamma) { 052 // the colorspace method of constructing colors is very noisy and non-linear, it was abandonned 053 //super(ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB), getColorComponents(aWavelength, intensity, aGamma), 1.0f); 054 //super(ColorSpace.getInstance(ColorSpace.CS_sRGB), getColorComponents(aWavelength, intensity, aGamma), 1.0f); 055 056 // TODO: improve efficiency by reducing this line to one call to getColorComponents() 057 super(getColorComponents(aWavelength, intensity, aGamma)[0], 058 getColorComponents(aWavelength, intensity, aGamma)[1], 059 getColorComponents(aWavelength, intensity, aGamma)[2]); 060 setWavelength(aWavelength); 061 setGamma(aGamma); 062 } 063 064 /** Get a monochromatic color based on a wavelength between 380 nm and 780 nm 065 * and scale the brightness by an intensity parameter between zero and one. 066 * The contrast is enhanced using a gamma value between 0.0 and 1.0. 067 * @param aWavelength the wavelength of the visible radiation in meters 068 * @param intensity a number between 0 and 1.0 which is to multiply the color 069 * @param aGamma a number which can be used to enhance the contrast of darker colors 070 * @return a color which represents one wavelength of visible light 071 */ 072 public static float[] getColorComponents(double aWavelength, double intensity, double aGamma) { 073 double red; 074 double green; 075 double blue; 076 if (aWavelength >= MINIMUM_WAVELENGTH && aWavelength <= WAVELENGTH_BLUE) { 077 red = (WAVELENGTH_BLUE - aWavelength) / (WAVELENGTH_BLUE - MINIMUM_WAVELENGTH); 078 green = 0.0d; 079 blue = 1.0d; 080 } else if (aWavelength >= WAVELENGTH_BLUE && aWavelength <= WAVELENGTH_CYAN) { 081 red = 0.0d; 082 green = (aWavelength - WAVELENGTH_BLUE) / (WAVELENGTH_CYAN - WAVELENGTH_BLUE); 083 blue = 1.0d; 084 } else if (aWavelength >= WAVELENGTH_CYAN && aWavelength <= WAVELENGTH_GREEN) { 085 red = 0.0d; 086 green = 1.0d; 087 blue = (WAVELENGTH_GREEN - aWavelength) / (WAVELENGTH_GREEN - WAVELENGTH_CYAN); 088 } else if (aWavelength >= WAVELENGTH_GREEN && aWavelength <= WAVELENGTH_YELLOW) { 089 red = (aWavelength - WAVELENGTH_GREEN) / (WAVELENGTH_YELLOW - WAVELENGTH_GREEN); 090 green = 1.0d; 091 blue = 0.0d; 092 } else if (aWavelength >= WAVELENGTH_YELLOW && aWavelength <= WAVELENGTH_RED) { 093 red = 1.0d; 094 green = (WAVELENGTH_RED - aWavelength) / (WAVELENGTH_RED - WAVELENGTH_YELLOW); 095 blue = 0.0d; 096 } else if (aWavelength >= WAVELENGTH_RED && aWavelength <= MAXIMUM_WAVELENGTH) { 097 red = 1.0d; 098 green = 0.0d; 099 blue = 0.0d; 100 } else { 101 red = 0.0d; 102 green = 0.0d; 103 blue = 0.0d; 104 } 105 double spectralSensitivity; 106 107 if (aWavelength > RED_SENSITIVITY_DROP) { 108 spectralSensitivity = 0.3d + 0.7d * (MAXIMUM_WAVELENGTH - aWavelength) / (MAXIMUM_WAVELENGTH - RED_SENSITIVITY_DROP); 109 } else if (aWavelength < BLUE_SENSITIVITY_DROP) { 110 spectralSensitivity = 0.3d + 0.7d * (aWavelength - MINIMUM_WAVELENGTH) / (BLUE_SENSITIVITY_DROP - MINIMUM_WAVELENGTH); 111 } else { 112 spectralSensitivity = 1.0d; 113 } 114 115 // adjust gamma 116 red = Math.pow(spectralSensitivity * red, aGamma); 117 green = Math.pow(spectralSensitivity * green, aGamma); 118 blue = Math.pow(spectralSensitivity * blue, aGamma); 119 120 float[] colors = new float[] { (float) (intensity * red), (float) (intensity * green), (float) (intensity * blue) }; 121 return colors; 122 } 123 124 125 // return new Color((float) (intensity * red), (float) (intensity * green), (float) (intensity * blue)); 126 127 128 public static void main(String[] args) { 129 double wavelength, min = 380e-9, max = 780e-9, fraction; 130 int maxpoints = 512; 131 for (int i = 0; i < maxpoints; i++) { 132 fraction = ((double) i) / ((double) maxpoints); 133 wavelength = min + fraction * (max - min); 134 Color aColor = new MonochromaticColor(wavelength); 135 System.out.println(wavelength + " " + aColor.getRed() + " " + aColor.getGreen() + " " + aColor.getBlue() ); 136 } 137 } 138 139 //--------------------------accessor methods-------------------------------------------- 140 141 /** Get the wavelength in meters which this color represents. 142 * @return a floating point number representing the wavelength in meters 143 */ 144 public double getWavelength() { 145 return wavelength; 146 } 147 148 /** Set the wavelength in meters, and change this color to the closest color match. 149 * @param aWavelength a floating point number representing the wavelength in meters 150 */ 151 public void setWavelength(double aWavelength) { 152 wavelength = aWavelength; 153 // TODO: change this color to suit the wavelength 154 } 155 156 /** Set the wavelength in nanometers and change this color to the closest color match. 157 * @param aWavelengthInNanoMeters a floating point number representing the wavelength in meters 158 */ 159 public void setWavelengthInNanoMeters(double aWavelengthInNanoMeters) { 160 setWavelength(aWavelengthInNanoMeters * Units.NANOMETERS); 161 } 162 163 /** Set the wavelength in angstrom units and change this color to the closest color match. 164 * @param aWavelengthInAngtroms a floating point number representing the wavelength in meters 165 */ 166 public void setWavelengthInAngtroms(double aWavelengthInAngtroms) { 167 setWavelength(aWavelengthInAngtroms * Units.ANGSTROMS); 168 } 169 170 /** Set the gamma, a number which can be used to enhance the contrast of darker colors. 171 * @param aGamma a number representing the gamma of the color 172 */ 173 public void setGamma(double aGamma) { 174 gamma = aGamma; 175 } 176 177 /** Get the gamma, a number which can be used to enhance the contrast of darker colors. 178 * @return a number representing the gamma of the color 179 */ 180 public double getGamma() { 181 return gamma; 182 } 183 }