00001 /* 00002 File: ColourSystem.cc 00003 00004 Function: Provides a class to help with colour space conversions to 00005 and from three-primary display devices. 00006 00007 Author: Andrew Willmott 00008 00009 */ 00010 00011 #include "ColourSystem.h" 00012 00074 ColourSystem::ColourSystem( 00075 Chroma primary1, 00076 Chroma primary2, 00077 Chroma primary3, 00078 Chroma whitePoint, 00079 ClrReal whiteLuminance 00080 ) 00081 { 00082 Colour whiteXYZ, csWhite; 00083 00084 prim0 = primary1; 00085 prim1 = primary2; 00086 prim2 = primary3; 00087 white = whitePoint; 00088 whiteLum = whiteLuminance; 00089 00090 toXYZ[0] = Colour(prim0[0], prim1[0], prim2[0]); 00091 toXYZ[1] = Colour(prim0[1], prim1[1], prim2[1]); 00092 toXYZ[2] = cWhite - toXYZ[0] - toXYZ[1]; 00093 00094 fromXYZ = inv(toXYZ); 00095 00096 // now we must scale so that the white point 00097 // maps to the cs colour [1, 1, 1]. 00098 00099 whiteXYZ = Colour(white[0], white[1], 1.0 - white[0] - white[1]); 00100 whiteXYZ *= whiteLum / white[1]; 00101 00102 csWhite = fromXYZ * whiteXYZ; 00103 00104 fromXYZ[0] /= csWhite[0]; 00105 fromXYZ[1] /= csWhite[1]; 00106 fromXYZ[2] /= csWhite[2]; 00107 col(toXYZ, 0) *= csWhite[0]; 00108 col(toXYZ, 1) *= csWhite[1]; 00109 col(toXYZ, 2) *= csWhite[2]; 00110 } 00111 00112 Colour ColourSystem::XYZToGamut(const Colour &cieXYZ) 00120 { 00121 Colour csClr = fromXYZ * cieXYZ; 00122 Colour t; 00123 ClrReal tMin; 00124 00125 // Is the contribution of one of the primaries negative? 00126 00127 if (MinCmpt(csClr) < 0.0) 00128 { 00129 // find how far we must move along the line through the white 00130 // point until we hit each axial plane 00131 t = cWhite / (cWhite - csClr); 00132 00133 // find smallest +ve intercept 00134 tMin = 1.0; 00135 if (t[0] >= 0.0) tMin = t[0]; 00136 if (t[1] >= 0.0 && t[1] < tMin) tMin = t[1]; 00137 if (t[2] >= 0.0 && t[2] < tMin) tMin = t[2]; 00138 00139 csClr = cWhite + (csClr - cWhite) * tMin; 00140 ClipColourZero(csClr); 00141 Assert(MinCmpt(csClr) >= 0.0, "bad correction"); 00142 } 00143 00144 return(csClr); 00145 } 00146 00147 Colour ColourSystem::XYZToGamutClip(const Colour &cieXYZ) 00148 { 00149 Colour c = XYZToGamut(cieXYZ); 00150 00151 if (c[0] > 1.0) c[0] = 1.0; 00152 if (c[1] > 1.0) c[1] = 1.0; 00153 if (c[2] > 1.0) c[2] = 1.0; 00154 00155 return(c); 00156 } 00157 00158 Colour ColourSystem::ChromaToGamut(const Chroma &cieChroma) 00159 { 00160 Colour c; 00161 00162 c = XYZToGamut(Colour(cieChroma, 1.0 - cieChroma[0] - cieChroma[1])); 00163 c /= cieChroma[1]; 00164 00165 return(c); 00166 } 00167 00168 Bool ColourSystem::XYZIsOutOfGamut(const Colour &cieXYZ) 00169 { 00170 return(MinCmpt(fromXYZ * cieXYZ) < 0.0); 00171 } 00172 00173 Bool ColourSystem::ChromaIsOutOfGamut(const Chroma &cieChroma) 00174 { 00175 return(MinCmpt(fromXYZ * Colour(cieChroma, 1.0 - cieChroma[0] - cieChroma[1])) 00176 < 0.0); 00177 } 00178 00179 // --- CIE standard illuminants --------------------------------------- 00180 00181 const Chroma csIllumA(0.448, 0.407); // Incandescent light 00182 const Chroma csIllumB(0.348, 0.352); // Solar light 00183 const Chroma csIllumC(0.3101, 0.3162); // For NTSC television 00184 const Chroma csIllumD55(0.332, 0.348); // Photography 00185 const Chroma csIllumD65(0.3127, 0.3291); // Overcast Daylight 00186 const Chroma csIllumD75(0.299, 0.315); 00187 const Chroma csIllumE(0.3333333, 0.3333333); // Uniform illuminant 00188 00189 // luminances of standard illuminants, in candela/watt 00190 00191 const ClrReal csMaxLum(683.0); // defined maximum at 555 nm 00192 const ClrReal csWhiteLum(179.0); // uniform white light 00193 const ClrReal csD65Lum(203.0); 00194 const ClrReal csALum(160.0); 00195 const ClrReal csBLum(208.0); 00196 00197 00198 // NOTE: most of this data is simply reformatted from the delphi 00199 // source code provided by EFG's fabulous CIE page above. 00200 00201 // The following define the x and y coordinates of the phosphors and 00202 // reference white points of various broadcast systems. 00203 00204 // [Martindale91] notes that NTSC primaries aren't remotely similar 00205 // to those used in modern displays. 00206 // 00207 // CCIR Report 476-1 00208 // "Colorimetric Standards in Colour Television" 00209 // See http://www.igd.fhg.de/icib/tv/ccir/rep_476-1/gen.html 00210 // 00211 // CCIR Report 624-4 00212 // "Characteristics of Television Systems" 00213 // See http://www.igd.fhg.de/icib/tv/ccir/rep_624/read.html 00214 00215 ColourSystem csNTSC( 00216 Chroma(0.67, 0.33), 00217 Chroma(0.21, 0.71), 00218 Chroma(0.14, 0.08), 00219 Chroma(0.310, 0.316) 00220 ); 00221 00222 // CCIR Report 476-1 00223 // "Colorimetric Standards in Colour Television" 00224 // See http://www.igd.fhg.de/icib/tv/ccir/rep_476-1/gen.html 00225 // 00226 // CCIR Report 624-4 00227 // "Characteristics of Television Systems" 00228 // See http://www.igd.fhg.de/icib/tv/ccir/rep_624/read.html 00229 00230 ColourSystem csPAL_SECAM( 00231 Chroma(0.64, 0.33), 00232 Chroma(0.29, 0.60), 00233 Chroma(0.15, 0.06), 00234 Chroma(0.313, 0.329) 00235 ); 00236 00237 // CCIR Recommendation 709 00238 // "Basic Parameter Values for the HDTV Standard for the Studio and for 00239 // International Programme Exchange" 00240 // See http://www.igd.fhg.de/icib/tv/ccir/rec_709/pictures/page-2.tiff 00241 00242 // EBU Technical Document 3271 (EBU = European Broadcasting Union) 00243 // "Interlaced version of the 1250/50 HDTV production standard" 00244 // http://www.igd.fhg.de/icib/tv/org/ebu/td_3271/pictures/page5.tiff 00245 00246 // This is used for all HDTV stuff. 00247 00248 ColourSystem csEBU( 00249 Chroma(0.640, 0.330), 00250 Chroma(0.300, 0.600), 00251 Chroma(0.150, 0.060), 00252 Chroma(0.3127, 0.3290) 00253 ); 00254 00255 // SMPTE 240M (SMPTE = The Society of Motion Picture and Television Engineers) 00256 // "Signal Parameters -- 1125-line High-Definition Production System" 00257 // http://www.igd.fhg.de/icib/tv/org/smpte/st_240M-1992/read.html 00258 00259 ColourSystem csSMPTE( 00260 Chroma(0.630, 0.340), 00261 Chroma(0.310, 0.595), 00262 Chroma(0.155, 0.070), 00263 csIllumD65 00264 ); 00265 00266 00267 ColourSystem csShortPersistencePhosphors( // [Foley96, p. 583] 00268 Chroma(0.61, 0.35), 00269 Chroma(0.29, 0.59), 00270 Chroma(0.15, 0.063), 00271 csIllumC 00272 ); 00273 00274 ColourSystem csLongPersistencePhosphors( // [Foley96, p. 583] 00275 Chroma(0.62, 0.33), 00276 Chroma(0.21, 0.685), 00277 Chroma(0.15, 0.063), 00278 csIllumC 00279 ); 00280 00281 ColourSystem csDellPhosphors( // 12 Jan 99 E-mail from Dell 00282 Chroma(0.625, 0.340), // All Dell monitors except 00283 Chroma(0.275, 0.605), // Nokia 91862 00284 Chroma(0.150, 0.065), 00285 csIllumD65 00286 ); 00287 00288 #ifdef UNFINISHED 00289 Sony Trinitron 00290 Red 0.621 0.340 00291 Green 0.281 0.606 00292 Blue 0.152 0.067 00293 00294 Hitachi CM2198 (all +- 0.02): 00295 00296 Red 0.624 0.339 00297 Green 0.285 0.604 00298 Blue 0.150 0.065 00299 00300 #endif 00301 00302 ColourSystem &csDisplay = csEBU; 00303 00304 #ifdef UNFINISHED 00305 ClrReal CIELumToLightness(ClrReal lum) 00306 { 00307 float relative_luminance; 00308 00309 if (reference_luminance == 0.) 00310 return 0.; 00311 00312 relative_luminance = luminance / reference_luminance; 00313 if (relative_luminance > 0.008856) 00314 return (1.16 * pow(relative_luminance, 0.33) - 0.16); 00315 else 00316 return 9.033 * relative_luminance; 00317 } 00318 #endif