Next: , Previous: Color Spaces, Up: Color


5.11.3 Spectra

The following functions compute colors from spectra, scale color luminance, and extract chromaticity. XYZ is used in the names of procedures for unnormalized colors; the coordinates of CIEXYZ colors are constrained as described in Color Spaces.

(require 'color-space)

A spectrum may be represented as:

CIEXYZ values are calculated as dot-product with the X, Y (Luminance), and Z Spectral Tristimulus Values. The files cie1931.xyz and cie1964.xyz in the distribution contain these CIE-defined values.

— Feature: cie1964

Loads the Spectral Tristimulus Values CIE 1964 Supplementary Standard Colorimetric Observer, defining cie:x-bar, cie:y-bar, and cie:z-bar.

— Feature: cie1931

Loads the Spectral Tristimulus Values CIE 1931 Supplementary Standard Colorimetric Observer, defining cie:x-bar, cie:y-bar, and cie:z-bar.

— Feature: ciexyz

Requires Spectral Tristimulus Values, defaulting to cie1931, defining cie:x-bar, cie:y-bar, and cie:z-bar.

(require 'cie1964) or (require 'cie1931) will load-ciexyz specific values used by the following spectrum conversion procedures. The spectrum conversion procedures (require 'ciexyz) to assure that a set is loaded.

— Function: read-cie-illuminant path

path must be a string naming a file consisting of 107 numbers for 5.nm intervals from 300.nm to 830.nm. read-cie-illuminant reads (using Scheme read) these numbers and returns a length 107 vector filled with them.

     (define CIE:SI-D65
       (read-CIE-illuminant (in-vicinity (library-vicinity) "ciesid65.dat")))
     (spectrum->XYZ CIE:SI-D65 300e-9 830e-9)
     ⇒ (25.108569422374994 26.418013465625001 28.764075683374993)
— Function: read-normalized-illuminant path

path must be a string naming a file consisting of 107 numbers for 5.nm intervals from 300.nm to 830.nm. read-normalized-illuminant reads (using Scheme read) these numbers and returns a length 107 vector filled with them, normalized so that spectrum->XYZ of the illuminant returns its whitepoint.

CIE Standard Illuminants A and D65 are included with SLIB:

     (define CIE:SI-A
       (read-normalized-illuminant (in-vicinity (library-vicinity) "ciesia.dat")))
     (define CIE:SI-D65
       (read-normalized-illuminant (in-vicinity (library-vicinity) "ciesid65.dat")))
     (spectrum->XYZ CIE:SI-A 300e-9 830e-9)
     ⇒ (1.098499460820401 999.9999999999998e-3 355.8173930654951e-3)
     (CIEXYZ->sRGB (spectrum->XYZ CIE:SI-A 300e-9 830e-9))
     ⇒ (255 234 133)
     (spectrum->XYZ CIE:SI-D65 300e-9 830e-9)
     ⇒ (950.4336673552745e-3 1.0000000000000002 1.0888053986649182)
     (CIEXYZ->sRGB (spectrum->XYZ CIE:SI-D65 300e-9 830e-9))
     ⇒ (255 255 255)
— Function: illuminant-map proc siv

siv must be a one-dimensional array or vector of 107 numbers. illuminant-map returns a vector of length 107 containing the result of applying proc to each element of siv.

— Function: illuminant-map->XYZ proc siv

(spectrum->XYZ (illuminant-map proc siv) 300e-9 830e-9)

— Function: spectrum->XYZ proc

proc must be a function of one argument. spectrum->XYZ computes the CIEXYZ(1931) values for the spectrum returned by proc when called with arguments from 380e-9 to 780e-9, the wavelength in meters.

— Function: spectrum->XYZ spectrum x1 x2

x1 and x2 must be positive real numbers specifying the wavelengths (in meters) corresponding to the zeroth and last elements of vector or list spectrum. spectrum->XYZ returns the CIEXYZ(1931) values for a light source with spectral values proportional to the elements of spectrum at evenly spaced wavelengths between x1 and x2.

Compute the colors of 6500.K and 5000.K blackbody radiation:

          (require 'color-space)
          (define xyz (spectrum->XYZ (blackbody-spectrum 6500)))
          (define y_n (cadr xyz))
          (map (lambda (x) (/ x y_n)) xyz)
              ⇒ (0.9687111145512467 1.0 1.1210875945303613)
          
          (define xyz (spectrum->XYZ (blackbody-spectrum 5000)))
          (map (lambda (x) (/ x y_n)) xyz)
              ⇒ (0.2933441826889158 0.2988931825387761 0.25783646831201573)
— Function: spectrum->chromaticity proc
— Function: spectrum->chromaticity spectrum x1 x2

Computes the chromaticity for the given spectrum.

— Function: wavelength->XYZ w

w must be a number between 380e-9 to 780e-9. wavelength->XYZ returns (unnormalized) XYZ values for a monochromatic light source with wavelength w.

— Function: wavelength->chromaticity w

w must be a number between 380e-9 to 780e-9. wavelength->chromaticity returns the chromaticity for a monochromatic light source with wavelength w.

— Function: blackbody-spectrum temp
— Function: blackbody-spectrum temp span

Returns a procedure of one argument (wavelength in meters), which returns the radiance of a black body at temp.

The optional argument span is the wavelength analog of bandwidth. With the default span of 1.nm (1e-9.m), the values returned by the procedure correspond to the power of the photons with wavelengths w to w+1e-9.

— Function: temperature->XYZ x

The positive number x is a temperature in degrees kelvin. temperature->XYZ computes the unnormalized CIEXYZ(1931) values for the spectrum of a black body at temperature x.

Compute the chromaticities of 6500.K and 5000.K blackbody radiation:

          (require 'color-space)
          (XYZ->chromaticity (temperature->XYZ 6500))
              ⇒ (0.3135191660557008 0.3236456786200268)
          
          (XYZ->chromaticity (temperature->XYZ 5000))
              ⇒ (0.34508082841161052 0.3516084965163377)
— Function: temperature->chromaticity x

The positive number x is a temperature in degrees kelvin. temperature->cromaticity computes the chromaticity for the spectrum of a black body at temperature x.

Compute the chromaticities of 6500.K and 5000.K blackbody radiation:

          (require 'color-space)
          (temperature->chromaticity 6500)
              ⇒ (0.3135191660557008 0.3236456786200268)
          
          (temperature->chromaticity 5000)
              ⇒ (0.34508082841161052 0.3516084965163377)
— Function: XYZ->chromaticity xyz

Returns a two element list: the x and y components of xyz normalized to 1 (= x + y + z).

— Function: chromaticity->CIEXYZ x y

Returns the list of x, and y, 1 - y - x.

— Function: chromaticity->whitepoint x y

Returns the CIEXYZ(1931) values having luminosity 1 and chromaticity x and y.

Many color datasets are expressed in xyY format; chromaticity with CIE luminance (Y). But xyY is not a CIE standard like CIEXYZ, CIELAB, and CIELUV. Although chrominance is well defined, the luminance component is sometimes scaled to 1, sometimes to 100, but usually has no obvious range. With no given whitepoint, the only reasonable course is to ascertain the luminance range of a dataset and normalize the values to lie from 0 to 1.

— Function: XYZ->xyY xyz

Returns a three element list: the x and y components of XYZ normalized to 1, and CIE luminance Y.

— Function: xyY->XYZ xyY
— Function: xyY:normalize-colors colors

colors is a list of xyY triples. xyY:normalize-colors scales each chromaticity so it sums to 1 or less; and divides the Y values by the maximum Y in the dataset, so all lie between 0 and 1.

— Function: xyY:normalize-colors colors n

If n is positive real, then xyY:normalize-colors divides the Y values by n times the maximum Y in the dataset.

If n is an exact non-positive integer, then xyY:normalize-colors divides the Y values by the maximum of the Ys in the dataset excepting the -n largest Y values.

In all cases, returned Y values are limited to lie from 0 to 1.

Why would one want to normalize to other than 1? If the sun or its reflection is the brightest object in a scene, then normalizing to its luminance will tend to make the rest of the scene very dark. As with photographs, limiting the specular highlights looks better than darkening everything else.

The results of measurements being what they are, xyY:normalize-colors is extremely tolerant. Negative numbers are replaced with zero, and chromaticities with sums greater than one are scaled to sum to one.