Coverage for models/rgb/transfer_functions/apple_log_profile.py: 58%
36 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"""
2Apple Log Profile Log Encoding
3==============================
5Define the *Apple Log Profile* log encoding.
7- :func:`colour.models.log_encoding_AppleLogProfile`
8- :func:`colour.models.log_decoding_AppleLogProfile`
10References
11----------
12- :cite:`AppleInc.2023` : Apple Inc. (2023). Apple Log Profile White Paper.
13 https://developer.apple.com/download/all/?q=Apple%20log%20profile
14- :cite:`TheAcademyofMotionPictureArtsandSciences2023` : The Academy of
15 Motion Picture Arts and Sciences. (2023). IDT.Apple.AppleLog_BT2020.ctl.
16 Retrieved December 17, 2023, from
17 https://github.com/ampas/aces-dev/blob/\
18528c78fe2c0f4e7eb322581e98aba05de79466cb/transforms/ctl/idt/vendorSupplied/\
19apple/IDT.Apple.AppleLog_BT2020.ctl
21"""
23from __future__ import annotations
25import numpy as np
27from colour.hints import ( # noqa: TC001
28 Domain1,
29 Range1,
30)
31from colour.utilities import Structure, as_float, from_range_1, optional, to_domain_1
33__author__ = "Colour Developers"
34__copyright__ = "Copyright 2013 Colour Developers"
35__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
36__maintainer__ = "Colour Developers"
37__email__ = "colour-developers@colour-science.org"
38__status__ = "Production"
40__all__ = [
41 "CONSTANTS_APPLE_LOG_PROFILE",
42 "log_encoding_AppleLogProfile",
43 "log_decoding_AppleLogProfile",
44]
46CONSTANTS_APPLE_LOG_PROFILE: Structure = Structure(
47 R_0=-0.05641088,
48 R_t=0.01,
49 sigma=47.28711236,
50 beta=0.00964052,
51 gamma=0.08550479,
52 delta=0.69336945,
53)
54"""*Apple Log Profile* constants."""
57def log_encoding_AppleLogProfile(
58 R: Domain1,
59 constants: Structure | None = None,
60) -> Range1:
61 """
62 Apply the *Apple Log Profile* log encoding opto-electronic transfer function (OETF).
64 Parameters
65 ----------
66 R
67 Linear reflection data :math:`R`.
68 constants
69 *Apple Log Profile* constants.
71 Returns
72 -------
73 :class:`numpy.ndarray`
74 Logarithmically encoded value :math:`P`.
76 References
77 ----------
78 :cite:`AppleInc.2023`,
79 :cite:`TheAcademyofMotionPictureArtsandSciences2023`
81 Notes
82 -----
83 - The scene reflection signal :math:`R` captured by the camera is
84 represented using a floating point encoding. The :math:`R` value
85 of 0.18 corresponds to the signal produced by an 18% reflectance
86 reference gray chart.
88 +------------+-----------------------+---------------+
89 | **Domain** | **Scale - Reference** | **Scale - 1** |
90 +============+=======================+===============+
91 | ``R`` | 1 | 1 |
92 +------------+-----------------------+---------------+
94 +------------+-----------------------+---------------+
95 | **Range** | **Scale - Reference** | **Scale - 1** |
96 +============+=======================+===============+
97 | ``P`` | 1 | 1 |
98 +------------+-----------------------+---------------+
100 Examples
101 --------
102 >>> log_encoding_AppleLogProfile(0.18) # doctest: +ELLIPSIS
103 0.4882724...
104 """
106 R = to_domain_1(R)
107 constants = optional(constants, CONSTANTS_APPLE_LOG_PROFILE)
109 R_0 = constants.R_0
110 R_t = constants.R_t
111 sigma = constants.sigma
112 beta = constants.beta
113 gamma = constants.gamma
114 delta = constants.delta
116 P = np.select(
117 [
118 R >= R_t, # noqa: SIM300
119 np.logical_and(R_0 <= R, R < R_t), # noqa: SIM300
120 R < R_0,
121 ],
122 [
123 gamma * np.log2(R + beta) + delta,
124 sigma * (R - R_0) ** 2,
125 0,
126 ],
127 )
129 return as_float(from_range_1(P))
132def log_decoding_AppleLogProfile(
133 P: Domain1,
134 constants: Structure | None = None,
135) -> Range1:
136 """
137 Apply the *Apple Log Profile* log decoding inverse opto-electronic transfer
138 function (OETF).
140 Parameters
141 ----------
142 P
143 Logarithmically encoded value :math:`P`.
144 constants
145 *Apple Log Profile* constants.
147 Returns
148 -------
149 :class:`numpy.ndarray`
150 Linear reflection data :math:`R`.
152 References
153 ----------
154 :cite:`AppleInc.2023`,
155 :cite:`TheAcademyofMotionPictureArtsandSciences2023`
157 Notes
158 -----
159 - The captured pixel :math:`P` value uses floating point encoding
160 normalized to the [0, 1] range.
162 +------------+-----------------------+---------------+
163 | **Domain** | **Scale - Reference** | **Scale - 1** |
164 +============+=======================+===============+
165 | ``P`` | 1 | 1 |
166 +------------+-----------------------+---------------+
168 +------------+-----------------------+---------------+
169 | **Range** | **Scale - Reference** | **Scale - 1** |
170 +============+=======================+===============+
171 | ``R`` | 1 | 1 |
172 +------------+-----------------------+---------------+
174 Examples
175 --------
176 >>> log_decoding_AppleLogProfile(0.48827245852686763) # doctest: +ELLIPSIS
177 0.1800000...
178 """
180 P = to_domain_1(P)
181 constants = optional(constants, CONSTANTS_APPLE_LOG_PROFILE)
183 R_0 = constants.R_0
184 R_t = constants.R_t
185 sigma = constants.sigma
186 beta = constants.beta
187 gamma = constants.gamma
188 delta = constants.delta
190 P_t = sigma * (R_t - R_0) ** 2
192 R = np.select(
193 [
194 P >= P_t, # noqa: SIM300
195 np.logical_and(0 <= P, P < P_t), # noqa: SIM300
196 P < 0,
197 ],
198 [
199 2 ** ((P - delta) / gamma) - beta,
200 np.sqrt(P / sigma) + R_0,
201 R_0,
202 ],
203 )
205 return as_float(from_range_1(R))