~
BEGIN
See ImagerColor for CIEXYZ to/from Chromaticity conversions
CIE:
TYPE = ImagerColor.
CIE;
CIE: TYPE ~ RECORD [X, Y, Z: REAL];
CIEChromaticity:
TYPE = ImagerColor.CIEChromaticity;
CIEChromaticity: TYPE ~ RECORD [x, y: REAL];
CIELAB: TYPE ~ RECORD [lStar, aStar, bStar: REAL];
CIELUV: TYPE ~ RECORD [lStar, uStar, vStar: REAL];
MetricChromaticity: TYPE ~ RECORD [uPrime, vPrime: REAL];
The CIE lightness function. This is controversial for Y/Yn < 0.01 (1%).
Note that such colors are very dark.
LStarFromLuminance:
PROC [Y:
REAL, whiteY:
REAL]
RETURNS[lStar:
REAL];
L* = 116(Y/Yn)1/3 - 16 Y/Yn > 0.008856
L* = 903.29(Y/Yn) Y/Yn <= 0.008856
LuminanceFromLStar: PROC [lStar: REAL, whiteY: REAL] RETURNS[Y: REAL];
THE CIE 1976 Metric Chromaticity Coordinates.
These coordinates are supposed to be more uniformly spaced perceptually than xy.
MetricChrFromXYZ:
PROC[xyz:
CIE]
RETURNS[uv: MetricChromaticity];
u' = 4X/(X+15Y+3Z) v' = 9Y/(X+15Y+3Z)
The inverse function does not seem to be commonly used. That is, I don't know
what additional information (Y? L? L*?) goes with u',v' to convert back to XYZ
MetricChrFromChr:
PROC[xy: CIEChromaticity]
RETURNS[uv: MetricChromaticity];
u' = 4x/(-2x+12y+3) v' = 9y/(-2x+12y+3)
ChrFromMetricChr:
PROC[uv: MetricChromaticity]
RETURNS[xy: CIEChromaticity];
x = 27u'/(18u'-48v'+36) y = 12v'/(18u'-48v'+36)
In CIELAB or CIELUV, the perceptual difference between two colors is approximately the euclidian distance between the two points in the color space. Both use the same function for lightness, L*, defined above, with the same caveat for very dark colors. Both are defined relative to a "reference white". Both were standardized by the CIE as they both were in common use and were judged to work equally well.
CIELABFromXYZ: PROC [xyz: CIE, white: CIE] RETURNS[lab: CIELAB];
XYZFromCIELAB:
PROC [lab:
CIELAB, white:
CIE]
RETURNS[xyz:
CIE];
The equations for CIELAB are:
a* = 500[(X/Xn)1/3 - (Y/Yn)1/3]
b* = 200[(Z/Zn)1/3 - (Y/Yn)1/3]
where Xn, Yn, Zn are the tristimulus values of the reference white. For values of X/Xn, Y/Yn, or Z/Zn less than 0.008856 use ??
CIELUVFromXYZ: PROC [xyz: CIE, white: CIE] RETURNS[luv: CIELUV];
XYZFromCIELUV:
PROC [luv:
CIELUV, white:
CIE]
RETURNS[xyz:
CIE];
The equations for CIELUV are:
u* = 13L*(u'-un')
v* = 13L*(v'-vn')
where u' and un' are the Metric Chromaticiy coordinates of the value and the reference white
DifferenceCIELAB: PROC [color1, color2: CIELAB] RETURNS [difference: REAL];
DifferenceCIELUV: PROC [color1, color2: CIELUV] RETURNS [difference: REAL];
One unit equals a "noticeable difference". Just computes the Euclidian distance between the two colors. These formulas are intended for colors that are close to one another. Don't get too hung up on the numbers here—some sources claim that only one digit is significant.
For ideal Reflectance, or for Transmittance=1-R.
Used for computing density from ideal dot area on halftoned films.
DensityFromReflectance:
PROC[r:
REAL]
RETURNS[
REAL];
d ← Log[1/R]. Reflectance of 0 will return a density of 5.0 (R=0.00001)
Reflectance is percentage [0+..100].
ReflectanceFromDensity:
PROC[d:
REAL]
RETURNS[
REAL];
Density is positive. To be consistant with procedure above, Density in [0..3]
Density measured from halftoned patterns on prints does not follow the equations above.
Here are equations relating density and dot area for reflective prints.
DensityFromDotArea:
PROC[area:
REAL, solidD:
REAL ← 1.5, n:
REAL ← 1.4]
RETURNS[density:
REAL];
area is percentage in [0..100], Density is positive. D = -n*log[1-a(1-10-solidD/n)]
If n=1 then reduces to the Murray-Davis equations (ref. Yule).
DotAreaFromDensity:
PROC[density:
REAL, solidD:
REAL ← 1.5, n:
REAL ← 1.4]
RETURNS[area:
REAL];
area is percentage in [0..100], Density is positive. Inverse of above