Coverage for temperature/mccamy1992.py: 53%
34 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"""
2McCamy (1992) Correlated Colour Temperature
3===========================================
5Define the *McCamy (1992)* correlated colour temperature :math:`T_{cp}`
6computation objects.
8- :func:`colour.temperature.xy_to_CCT_McCamy1992`: Compute correlated
9 colour temperature :math:`T_{cp}` from specified *CIE xy* chromaticity
10 coordinates using the *McCamy (1992)* method.
11- :func:`colour.temperature.CCT_to_xy_McCamy1992`: Compute *CIE xy*
12 chromaticity coordinates from specified correlated colour temperature
13 :math:`T_{cp}` using the *McCamy (1992)* method.
15References
16----------
17- :cite:`Wikipedia2001` : Wikipedia. (2001). Approximation. Retrieved June
18 28, 2014, from http://en.wikipedia.org/wiki/Color_temperature#Approximation
19"""
21from __future__ import annotations
23import typing
25import numpy as np
27from colour.algebra import sdiv, sdiv_mode
28from colour.colorimetry import CCS_ILLUMINANTS
30if typing.TYPE_CHECKING:
31 from colour.hints import ArrayLike, DTypeFloat, NDArrayFloat
33from colour.utilities import as_float, as_float_array, required, tsplit, usage_warning
35__author__ = "Colour Developers"
36__copyright__ = "Copyright 2013 Colour Developers"
37__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
38__maintainer__ = "Colour Developers"
39__email__ = "colour-developers@colour-science.org"
40__status__ = "Production"
42__all__ = [
43 "xy_to_CCT_McCamy1992",
44 "CCT_to_xy_McCamy1992",
45]
48@required("SciPy")
49def xy_to_CCT_McCamy1992(xy: ArrayLike) -> NDArrayFloat:
50 """
51 Compute the correlated colour temperature :math:`T_{cp}` from the
52 specified *CIE xy* chromaticity coordinates using the *McCamy (1992)*
53 method.
55 Parameters
56 ----------
57 xy
58 *CIE xy* chromaticity coordinates.
60 Returns
61 -------
62 :class:`numpy.ndarray`
63 Correlated colour temperature :math:`T_{cp}`.
65 References
66 ----------
67 :cite:`Wikipedia2001`
69 Examples
70 --------
71 >>> import numpy as np
72 >>> xy = np.array([0.31270, 0.32900])
73 >>> xy_to_CCT_McCamy1992(xy) # doctest: +ELLIPSIS
74 6505.0805913...
75 """
77 x, y = tsplit(xy)
79 with sdiv_mode():
80 n = sdiv(x - 0.3320, y - 0.1858)
82 CCT = -449 * n**3 + 3525 * n**2 - 6823.3 * n + 5520.33
84 return as_float(CCT)
87def CCT_to_xy_McCamy1992(
88 CCT: ArrayLike, optimisation_kwargs: dict | None = None
89) -> NDArrayFloat:
90 """
91 Compute the *CIE xy* chromaticity coordinates from the specified
92 correlated colour temperature :math:`T_{cp}` using the *McCamy (1992)*
93 method.
95 Parameters
96 ----------
97 CCT
98 Correlated colour temperature :math:`T_{cp}`.
99 optimisation_kwargs
100 Parameters for :func:`scipy.optimize.minimize` definition.
102 Returns
103 -------
104 :class:`numpy.ndarray`
105 *CIE xy* chromaticity coordinates.
107 Warnings
108 --------
109 The *McCamy (1992)* method for computing *CIE xy* chromaticity coordinates
110 from the specified correlated colour temperature is not a bijective
111 function and might produce unexpected results. It is provided for
112 consistency with other correlated colour temperature computation methods
113 but should be avoided for practical applications. The current
114 implementation relies on optimisation using
115 :func:`scipy.optimize.minimize` definition and thus has reduced precision
116 and poor performance.
118 References
119 ----------
120 :cite:`Wikipedia2001`
122 Examples
123 --------
124 >>> CCT_to_xy_McCamy1992(6505.0805913074782) # doctest: +ELLIPSIS
125 array([ 0.3127..., 0.329...])
126 """
128 from scipy.optimize import minimize # noqa: PLC0415
130 usage_warning(
131 '"McCamy (1992)" method for computing "CIE xy" chromaticity '
132 "coordinates from given correlated colour temperature is not a "
133 "bijective function and might produce unexpected results. It is given "
134 "for consistency with other correlated colour temperature computation "
135 "methods but should be avoided for practical applications."
136 )
138 CCT = as_float_array(CCT)
139 shape = list(CCT.shape)
140 CCT = np.atleast_1d(np.reshape(CCT, (-1, 1)))
142 def objective_function(xy: NDArrayFloat, CCT: NDArrayFloat) -> DTypeFloat:
143 """Objective function."""
145 objective = np.linalg.norm(xy_to_CCT_McCamy1992(xy) - CCT)
147 return as_float(objective)
149 optimisation_settings = {
150 "method": "Nelder-Mead",
151 "options": {
152 "fatol": 1e-10,
153 },
154 }
155 if optimisation_kwargs is not None:
156 optimisation_settings.update(optimisation_kwargs)
158 xy = as_float_array(
159 [
160 minimize(
161 objective_function,
162 x0=CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"]["D65"],
163 args=(CCT_i,),
164 **optimisation_settings,
165 ).x
166 for CCT_i in CCT
167 ]
168 )
170 return np.reshape(xy, ([*shape, 2]))