Standard Illuminants & Chromatic Adaptation
Reference light sources used in colorimetry for consistent color measurement and reproduction.
Overview
Standard illuminants define the spectral power distribution (SPD) of light sources. They're essential for:
- Color measurement and specification
- Chromatic adaptation (adjusting colors for different lighting)
- Color matching across devices
- Quality control in manufacturing
- Color rendering index (CRI) calculations
Common CIE Standard Illuminants
D-Series (Daylight)
Represent natural daylight at different color temperatures.
| Illuminant | CCT | $X_n$ | $Y_n$ | $Z_n$ | Description |
|---|---|---|---|---|---|
| D50 | 5003K | 96.42 | 100.0 | 82.51 | Horizon daylight, printing standard |
| D55 | 5503K | 95.68 | 100.0 | 92.15 | Mid-morning/afternoon daylight |
| D65 | 6504K | 95.047 | 100.0 | 108.883 | Noon daylight, sRGB standard |
| D75 | 7504K | 94.97 | 100.0 | 122.64 | North sky daylight |
A-Series (Incandescent)
| Illuminant | CCT | $X_n$ | $Y_n$ | $Z_n$ | Description |
|---|---|---|---|---|---|
| A | 2856K | 109.85 | 100.0 | 35.58 | Tungsten incandescent lamp |
F-Series (Fluorescent)
| Illuminant | CCT | $X_n$ | $Y_n$ | $Z_n$ | Description |
|---|---|---|---|---|---|
| F2 | 4230K | 99.19 | 100.0 | 67.39 | Cool white fluorescent |
| F7 | 6500K | 95.04 | 100.0 | 108.75 | Daylight fluorescent |
| F11 | 4000K | 100.96 | 100.0 | 64.35 | Narrow-band white fluorescent |
E (Equal Energy)
| Illuminant | CCT | $X_n$ | $Y_n$ | $Z_n$ | Description |
|---|---|---|---|---|---|
| E | 5454K | 100.0 | 100.0 | 100.0 | Theoretical equal energy |
Spectral Power Distributions
Illuminant SPDs at 5nm resolution (380-780nm):
xychart-beta
title "CIE Standard Illuminants - Spectral Power Distribution"
x-axis "Wavelength (nm)" [380, 385, 390, 395, 400, 405, 410, 415, 420, 425, 430, 435, 440, 445, 450, 455, 460, 465, 470, 475, 480, 485, 490, 495, 500, 505, 510, 515, 520, 525, 530, 535, 540, 545, 550, 555, 560, 565, 570, 575, 580, 585, 590, 595, 600, 605, 610, 615, 620, 625, 630, 635, 640, 645, 650, 655, 660, 665, 670, 675, 680, 685, 690, 695, 700, 705, 710, 715, 720, 725, 730, 735, 740, 745, 750, 755, 760, 765, 770, 775, 780]
y-axis "Relative Power" 0 --> 140
line "D65 (6504K)" [49.98, 52.31, 54.65, 68.70, 82.75, 87.12, 91.49, 92.46, 93.43, 90.06, 86.68, 95.77, 104.86, 110.94, 117.01, 117.41, 117.81, 116.34, 114.86, 115.39, 115.92, 112.37, 108.81, 109.08, 109.35, 108.58, 107.80, 106.30, 104.79, 106.24, 107.69, 106.05, 104.41, 104.23, 104.05, 102.02, 100.00, 98.17, 96.33, 96.06, 95.79, 92.24, 88.69, 89.35, 90.01, 89.80, 89.60, 88.65, 87.70, 85.49, 83.29, 83.49, 83.70, 81.86, 80.03, 80.12, 80.21, 81.25, 82.28, 80.28, 78.28, 74.00, 69.72, 70.67, 71.61, 72.98, 74.35, 67.98, 61.60, 65.74, 69.89, 72.49, 75.09, 69.34, 63.59, 55.01, 46.42, 56.61, 66.81, 65.09, 63.38]
line "D50 (5003K)" [24.49, 27.18, 29.87, 39.59, 49.32, 52.91, 56.51, 58.27, 60.04, 58.93, 57.82, 66.32, 74.82, 81.04, 87.26, 88.93, 90.61, 90.99, 91.37, 93.24, 95.11, 93.54, 91.97, 93.84, 95.72, 96.17, 96.62, 96.87, 97.13, 99.61, 102.09, 101.43, 100.78, 101.54, 102.30, 101.16, 100.00, 98.87, 97.74, 98.33, 98.93, 96.21, 93.50, 95.59, 97.69, 98.48, 99.27, 99.16, 99.04, 97.38, 95.72, 97.29, 98.86, 97.70, 96.54, 97.48, 98.42, 100.00, 101.58, 100.75, 99.92, 97.13, 94.35, 96.90, 99.45, 102.02, 104.58, 99.19, 93.80, 98.81, 103.82, 107.69, 111.55, 106.86, 102.16, 91.99, 81.83, 98.82, 115.80, 115.39, 114.98]
line "A (2856K)" [9.80, 10.90, 12.09, 13.35, 14.71, 16.15, 17.68, 19.29, 20.99, 22.79, 24.67, 26.64, 28.70, 30.85, 33.09, 35.41, 37.81, 40.30, 42.87, 45.52, 48.24, 51.04, 53.91, 56.85, 59.86, 62.93, 66.06, 69.25, 72.50, 75.80, 79.15, 82.55, 86.00, 89.49, 93.02, 96.59, 100.00, 103.83, 107.69, 111.57, 115.47, 119.36, 123.27, 127.18, 131.09, 135.00, 138.90, 142.79, 146.67, 150.54, 154.38, 158.21, 162.02, 165.80, 169.55, 173.27, 176.97, 180.63, 184.25, 187.84, 191.38, 194.89, 198.35, 201.77, 205.14, 208.46, 211.74, 214.97, 218.15, 221.28, 224.36, 227.39, 230.36, 233.28, 236.15, 238.96, 241.72, 244.42, 247.07, 249.66, 252.19]Color Temperature (CCT)
Correlated Color Temperature is measured in Kelvin (K):
- < 3000K: Warm (yellowish) - Candles, incandescent
- 3000-5000K: Neutral - Fluorescent, morning sun
- > 5000K: Cool (bluish) - Daylight, overcast sky
Approximation Formula
For Planckian radiators (blackbody):
$$ \text{CCT} \approx -449n^3 + 3525n^2 - 6823.3n + 5520.33 $$Where $n = \frac{x - 0.3320}{y - 0.1858}$ and $(x, y)$ are chromaticity coordinates.
Chromatic Adaptation
When converting colors between different illuminants, chromatic adaptation is needed.
Bradford Transform (Most Accurate)
The Bradford transform converts XYZ values from one illuminant to another through a cone response domain (LMS):
Step 1: Convert XYZ to cone response (LMS)
$$ \begin{bmatrix} L \\\\ M \\\\ S \end{bmatrix} = \mathbf{M}_{\text{Bradford}} \cdot \begin{bmatrix} X \\\\ Y \\\\ Z \end{bmatrix} $$Step 2: Scale cone responses
$$ \begin{bmatrix} L' \\\\ M' \\\\ S' \end{bmatrix} = \begin{bmatrix} \frac{L_{\text{dest}}}{L_{\text{src}}} & 0 & 0 \\\\ 0 & \frac{M_{\text{dest}}}{M_{\text{src}}} & 0 \\\\ 0 & 0 & \frac{S_{\text{dest}}}{S_{\text{src}}} \end{bmatrix} \cdot \begin{bmatrix} L \\\\ M \\\\ S \end{bmatrix} $$Step 3: Convert back to XYZ
$$ \begin{bmatrix} X' \\\\ Y' \\\\ Z' \end{bmatrix} = \mathbf{M}_{\text{Bradford}}^{-1} \cdot \begin{bmatrix} L' \\\\ M' \\\\ S' \end{bmatrix} $$Where:
$$ \mathbf{M}_{\text{Bradford}} = \begin{bmatrix} 0.8951 & 0.2664 & -0.1614 \\\\ -0.7502 & 1.7135 & 0.0367 \\\\ 0.0389 & -0.0685 & 1.0296 \end{bmatrix} $$Color Rendering Index (CRI)
CRI measures how accurately a light source renders colors compared to a reference illuminant of the same CCT (a Planckian radiator below 5000K, CIE daylight at or above 5000K).
CRI Calculation Method
Step 1: Select 8 test color samples (TCS01-TCS08)
These are standardized Munsell color samples covering the hue circle.
Step 2: Calculate tristimulus values under test and reference illuminants
For each test sample $i$:
$$ X_i^{\text{test}}, Y_i^{\text{test}}, Z_i^{\text{test}} = \int S_{\text{test}}(\lambda) R_i(\lambda) \bar{x}(\lambda) d\lambda, \ldots $$$$ X_i^{\text{ref}}, Y_i^{\text{ref}}, Z_i^{\text{ref}} = \int S_{\text{ref}}(\lambda) R_i(\lambda) \bar{x}(\lambda) d\lambda, \ldots $$Step 3: Convert to CIE 1960 UCS (u, v) coordinates
$$ u = \frac{4X}{X + 15Y + 3Z} $$$$ v = \frac{6Y}{X + 15Y + 3Z} $$Step 4: Apply chromatic adaptation
Adapt test illuminant colors to reference illuminant using the von Kries transform in CIE 1960 $(c, d)$ space, with $c = (4 - u - 10v)/v$ and $d = (1.708v + 0.404 - 1.481u)/v$. Each illuminant is normalized so its white has $Y = 100$, and each uses its own white point.
Step 5: Convert to CIE 1964 WUV* color space
$$ W^* = 25Y^{1/3} - 17 $$$$ U^* = 13W^*(u - u_n) $$$$ V^* = 13W^*(v - v_n) $$Step 6: Calculate color difference for each sample
$$ \Delta E_i = \sqrt{(U^*_{test} - U^*_{ref})^2 + (V^*_{test} - V^*_{ref})^2 + (W^*_{test} - W^*_{ref})^2} $$Step 7: Calculate special color rendering index for each sample
$$ R_i = 100 - 4.6\Delta E_i $$Step 8: Calculate general CRI (Ra)
$$ \text{CRI (Ra)} = \frac{1}{8}\sum_{i=1}^{8} R_i $$CRI Interpretation
- CRI > 90: Excellent (museum, art gallery, medical)
- CRI 80-90: Good (home, office, retail)
- CRI 70-80: Fair (industrial, outdoor)
- CRI < 70: Poor (street lighting, parking)
Python Implementation
1import numpy as np
2
3def calculate_cri_single_sample(spd_test, spd_ref, reflectance, cmf_x, cmf_y, cmf_z, wavelengths):
4 """
5 Calculate CRI for a single test color sample
6
7 Parameters:
8 - spd_test: Test illuminant SPD
9 - spd_ref: Reference illuminant SPD (Planckian at test CCT if < 5000K, else CIE daylight)
10 - reflectance: Test color sample reflectance
11 - cmf_x, cmf_y, cmf_z: CIE 1931 color matching functions
12 - wavelengths: Wavelength array
13
14 Returns:
15 - R_i: Special color rendering index for this sample
16 """
17 delta_lambda = wavelengths[1] - wavelengths[0]
18
19 def xyz(spd, refl):
20 return np.array([np.sum(spd * refl * cmf) for cmf in (cmf_x, cmf_y, cmf_z)]) * delta_lambda
21
22 # Normalize each illuminant so its own white has Y = 100
23 white_test = xyz(spd_test, 1.0)
24 white_ref = xyz(spd_ref, 1.0)
25 sample_test = xyz(spd_test, reflectance) * 100 / white_test[1]
26 sample_ref = xyz(spd_ref, reflectance) * 100 / white_ref[1]
27
28 # Convert to CIE 1960 UCS
29 def xyz_to_uv(X, Y, Z):
30 denom = X + 15*Y + 3*Z
31 return 4*X / denom, 6*Y / denom
32
33 def uv_to_cd(u, v):
34 return (4 - u - 10*v) / v, (1.708*v + 0.404 - 1.481*u) / v
35
36 u_t, v_t = xyz_to_uv(*white_test)
37 u_r, v_r = xyz_to_uv(*white_ref)
38 u_i, v_i = xyz_to_uv(*sample_test)
39 u_ri, v_ri = xyz_to_uv(*sample_ref)
40
41 # Von Kries adaptation of the test sample to the reference white
42 c_t, d_t = uv_to_cd(u_t, v_t)
43 c_r, d_r = uv_to_cd(u_r, v_r)
44 c_i, d_i = uv_to_cd(u_i, v_i)
45 cc = c_r / c_t * c_i
46 dd = d_r / d_t * d_i
47 denom = 16.518 + 1.481*cc - dd
48 u_ti = (10.872 + 0.404*cc - 4*dd) / denom
49 v_ti = 5.520 / denom
50
51 # Convert to W*U*V* (both relative to the reference white after adaptation)
52 def uv_to_wuv(u, v, Y, u_n, v_n):
53 W = 25 * (Y ** (1/3)) - 17
54 U = 13 * W * (u - u_n)
55 V = 13 * W * (v - v_n)
56 return W, U, V
57
58 W_test, U_test, V_test = uv_to_wuv(u_ti, v_ti, sample_test[1], u_r, v_r)
59 W_ref, U_ref, V_ref = uv_to_wuv(u_ri, v_ri, sample_ref[1], u_r, v_r)
60
61 # Calculate color difference
62 delta_E = np.sqrt((U_test - U_ref)**2 + (V_test - V_ref)**2 + (W_test - W_ref)**2)
63
64 # Calculate special CRI
65 R_i = 100 - 4.6 * delta_E
66
67 return R_i
68
69def calculate_cri(spd_test, spd_ref, tcs_reflectances, cmf_x, cmf_y, cmf_z, wavelengths):
70 """
71 Calculate general CRI (Ra) using 8 test color samples
72
73 Parameters:
74 - spd_test: Test illuminant SPD
75 - spd_ref: Reference illuminant SPD
76 - tcs_reflectances: List of 8 TCS reflectance spectra
77 - cmf_x, cmf_y, cmf_z: Color matching functions
78 - wavelengths: Wavelength array
79
80 Returns:
81 - Ra: General color rendering index (average of 8 samples)
82 """
83 R_values = []
84
85 for i, reflectance in enumerate(tcs_reflectances[:8]):
86 R_i = calculate_cri_single_sample(
87 spd_test, spd_ref, reflectance,
88 cmf_x, cmf_y, cmf_z, wavelengths
89 )
90 R_values.append(R_i)
91
92 # General CRI is the average of 8 special indices
93 Ra = np.mean(R_values)
94
95 return Ra
96
97# Example usage:
98# wavelengths = np.arange(380, 781, 5) # 5nm resolution
99# spd_test = load_spd("test_led.csv")
100# spd_ref = load_spd("reference_at_test_cct.csv") # Planckian (< 5000K) or CIE daylight
101# tcs_reflectances = load_tcs_samples() # Load 8 TCS samples
102# cmf_x, cmf_y, cmf_z = load_cmf()
103#
104# cri = calculate_cri(spd_test, spd_ref, tcs_reflectances, cmf_x, cmf_y, cmf_z, wavelengths)
105# print(f"CRI (Ra): {cri:.1f}")
Practical Implementation
Python
1import numpy as np
2
3# Standard illuminants (2° observer, normalized to Y=100)
4ILLUMINANTS = {
5 'A': np.array([109.850, 100.0, 35.585]),
6 'D50': np.array([96.422, 100.0, 82.521]),
7 'D55': np.array([95.682, 100.0, 92.149]),
8 'D65': np.array([95.047, 100.0, 108.883]),
9 'D75': np.array([94.972, 100.0, 122.638]),
10 'E': np.array([100.0, 100.0, 100.0]),
11 'F2': np.array([99.186, 100.0, 67.393]),
12 'F7': np.array([95.041, 100.0, 108.747]),
13 'F11': np.array([100.962, 100.0, 64.350]),
14}
15
16def get_illuminant(name='D65'):
17 """Get XYZ values for a standard illuminant"""
18 return ILLUMINANTS.get(name.upper(), ILLUMINANTS['D65'])
19
20# Bradford chromatic adaptation matrix
21BRADFORD = np.array([
22 [ 0.8951, 0.2664, -0.1614],
23 [-0.7502, 1.7135, 0.0367],
24 [ 0.0389, -0.0685, 1.0296]
25])
26
27BRADFORD_INV = np.linalg.inv(BRADFORD)
28
29def chromatic_adaptation(xyz, src_illuminant='D65', dst_illuminant='D50'):
30 """
31 Adapt XYZ color from one illuminant to another using Bradford transform
32 """
33 src_white = get_illuminant(src_illuminant)
34 dst_white = get_illuminant(dst_illuminant)
35
36 # Convert whites to cone response domain (LMS)
37 src_lms = BRADFORD @ src_white
38 dst_lms = BRADFORD @ dst_white
39
40 # Convert color to LMS
41 color_lms = BRADFORD @ xyz
42
43 # Scale factors
44 scale = dst_lms / src_lms
45
46 # Apply scaling
47 adapted_lms = scale * color_lms
48
49 # Convert back to XYZ
50 xyz_adapted = BRADFORD_INV @ adapted_lms
51
52 return xyz_adapted
Go
1package color
2
3var Illuminants = map[string]XYZ{
4 "A": {109.850, 100.0, 35.585},
5 "D50": {96.422, 100.0, 82.521},
6 "D55": {95.682, 100.0, 92.149},
7 "D65": {95.047, 100.0, 108.883},
8 "D75": {94.972, 100.0, 122.638},
9 "E": {100.0, 100.0, 100.0},
10 "F2": {99.186, 100.0, 67.393},
11 "F7": {95.041, 100.0, 108.747},
12 "F11": {100.962, 100.0, 64.350},
13}
14
15func GetIlluminant(name string) XYZ {
16 if ill, ok := Illuminants[name]; ok {
17 return ill
18 }
19 return Illuminants["D65"] // Default
20}
Use Cases by Illuminant
D65
- sRGB, Adobe RGB: Standard for computer displays
- HDTV: Broadcast standard
- Photography: Digital camera white balance "daylight"
D50
- Printing: ICC profile connection space
- ProPhoto RGB: Wide-gamut color space
- Color management: Industry standard for graphic arts
A
- Photography: Tungsten/incandescent white balance
- Testing: Simulating indoor lighting
- Color rendering index: Reference for warm lighting
F-Series
- Retail: Simulating store lighting
- Office: Fluorescent lighting conditions
- Color rendering: Testing under artificial light
Important Notes
- Always specify the illuminant when measuring or specifying colors
- D65 is most common for digital imaging and displays
- D50 is standard for print and graphic arts
- Chromatic adaptation is necessary when converting between illuminants
- Observer angle (2° or 10°) also affects XYZ values
- CRI is illuminant-specific - always compare against appropriate reference
Further Reading
- Standard Illuminant - Wikipedia
- CIE Illuminants
- Bruce Lindbloom's Chromatic Adaptation
- Color Rendering Index - CIE 13.3
Related Snippets
- CIE LAB Color Space
Perceptually uniform color space for color difference calculations - CIE XYZ Color Space
Device-independent color representation based on human vision - Color Difference Formulas
Delta E and perceptual color distance calculations - Color Space Conversions - Quick Reference
Quick reference for all color space conversion formulas - HSV/HSL Color Spaces
Intuitive color representations for user interfaces and color pickers - RGB Color Space & Gamma Correction
sRGB color model and gamma encoding/decoding formulas