Coverage for colour/models/rgb/transfer_functions/itut_h_273.py: 100%
43 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"""
2Recommendation ITU-T H.273 Transfer Characteristics
3===================================================
5Define the *Recommendation ITU-T H.273* transfer functions that do not belong
6in another specification or standard, or have been modified for inclusion.
8- :func:`colour.models.oetf_H273_Log`
9- :func:`colour.models.oetf_inverse_H273_Log`
10- :func:`colour.models.oetf_H273_LogSqrt`
11- :func:`colour.models.oetf_inverse_H273_LogSqrt`
12- :func:`colour.models.oetf_H273_IEC61966_2`
13- :func:`colour.models.oetf_inverse_H273_IEC61966_2`
14- :func:`colour.models.eotf_H273_ST428_1`
15- :func:`colour.models.eotf_inverse_H273_ST428_1`
17References
18----------
19- :cite:`InternationalTelecommunicationUnion2021` : International
20 Telecommunication Union. (2021). Recommendation ITU-T H.273 -
21 Coding-independent code points for video signal type identification.
22 https://www.itu.int/rec/T-REC-H.273-202107-I/en
23- :cite:`SocietyofMotionPictureandTelevisionEngineers2019` : Society of
24 Motion Picture and Television Engineers. (2019). ST 428-1:2019 - D-Cinema
25 Distribution Master — Image Characteristic. doi:10.5594/SMPTE.ST428-1.2019
26"""
28from __future__ import annotations
30import numpy as np
32from colour.algebra import spow
33from colour.hints import ( # noqa: TC001
34 Domain1,
35 Range1,
36)
37from colour.models.rgb.transfer_functions import (
38 eotf_DCDM,
39 eotf_inverse_DCDM,
40 eotf_inverse_sRGB,
41 eotf_sRGB,
42)
43from colour.utilities import as_float, as_float_array, from_range_1, to_domain_1
45__author__ = "Colour Developers"
46__copyright__ = "Copyright 2013 Colour Developers"
47__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
48__maintainer__ = "Colour Developers"
49__email__ = "colour-developers@colour-science.org"
50__status__ = "Production"
52__all__ = [
53 "oetf_H273_Log",
54 "oetf_inverse_H273_Log",
55 "oetf_H273_LogSqrt",
56 "oetf_inverse_H273_LogSqrt",
57 "oetf_H273_IEC61966_2",
58 "oetf_inverse_H273_IEC61966_2",
59 "eotf_H273_ST428_1",
60 "eotf_inverse_H273_ST428_1",
61]
64def oetf_H273_Log(L_c: Domain1) -> Range1:
65 """
66 Apply the *Recommendation ITU-T H.273* opto-electronic transfer function
67 (OETF) for logarithmic encoding with 100:1 dynamic range.
69 Parameters
70 ----------
71 L_c
72 Scene *luminance* :math:`L_c`.
74 Returns
75 -------
76 :class:`numpy.ndarray`
77 Electrical signal :math:`V`.
79 Notes
80 -----
81 +------------+-----------------------+---------------+
82 | **Domain** | **Scale - Reference** | **Scale - 1** |
83 +============+=======================+===============+
84 | ``L_c`` | 1 | 1 |
85 +------------+-----------------------+---------------+
87 +------------+-----------------------+---------------+
88 | **Range** | **Scale - Reference** | **Scale - 1** |
89 +============+=======================+===============+
90 | ``V`` | 1 | 1 |
91 +------------+-----------------------+---------------+
93 References
94 ----------
95 :cite:`InternationalTelecommunicationUnion2021`
97 Warnings
98 --------
99 - The function is clamped to domain [0.01, np.inf].
101 Examples
102 --------
103 >>> oetf_H273_Log(0.18) # doctest: +ELLIPSIS
104 0.6276362525516...
105 >>> oetf_H273_Log(0.01) # doctest: +ELLIPSIS
106 0.0
107 >>> oetf_H273_Log(0.001) # doctest: +ELLIPSIS
108 0.0
109 >>> oetf_H273_Log(1.0) # doctest: +ELLIPSIS
110 1.0
111 """
113 L_c = to_domain_1(L_c)
115 V = np.where(
116 L_c >= 0.01,
117 # L_c in [0.01, 1] range
118 1 + np.log10(L_c) / 2,
119 # L_c in [0, 0.01] range
120 0,
121 )
123 return as_float(from_range_1(V))
126def oetf_inverse_H273_Log(V: Domain1) -> Range1:
127 """
128 Apply the *Recommendation ITU-T H.273* inverse opto-electronic transfer
129 function (OETF) for logarithmic encoding with 100:1 dynamic range.
131 Parameters
132 ----------
133 V
134 Electrical signal :math:`V`.
136 Returns
137 -------
138 :class:`numpy.ndarray`
139 Scene *luminance* :math:`L_c`.
141 Notes
142 -----
143 +------------+-----------------------+---------------+
144 | **Domain** | **Scale - Reference** | **Scale - 1** |
145 +============+=======================+===============+
146 | ``V`` | 1 | 1 |
147 +------------+-----------------------+---------------+
149 +------------+-----------------------+---------------+
150 | **Range** | **Scale - Reference** | **Scale - 1** |
151 +============+=======================+===============+
152 | ``L_c`` | 1 | 1 |
153 +------------+-----------------------+---------------+
155 References
156 ----------
157 :cite:`InternationalTelecommunicationUnion2021`
159 Warnings
160 --------
161 - The function is clamped to domain
162 [:func:`colour.models.oetf_H273_Log` (0.01), np.inf].
164 Examples
165 --------
166 >>> oetf_inverse_H273_Log(0.6276362525516) # doctest: +ELLIPSIS
167 0.17999999...
168 >>> oetf_inverse_H273_Log(0.0) # doctest: +ELLIPSIS
169 0.01
170 >>> oetf_inverse_H273_Log(1.0) # doctest: +ELLIPSIS
171 1.0
172 """
174 V = to_domain_1(V)
176 L_c = np.where(
177 oetf_H273_Log(0.01) <= V,
178 # L_c in [0.01, 1] range
179 spow(10, (V - 1) * 2),
180 # L_c in [0, 0.01] range
181 0,
182 )
184 return as_float(from_range_1(L_c))
187def oetf_H273_LogSqrt(L_c: Domain1) -> Range1:
188 """
189 Apply the *Recommendation ITU-T H.273* opto-electronic transfer function
190 (OETF) for logarithmic encoding (100\\*Sqrt(10):1 range).
192 Parameters
193 ----------
194 L_c
195 Scene *luminance* :math:`L_c`.
197 Returns
198 -------
199 :class:`numpy.ndarray`
200 Electrical signal :math:`V`.
202 Notes
203 -----
204 +------------+-----------------------+---------------+
205 | **Domain** | **Scale - Reference** | **Scale - 1** |
206 +============+=======================+===============+
207 | ``L_c`` | 1 | 1 |
208 +------------+-----------------------+---------------+
210 +------------+-----------------------+---------------+
211 | **Range** | **Scale - Reference** | **Scale - 1** |
212 +============+=======================+===============+
213 | ``V`` | 1 | 1 |
214 +------------+-----------------------+---------------+
216 References
217 ----------
218 :cite:`InternationalTelecommunicationUnion2021`
220 Warnings
221 --------
222 - The function is clamped to domain
223 [:func:`colour.models.oetf_H273_LogSqrt` (sqrt(10) / 1000),
224 np.inf].
226 Examples
227 --------
228 >>> oetf_H273_LogSqrt(0.18) # doctest: +ELLIPSIS
229 0.702109002041...
230 >>> oetf_H273_LogSqrt(0.003162277660168) # doctest: +ELLIPSIS
231 0.0
232 >>> oetf_H273_LogSqrt(0.0001) # doctest: +ELLIPSIS
233 0.0
234 >>> oetf_H273_LogSqrt(1.0) # doctest: +ELLIPSIS
235 1.0
236 """
238 L_c = to_domain_1(L_c)
240 V = np.where(
241 L_c >= np.sqrt(10) / 1000,
242 # L_c in [sqrt(10)/1000, 1] range
243 1 + np.log10(L_c) / 2.5,
244 # L_c in [0, sqrt(10)/1000] range
245 0,
246 )
248 return as_float(from_range_1(V))
251def oetf_inverse_H273_LogSqrt(V: Domain1) -> Range1:
252 """
253 Apply the *Recommendation ITU-T H.273* inverse opto-electronic transfer
254 function (OETF) for logarithmic encoding (100\\*Sqrt(10):1 range).
256 Parameters
257 ----------
258 V
259 Electrical signal :math:`V`.
261 Returns
262 -------
263 :class:`numpy.ndarray`
264 Scene *luminance* :math:`L_c`.
266 Notes
267 -----
268 +------------+-----------------------+---------------+
269 | **Domain** | **Scale - Reference** | **Scale - 1** |
270 +============+=======================+===============+
271 | ``V`` | 1 | 1 |
272 +------------+-----------------------+---------------+
274 +------------+-----------------------+---------------+
275 | **Range** | **Scale - Reference** | **Scale - 1** |
276 +============+=======================+===============+
277 | ``L_c`` | 1 | 1 |
278 +------------+-----------------------+---------------+
280 References
281 ----------
282 :cite:`InternationalTelecommunicationUnion2021`
284 Warnings
285 --------
286 - The function is clamped to domain [sqrt(10) / 1000, np.inf].
288 Examples
289 --------
290 >>> oetf_inverse_H273_LogSqrt(0.702109002041) # doctest: +ELLIPSIS
291 0.1799999999...
292 >>> oetf_inverse_H273_LogSqrt(0.0) # doctest: +ELLIPSIS
293 0.00316227766...
294 >>> oetf_inverse_H273_LogSqrt(1.0) # doctest: +ELLIPSIS
295 1.0
296 """
298 V = to_domain_1(V)
300 L_c = np.where(
301 oetf_H273_LogSqrt(np.sqrt(10) / 1000) <= V,
302 # L_c in [sqrt(10)/1000, 1] range
303 spow(10, (V - 1) * 2.5),
304 # L_c in [0, sqrt(10)/1000] range
305 0,
306 )
308 return as_float(from_range_1(L_c))
311def oetf_H273_IEC61966_2(L_c: Domain1) -> Range1:
312 """
313 Apply the *Recommendation ITU-T H.273* opto-electronic transfer function
314 (OETF) for *IEC 61966-2* family of transfer functions (*2-1 sRGB*, *2-1
315 sYCC*, *2-4 xvYCC*).
317 Parameters
318 ----------
319 L_c
320 Scene *luminance* :math:`L_c`.
322 Returns
323 -------
324 :class:`numpy.ndarray`
325 Electrical signal :math:`V`.
327 Notes
328 -----
329 Usage in :cite:`InternationalTelecommunicationUnion2021` is as follows:
331 - For *IEC 61966-2-1 sRGB (MatrixCoefficients=0)*, the function is
332 only defined for :math:`L_c` in [0-1] range.
333 - For *IEC 61966-2-1 sYCC (MatrixCoefficients=5)* and *IEC 61966-2-4
334 xvYCC*, the function is defined for any real-valued :math:`L_c`.
336 +------------+-----------------------+---------------+
337 | **Domain** | **Scale - Reference** | **Scale - 1** |
338 +============+=======================+===============+
339 | ``L_c`` | 1 | 1 |
340 +------------+-----------------------+---------------+
342 +------------+-----------------------+---------------+
343 | **Range** | **Scale - Reference** | **Scale - 1** |
344 +============+=======================+===============+
345 | ``V`` | 1 | 1 |
346 +------------+-----------------------+---------------+
348 References
349 ----------
350 - :cite:`InternationalTelecommunicationUnion2021`
352 Examples
353 --------
354 >>> oetf_H273_IEC61966_2(0.18) # doctest: +ELLIPSIS
355 0.4613561295004...
356 >>> oetf_H273_IEC61966_2(-0.18) # doctest: +ELLIPSIS
357 -0.4613561295004...
358 """
360 L_c = as_float_array(L_c)
362 V = np.where(
363 L_c >= 0,
364 eotf_inverse_sRGB(L_c),
365 -eotf_inverse_sRGB(-L_c),
366 )
368 return as_float(V)
371def oetf_inverse_H273_IEC61966_2(
372 V: Domain1,
373) -> Range1:
374 """
375 Apply the *Recommendation ITU-T H.273* inverse opto-electronic
376 transfer function (OETF) for the *IEC 61966-2* family of transfer
377 functions (*2-1 sRGB*, *2-1 sYCC*, *2-4 xvYCC*).
379 Parameters
380 ----------
381 V
382 Electrical signal :math:`V`.
384 Returns
385 -------
386 :class:`numpy.ndarray`
387 Scene *luminance* :math:`L_c`.
389 Notes
390 -----
391 Usage in :cite:`InternationalTelecommunicationUnion2021` is
392 specified as follows:
394 - For *IEC 61966-2-1 sRGB (MatrixCoefficients=0)*, the function is
395 only defined for :math:`L_c` in [0-1] range.
396 - For *IEC 61966-2-1 sYCC (MatrixCoefficients=5)* and *IEC
397 61966-2-4 xvYCC*, the function is defined for any real-valued
398 :math:`L_c`.
400 +------------+-----------------------+---------------+
401 | **Domain** | **Scale - Reference** | **Scale - 1** |
402 +============+=======================+===============+
403 | ``V`` | 1 | 1 |
404 +------------+-----------------------+---------------+
406 +------------+-----------------------+---------------+
407 | **Range** | **Scale - Reference** | **Scale - 1** |
408 +============+=======================+===============+
409 | ``L_c`` | 1 | 1 |
410 +------------+-----------------------+---------------+
412 References
413 ----------
414 - :cite:`InternationalTelecommunicationUnion2021`
416 Examples
417 --------
418 >>> oetf_inverse_H273_IEC61966_2(0.461356129500) # doctest: +ELLIPSIS
419 0.1799999999...
420 >>> oetf_inverse_H273_IEC61966_2(-0.461356129500) # doctest: +ELLIPSIS
421 -0.1799999999...
422 """
424 V = as_float_array(V)
426 L_c = np.where(
427 V >= 0,
428 eotf_sRGB(V),
429 -eotf_sRGB(-V),
430 )
432 return as_float(L_c)
435def eotf_H273_ST428_1(V: Domain1) -> Range1:
436 """
437 Apply the *SMPTE ST 428-1 (2019)* electro-optical transfer function
438 (EOTF) as specified in *ITU-T H.273*.
440 Parameters
441 ----------
442 V
443 Electrical signal :math:`V`.
445 Returns
446 -------
447 :class:`numpy.ndarray`
448 Output display *Luminance* :math:`L_o` of the image.
450 Notes
451 -----
452 - The function specified in
453 :cite:`InternationalTelecommunicationUnion2021` divides
454 :math:`L_o` by 48, contrary to what is specified in
455 :cite:`SocietyofMotionPictureandTelevisionEngineers2019` and
456 :func:`colour.models.eotf_DCDM`.
458 +------------+-----------------------+---------------+
459 | **Domain** | **Scale - Reference** | **Scale - 1** |
460 +============+=======================+===============+
461 | ``V`` | 1 | 1 |
462 +------------+-----------------------+---------------+
464 +------------+-----------------------+---------------+
465 | **Range** | **Scale - Reference** | **Scale - 1** |
466 +============+=======================+===============+
467 | ``L_o`` | 1 | 1 |
468 +------------+-----------------------+---------------+
470 References
471 ----------
472 - :cite:`InternationalTelecommunicationUnion2021`,
473 :cite:`SocietyofMotionPictureandTelevisionEngineers2019`
475 Examples
476 --------
477 >>> eotf_H273_ST428_1(0.5000483377172) # doctest: +ELLIPSIS
478 0.1799999...
479 """
481 V = to_domain_1(V)
483 return as_float(from_range_1(eotf_DCDM(V) / 48))
486def eotf_inverse_H273_ST428_1(
487 L_o: Domain1,
488) -> Range1:
489 """
490 Apply the *SMPTE ST 428-1 (2019)* inverse electro-optical transfer function
491 (EOTF) as specified in *ITU-T H.273*.
493 Parameters
494 ----------
495 L_o
496 Output display *Luminance* :math:`L_o` of the image.
498 Returns
499 -------
500 :class:`numpy.ndarray`
501 Electrical signal :math:`V`.
503 Notes
504 -----
505 - The function specified in
506 :cite:`InternationalTelecommunicationUnion2021` multiplies :math:`L_o`
507 by 48, contrary to what is specified in
508 :cite:`SocietyofMotionPictureandTelevisionEngineers2019` and
509 :func:`colour.models.eotf_inverse_DCDM`.
511 +------------+-----------------------+---------------+
512 | **Domain** | **Scale - Reference** | **Scale - 1** |
513 +============+=======================+===============+
514 | ``L_o`` | 1 | 1 |
515 +------------+-----------------------+---------------+
517 +------------+-----------------------+---------------+
518 | **Range** | **Scale - Reference** | **Scale - 1** |
519 +============+=======================+===============+
520 | ``V`` | 1 | 1 |
521 +------------+-----------------------+---------------+
523 References
524 ----------
525 - :cite:`InternationalTelecommunicationUnion2021`,
526 :cite:`SocietyofMotionPictureandTelevisionEngineers2019`
528 Examples
529 --------
530 >>> eotf_inverse_H273_ST428_1(0.18) # doctest: +ELLIPSIS
531 0.5000483...
532 """
534 L_o = to_domain_1(L_o)
536 return as_float(from_range_1(eotf_inverse_DCDM(L_o * 48)))