Coverage for temperature/cie_d.py: 57%
35 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 22:49 +1300
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 22:49 +1300
1"""
2CIE Illuminant D Series Correlated Colour Temperature
3=====================================================
5Define the *CIE Illuminant D Series* correlated colour temperature
6:math:`T_{cp}` computation objects.
8- :func:`colour.temperature.xy_to_CCT_CIE_D`: Compute correlated colour
9 temperature :math:`T_{cp}` of a *CIE Illuminant D Series* from its
10 *CIE xy* chromaticity coordinates.
11- :func:`colour.temperature.CCT_to_xy_CIE_D`: Compute *CIE xy*
12 chromaticity coordinates of a *CIE Illuminant D Series* from its
13 correlated colour temperature :math:`T_{cp}`.
15References
16----------
17- :cite:`Wyszecki2000z` : Wyszecki, Günther, & Stiles, W. S. (2000). CIE
18 Method of Calculating D-Illuminants. In Color Science: Concepts and
19 Methods, Quantitative Data and Formulae (pp. 145-146). Wiley.
20 ISBN:978-0-471-39918-6
21"""
23from __future__ import annotations
25import typing
27import numpy as np
29from colour.colorimetry import daylight_locus_function
31if typing.TYPE_CHECKING:
32 from colour.hints import ArrayLike, DTypeFloat, NDArrayFloat
34from colour.utilities import as_float, as_float_array, required, tstack, usage_warning
36__author__ = "Colour Developers"
37__copyright__ = "Copyright 2013 Colour Developers"
38__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
39__maintainer__ = "Colour Developers"
40__email__ = "colour-developers@colour-science.org"
41__status__ = "Production"
43__all__ = [
44 "xy_to_CCT_CIE_D",
45 "CCT_to_xy_CIE_D",
46]
49@required("SciPy")
50def xy_to_CCT_CIE_D(
51 xy: ArrayLike, optimisation_kwargs: dict | None = None
52) -> NDArrayFloat:
53 """
54 Compute the correlated colour temperature :math:`T_{cp}` of a
55 *CIE Illuminant D Series* from the specified *CIE xy* chromaticity
56 coordinates.
58 Parameters
59 ----------
60 xy
61 *CIE xy* chromaticity coordinates.
62 optimisation_kwargs
63 Parameters for :func:`scipy.optimize.minimize` definition.
65 Returns
66 -------
67 :class:`numpy.ndarray`
68 Correlated colour temperature :math:`T_{cp}`.
70 Warnings
71 --------
72 The *CIE Illuminant D Series* method does not provide an analytical inverse
73 transformation to compute the correlated colour temperature :math:`T_{cp}`
74 from the specified *CIE xy* chromaticity coordinates. The current
75 implementation relies on optimisation using :func:`scipy.optimize.minimize`
76 definition and thus has reduced precision and poor performance.
78 References
79 ----------
80 :cite:`Wyszecki2000z`
82 Examples
83 --------
84 >>> xy_to_CCT_CIE_D(np.array([0.31270775, 0.32911283]))
85 ... # doctest: +ELLIPSIS
86 6504.3895840...
87 """
89 from scipy.optimize import minimize # noqa: PLC0415
91 xy = as_float_array(xy)
92 shape = xy.shape
93 xy = np.atleast_1d(np.reshape(xy, (-1, 2)))
95 def objective_function(CCT: NDArrayFloat, xy: NDArrayFloat) -> DTypeFloat:
96 """Objective function."""
98 objective = np.linalg.norm(CCT_to_xy_CIE_D(CCT) - xy)
100 return as_float(objective)
102 optimisation_settings = {
103 "method": "Nelder-Mead",
104 "options": {
105 "fatol": 1e-10,
106 },
107 }
108 if optimisation_kwargs is not None:
109 optimisation_settings.update(optimisation_kwargs)
111 CCT = as_float_array(
112 [
113 minimize(
114 objective_function,
115 x0=[6500],
116 args=(xy_i,),
117 **optimisation_settings,
118 ).x
119 for xy_i in xy
120 ]
121 )
123 return as_float(np.reshape(CCT, shape[:-1]))
126def CCT_to_xy_CIE_D(CCT: ArrayLike) -> NDArrayFloat:
127 """
128 Compute the *CIE xy* chromaticity coordinates of a
129 *CIE Illuminant D Series* from the specified correlated colour temperature
130 :math:`T_{cp}`.
132 Parameters
133 ----------
134 CCT
135 Correlated colour temperature :math:`T_{cp}`.
137 Returns
138 -------
139 :class:`numpy.ndarray`
140 *CIE xy* chromaticity coordinates.
142 Raises
143 ------
144 ValueError
145 If the correlated colour temperature is not in the appropriate
146 domain.
148 References
149 ----------
150 :cite:`Wyszecki2000z`
152 Examples
153 --------
154 >>> CCT_to_xy_CIE_D(6504.38938305) # doctest: +ELLIPSIS
155 array([ 0.3127077..., 0.3291128...])
156 """
158 CCT = as_float_array(CCT)
160 if np.any(CCT[np.asarray(np.logical_or(CCT < 4000, CCT > 25000))]):
161 usage_warning(
162 "Correlated colour temperature must be in domain "
163 "[4000, 25000], unpredictable results may occur!"
164 )
166 CCT_3 = CCT**3
167 CCT_2 = CCT**2
169 x = as_float(
170 np.where(
171 CCT <= 7000,
172 -4.607 * 10**9 / CCT_3
173 + 2.9678 * 10**6 / CCT_2
174 + 0.09911 * 10**3 / CCT
175 + 0.244063,
176 -2.0064 * 10**9 / CCT_3
177 + 1.9018 * 10**6 / CCT_2
178 + 0.24748 * 10**3 / CCT
179 + 0.23704,
180 )
181 )
183 y = daylight_locus_function(x)
185 return tstack([x, y])