Coverage for colour/temperature/kang2002.py: 100%
40 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-15 19:01 +1300
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-15 19:01 +1300
1"""
2Kang, Moon, Hong, Lee, Cho and Kim (2002) Correlated Colour Temperature
3=======================================================================
5Define the *Kang et al. (2002)* correlated colour temperature :math:`T_{cp}`
6computation objects.
8- :func:`colour.temperature.xy_to_CCT_Kang2002`: Compute correlated colour
9 temperature :math:`T_{cp}` from specified *CIE xy* chromaticity
10 coordinates using the *Kang, Moon, Hong, Lee, Cho and Kim (2002)* method.
11- :func:`colour.temperature.CCT_to_xy_Kang2002`: Compute *CIE xy*
12 chromaticity coordinates from specified correlated colour temperature
13 :math:`T_{cp}` using the *Kang, Moon, Hong, Lee, Cho and Kim (2002)*
14 method.
16References
17----------
18- :cite:`Kang2002a` : Kang, B., Moon, O., Hong, C., Lee, H., Cho, B., & Kim,
19 Y. (2002). Design of advanced color: Temperature control system for HDTV
20 applications. Journal of the Korean Physical Society, 41(6), 865-871.
21"""
23from __future__ import annotations
25import typing
27import numpy as np
29if typing.TYPE_CHECKING:
30 from colour.hints import ArrayLike, DTypeFloat, NDArrayFloat
32from colour.utilities import as_float, as_float_array, required, tstack, usage_warning
34__author__ = "Colour Developers"
35__copyright__ = "Copyright 2013 Colour Developers"
36__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
37__maintainer__ = "Colour Developers"
38__email__ = "colour-developers@colour-science.org"
39__status__ = "Production"
41__all__ = [
42 "xy_to_CCT_Kang2002",
43 "CCT_to_xy_Kang2002",
44]
47@required("SciPy")
48def xy_to_CCT_Kang2002(
49 xy: ArrayLike, optimisation_kwargs: dict | None = None
50) -> NDArrayFloat:
51 """
52 Compute the correlated colour temperature :math:`T_{cp}` from the
53 specified *CIE xy* chromaticity coordinates using *Kang et al. (2002)*
54 method.
56 Parameters
57 ----------
58 xy
59 *CIE xy* chromaticity coordinates.
60 optimisation_kwargs
61 Parameters for :func:`scipy.optimize.minimize` definition.
63 Returns
64 -------
65 :class:`numpy.ndarray`
66 Correlated colour temperature :math:`T_{cp}`.
68 Warnings
69 --------
70 The *Kang et al. (2002)* method does not provide an analytical inverse
71 transformation to compute the correlated colour temperature
72 :math:`T_{cp}` from the specified *CIE xy* chromaticity coordinates.
73 The current implementation relies on optimisation using
74 :func:`scipy.optimize.minimize` definition and thus has reduced
75 precision and poor performance.
77 References
78 ----------
79 :cite:`Kang2002a`
81 Examples
82 --------
83 >>> xy_to_CCT_Kang2002(np.array([0.31342600, 0.32359597]))
84 ... # doctest: +ELLIPSIS
85 6504.3893128...
86 """
88 from scipy.optimize import minimize # noqa: PLC0415
90 xy = as_float_array(xy)
91 shape = xy.shape
92 xy = np.atleast_1d(np.reshape(xy, (-1, 2)))
94 def objective_function(CCT: NDArrayFloat, xy: NDArrayFloat) -> DTypeFloat:
95 """Objective function."""
97 objective = np.linalg.norm(CCT_to_xy_Kang2002(CCT) - xy)
99 return as_float(objective)
101 optimisation_settings = {
102 "method": "Nelder-Mead",
103 "options": {
104 "fatol": 1e-10,
105 },
106 }
107 if optimisation_kwargs is not None:
108 optimisation_settings.update(optimisation_kwargs)
110 CCT = as_float_array(
111 [
112 minimize(
113 objective_function,
114 x0=[6500],
115 args=(xy_i,),
116 **optimisation_settings,
117 ).x
118 for xy_i in xy
119 ]
120 )
122 return as_float(np.reshape(CCT, shape[:-1]))
125def CCT_to_xy_Kang2002(CCT: ArrayLike) -> NDArrayFloat:
126 """
127 Compute the *CIE xy* chromaticity coordinates from the specified
128 correlated colour temperature :math:`T_{cp}` using *Kang et al. (2002)*
129 method.
131 Parameters
132 ----------
133 CCT
134 Correlated colour temperature :math:`T_{cp}`.
136 Returns
137 -------
138 :class:`numpy.ndarray`
139 *CIE xy* chromaticity coordinates.
141 Raises
142 ------
143 ValueError
144 If the correlated colour temperature is not in appropriate domain.
146 References
147 ----------
148 :cite:`Kang2002a`
150 Examples
151 --------
152 >>> CCT_to_xy_Kang2002(6504.38938305) # doctest: +ELLIPSIS
153 array([ 0.313426 ..., 0.3235959...])
154 """
156 CCT = as_float_array(CCT)
158 if np.any(CCT[np.asarray(np.logical_or(CCT < 1667, CCT > 25000))]):
159 usage_warning(
160 "Correlated colour temperature must be in domain "
161 "[1667, 25000], unpredictable results may occur!"
162 )
164 CCT_3 = CCT**3
165 CCT_2 = CCT**2
167 x = np.where(
168 CCT <= 4000,
169 -0.2661239 * 10**9 / CCT_3
170 - 0.2343589 * 10**6 / CCT_2
171 + 0.8776956 * 10**3 / CCT
172 + 0.179910,
173 -3.0258469 * 10**9 / CCT_3
174 + 2.1070379 * 10**6 / CCT_2
175 + 0.2226347 * 10**3 / CCT
176 + 0.24039,
177 )
179 x_3 = x**3
180 x_2 = x**2
182 cnd_l = [CCT <= 2222, np.logical_and(CCT > 2222, CCT <= 4000), CCT > 4000]
183 i = -1.1063814 * x_3 - 1.34811020 * x_2 + 2.18555832 * x - 0.20219683
184 j = -0.9549476 * x_3 - 1.37418593 * x_2 + 2.09137015 * x - 0.16748867
185 k = 3.0817580 * x_3 - 5.8733867 * x_2 + 3.75112997 * x - 0.37001483
186 y = np.select(cnd_l, [i, j, k])
188 return tstack([x, y])