Coverage for colour/models/cie_ucs.py: 100%
50 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"""
2CIE 1960 UCS Colourspace
3========================
5Define the *CIE 1960 UCS* colourspace transformations.
7- :func:`colour.XYZ_to_UCS`
8- :func:`colour.UCS_to_XYZ`
9- :func:`colour.UCS_to_uv`
10- :func:`colour.uv_to_UCS`
11- :func:`colour.UCS_uv_to_xy`
12- :func:`colour.xy_to_UCS_uv`
13- :func:`colour.XYZ_to_CIE1960UCS`
14- :func:`colour.CIE1960UCS_to_XYZ`
16References
17----------
18- :cite:`Wikipedia2008` : Wikipedia. (2008). CIE 1960 color space. Retrieved
19 February 24, 2014, from http://en.wikipedia.org/wiki/CIE_1960_color_space
20- :cite:`Wikipedia2008c` : Wikipedia. (2008). Relation to CIE XYZ. Retrieved
21 February 24, 2014, from
22 http://en.wikipedia.org/wiki/CIE_1960_color_space#Relation_to_CIE_XYZ
23"""
25from __future__ import annotations
27import numpy as np
29from colour.algebra import sdiv, sdiv_mode
30from colour.hints import ( # noqa: TC001
31 ArrayLike,
32 Domain1,
33 NDArrayFloat,
34 Range1,
35)
36from colour.utilities import from_range_1, to_domain_1, tsplit, tstack
38__author__ = "Colour Developers"
39__copyright__ = "Copyright 2013 Colour Developers"
40__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
41__maintainer__ = "Colour Developers"
42__email__ = "colour-developers@colour-science.org"
43__status__ = "Production"
45__all__ = [
46 "XYZ_to_UCS",
47 "UCS_to_XYZ",
48 "UCS_to_uv",
49 "uv_to_UCS",
50 "UCS_uv_to_xy",
51 "xy_to_UCS_uv",
52 "XYZ_to_CIE1960UCS",
53 "CIE1960UCS_to_XYZ",
54]
57def XYZ_to_UCS(XYZ: Domain1) -> Range1:
58 """
59 Convert from *CIE XYZ* tristimulus values to *CIE 1960 UCS* :math:`UVW`
60 colourspace.
62 Parameters
63 ----------
64 XYZ
65 *CIE XYZ* tristimulus values.
67 Returns
68 -------
69 :class:`numpy.ndarray`
70 *CIE 1960 UCS* :math:`UVW` colourspace array.
72 Notes
73 -----
74 +------------+-----------------------+---------------+
75 | **Domain** | **Scale - Reference** | **Scale - 1** |
76 +============+=======================+===============+
77 | ``XYZ`` | 1 | 1 |
78 +------------+-----------------------+---------------+
80 +------------+-----------------------+---------------+
81 | **Range** | **Scale - Reference** | **Scale - 1** |
82 +============+=======================+===============+
83 | ``UVW`` | 1 | 1 |
84 +------------+-----------------------+---------------+
86 References
87 ----------
88 :cite:`Wikipedia2008c`, :cite:`Wikipedia2008`
90 Examples
91 --------
92 >>> import numpy as np
93 >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952])
94 >>> XYZ_to_UCS(XYZ) # doctest: +ELLIPSIS
95 array([ 0.1376933..., 0.1219722..., 0.1053731...])
96 """
98 X, Y, Z = tsplit(to_domain_1(XYZ))
100 UVW = tstack([2 / 3 * X, Y, 1 / 2 * (-X + 3 * Y + Z)])
102 return from_range_1(UVW)
105def UCS_to_XYZ(UVW: Domain1) -> Range1:
106 """
107 Convert from *CIE 1960 UCS* :math:`UVW` colourspace to *CIE XYZ*
108 tristimulus values.
110 Parameters
111 ----------
112 UVW
113 *CIE 1960 UCS* :math:`UVW` colourspace array.
115 Returns
116 -------
117 :class:`numpy.ndarray`
118 *CIE XYZ* tristimulus values.
120 Notes
121 -----
122 +------------+-----------------------+---------------+
123 | **Domain** | **Scale - Reference** | **Scale - 1** |
124 +============+=======================+===============+
125 | ``UVW`` | 1 | 1 |
126 +------------+-----------------------+---------------+
128 +------------+-----------------------+---------------+
129 | **Range** | **Scale - Reference** | **Scale - 1** |
130 +============+=======================+===============+
131 | ``XYZ`` | 1 | 1 |
132 +------------+-----------------------+---------------+
134 References
135 ----------
136 :cite:`Wikipedia2008c`, :cite:`Wikipedia2008`
138 Examples
139 --------
140 >>> import numpy as np
141 >>> UVW = np.array([0.13769339, 0.12197225, 0.10537310])
142 >>> UCS_to_XYZ(UVW) # doctest: +ELLIPSIS
143 array([ 0.2065400..., 0.1219722..., 0.0513695...])
144 """
146 U, V, W = tsplit(to_domain_1(UVW))
148 XYZ = tstack([3 / 2 * U, V, 3 / 2 * U - (3 * V) + (2 * W)])
150 return from_range_1(XYZ)
153def UCS_to_uv(UVW: Domain1) -> NDArrayFloat:
154 """
155 Convert from *CIE 1960 UCS* colourspace to *uv* chromaticity
156 coordinates.
158 Parameters
159 ----------
160 UVW
161 *CIE 1960 UCS* :math:`UVW` colourspace array.
163 Returns
164 -------
165 :class:`numpy.ndarray`
166 *CIE UCS uv* chromaticity coordinates.
168 Notes
169 -----
170 +------------+-----------------------+---------------+
171 | **Domain** | **Scale - Reference** | **Scale - 1** |
172 +============+=======================+===============+
173 | ``UVW`` | 1 | 1 |
174 +------------+-----------------------+---------------+
176 References
177 ----------
178 :cite:`Wikipedia2008c`
180 Examples
181 --------
182 >>> import numpy as np
183 >>> UVW = np.array([0.13769339, 0.12197225, 0.10537310])
184 >>> UCS_to_uv(UVW) # doctest: +ELLIPSIS
185 array([ 0.3772021..., 0.3341350...])
186 """
188 U, V, W = tsplit(to_domain_1(UVW))
190 U_V_W = U + V + W
192 with sdiv_mode():
193 return tstack([sdiv(U, U_V_W), sdiv(V, U_V_W)])
196def uv_to_UCS(uv: ArrayLike, V: Domain1 = 1) -> Range1:
197 """
198 Convert from *uv* chromaticity coordinates to *CIE 1960 UCS*
199 colourspace.
201 Parameters
202 ----------
203 uv
204 *CIE UCS uv* chromaticity coordinates.
205 V
206 Optional :math:`V` *luminance* value used to construct the
207 *CIE 1960 UCS* :math:`UVW` colourspace array, the default :math:`V`
208 *luminance* is set to 1.
210 Returns
211 -------
212 :class:`numpy.ndarray`
213 *CIE 1960 UCS* :math:`UVW` colourspace array.
215 Notes
216 -----
217 +------------+-----------------------+---------------+
218 | **Domain** | **Scale - Reference** | **Scale - 1** |
219 +============+=======================+===============+
220 | ``V`` | 1 | 1 |
221 +------------+-----------------------+---------------+
223 +------------+-----------------------+---------------+
224 | **Range** | **Scale - Reference** | **Scale - 1** |
225 +============+=======================+===============+
226 | ``UVW`` | 1 | 1 |
227 +------------+-----------------------+---------------+
229 References
230 ----------
231 :cite:`Wikipedia2008c`
233 Examples
234 --------
235 >>> import numpy as np
236 >>> uv = np.array([0.37720213, 0.33413508])
237 >>> uv_to_UCS(uv) # doctest: +ELLIPSIS
238 array([ 1.1288911..., 1. , 0.8639104...])
239 """
241 u, v = tsplit(uv)
242 V = to_domain_1(V)
244 with sdiv_mode():
245 UVW = tstack([V * sdiv(u, v), np.resize(V, u.shape), -V * sdiv(u + v - 1, v)])
247 return from_range_1(UVW)
250def UCS_uv_to_xy(uv: ArrayLike) -> NDArrayFloat:
251 """
252 Convert from *CIE 1960 UCS* :math:`UVW` colourspace *uv* chromaticity
253 coordinates to *CIE xy* chromaticity coordinates.
255 Parameters
256 ----------
257 uv
258 *CIE UCS uv* chromaticity coordinates.
260 Returns
261 -------
262 :class:`numpy.ndarray`
263 *CIE xy* chromaticity coordinates.
265 References
266 ----------
267 :cite:`Wikipedia2008c`
269 Examples
270 --------
271 >>> import numpy as np
272 >>> uv = np.array([0.37720213, 0.33413508])
273 >>> UCS_uv_to_xy(uv) # doctest: +ELLIPSIS
274 array([ 0.5436955..., 0.3210794...])
275 """
277 u, v = tsplit(uv)
279 d = 2 * u - 8 * v + 4
281 with sdiv_mode():
282 return tstack([sdiv(3 * u, d), sdiv(2 * v, d)])
285def xy_to_UCS_uv(xy: ArrayLike) -> NDArrayFloat:
286 """
287 Convert from *CIE xy* chromaticity coordinates to *CIE 1960 UCS*
288 :math:`UVW` colourspace *uv* chromaticity coordinates.
290 Parameters
291 ----------
292 xy
293 *CIE xy* chromaticity coordinates.
295 Returns
296 -------
297 :class:`numpy.ndarray`
298 *CIE UCS uv* chromaticity coordinates.
300 References
301 ----------
302 :cite:`Wikipedia2008c`
304 Examples
305 --------
306 >>> import numpy as np
307 >>> xy = np.array([0.54369555, 0.32107941])
308 >>> xy_to_UCS_uv(xy) # doctest: +ELLIPSIS
309 array([ 0.3772021..., 0.3341350...])
310 """
312 x, y = tsplit(xy)
314 d = 12 * y - 2 * x + 3
316 with sdiv_mode():
317 return tstack([sdiv(4 * x, d), sdiv(6 * y, d)])
320def XYZ_to_CIE1960UCS(
321 XYZ: Domain1,
322) -> Range1:
323 """
324 Convert from *CIE XYZ* tristimulus values to *CIE 1960 UCS* :math:`uvV`
325 colourspace.
327 This colourspace combines the *CIE 1960 UCS* :math:`UVW` colourspace
328 :math:`uv` chromaticity coordinates with the luminance :math:`V` from
329 the *CIE 1960 UCS* :math:`UVW` colourspace.
331 It is a convenient definition for use with the
332 *CIE 1960 UCS Chromaticity Diagram*.
334 Parameters
335 ----------
336 XYZ
337 *CIE XYZ* tristimulus values.
339 Returns
340 -------
341 :class:`numpy.ndarray`
342 :math:`uvV` colourspace array.
344 Notes
345 -----
346 +----------------+-----------------------+-----------------+
347 | **Domain** | **Scale - Reference** | **Scale - 1** |
348 +================+=======================+=================+
349 | ``XYZ`` | 1 | 1 |
350 +----------------+-----------------------+-----------------+
352 +----------------+-----------------------+-----------------+
353 | **Range** | **Scale - Reference** | **Scale - 1** |
354 +================+=======================+=================+
355 | ``uvV`` | 1 | 1 |
356 +----------------+-----------------------+-----------------+
358 Examples
359 --------
360 >>> import numpy as np
361 >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952])
362 >>> XYZ_to_CIE1960UCS(XYZ) # doctest: +ELLIPSIS
363 array([ 0.3772021..., 0.3341350..., 0.12197225])
364 """
366 UVW = XYZ_to_UCS(XYZ)
368 _U, V, _W = tsplit(UVW)
370 u, v = tsplit(UCS_to_uv(UVW))
372 return tstack([u, v, V])
375def CIE1960UCS_to_XYZ(
376 uvV: Domain1,
377) -> Range1:
378 """
379 Convert from *CIE 1960 UCS* :math:`uvV` colourspace to *CIE XYZ*
380 tristimulus values.
382 This colourspace combines the *CIE 1960 UCS* :math:`UVW` colourspace
383 :math:`uv` chromaticity coordinates with the luminance :math:`V` from
384 the *CIE 1960 UCS* :math:`UVW` colourspace.
386 It is a convenient definition for use with the
387 *CIE 1960 UCS Chromaticity Diagram*.
389 Parameters
390 ----------
391 uvV
392 :math:`uvV` colourspace array.
394 Returns
395 -------
396 :class:`numpy.ndarray`
397 *CIE XYZ* tristimulus values.
399 Notes
400 -----
401 +----------------+-----------------------+-----------------+
402 | **Domain** | **Scale - Reference** | **Scale - 1** |
403 +================+=======================+=================+
404 | ``uvV`` | 1 | 1 |
405 +----------------+-----------------------+-----------------+
407 +----------------+-----------------------+-----------------+
408 | **Range** | **Scale - Reference** | **Scale - 1** |
409 +================+=======================+=================+
410 | ``XYZ`` | 1 | 1 |
411 +----------------+-----------------------+-----------------+
413 Examples
414 --------
415 >>> import numpy as np
416 >>> uvV = np.array([0.37720213, 0.33413509, 0.12197225])
417 >>> CIE1960UCS_to_XYZ(uvV) # doctest: +ELLIPSIS
418 array([ 0.2065400..., 0.1219722..., 0.0513695...])
419 """
421 u, v, V = tsplit(uvV)
423 U, _V, W = tsplit(uv_to_UCS(tstack([u, v]), V))
425 return UCS_to_XYZ(tstack([U, V, W]))