Coverage for colour/models/rgb/transfer_functions/fujifilm_f_log.py: 100%
52 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"""
2Fujifilm F-Log Log Encoding
3===========================
5Define the *Fujifilm F-Log* log encoding.
7- :func:`colour.models.log_encoding_FLog`
8- :func:`colour.models.log_decoding_FLog`
9- :func:`colour.models.log_encoding_FLog2`
10- :func:`colour.models.log_decoding_FLog2`
12References
13----------
14- :cite:`Fujifilm2022` : Fujifilm. (2022). F-Log Data Sheet Ver.1.1 (pp.
15 1-4). https://dl.fujifilm-x.com/support/lut/F-Log_DataSheet_E_Ver.1.1.pdf
16- :cite:`Fujifilm2022a` : Fujifilm. (2022). F-Log2 Data Sheet Ver.1.0 (pp.
17 1-4). https://dl.fujifilm-x.com/support/lut/F-Log2_DataSheet_E_Ver.1.0.pdf
18"""
20from __future__ import annotations
22import numpy as np
24from colour.hints import ( # noqa: TC001
25 Domain1,
26 Range1,
27)
28from colour.models.rgb.transfer_functions import full_to_legal, legal_to_full
29from colour.utilities import Structure, as_float, from_range_1, optional, to_domain_1
31__author__ = "Colour Developers"
32__copyright__ = "Copyright 2013 Colour Developers"
33__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
34__maintainer__ = "Colour Developers"
35__email__ = "colour-developers@colour-science.org"
36__status__ = "Production"
38__all__ = [
39 "CONSTANTS_FLOG",
40 "CONSTANTS_FLOG2",
41 "log_encoding_FLog",
42 "log_decoding_FLog",
43 "log_encoding_FLog2",
44 "log_decoding_FLog2",
45]
47CONSTANTS_FLOG: Structure = Structure(
48 cut1=0.00089,
49 cut2=0.100537775223865,
50 a=0.555556,
51 b=0.009468,
52 c=0.344676,
53 d=0.790453,
54 e=8.735631,
55 f=0.092864,
56)
57"""*Fujifilm F-Log* constants."""
59CONSTANTS_FLOG2: Structure = Structure(
60 cut1=0.000889,
61 cut2=0.100686685370811,
62 a=5.555556,
63 b=0.064829,
64 c=0.245281,
65 d=0.384316,
66 e=8.799461,
67 f=0.092864,
68)
69"""*Fujifilm F-Log2* colourspace constants."""
72def log_encoding_FLog(
73 in_r: Domain1,
74 bit_depth: int = 10,
75 out_normalised_code_value: bool = True,
76 in_reflection: bool = True,
77 constants: Structure | None = None,
78) -> Range1:
79 """
80 Apply the *Fujifilm F-Log* log encoding opto-electronic transfer function (OETF).
82 Parameters
83 ----------
84 in_r
85 Linear reflection data :math:`in`.
86 bit_depth
87 Bit-depth used for conversion.
88 out_normalised_code_value
89 Whether the *Fujifilm F-Log* non-linear data :math:`out` is encoded as
90 normalised code values.
91 in_reflection
92 Whether the light level :math:`in` to a camera is reflection.
93 constants
94 *Fujifilm F-Log* constants.
96 Returns
97 -------
98 :class:`numpy.ndarray`
99 *Fujifilm F-Log* non-linear encoded data :math:`out`.
101 Notes
102 -----
103 +------------+-----------------------+---------------+
104 | **Domain** | **Scale - Reference** | **Scale - 1** |
105 +============+=======================+===============+
106 | ``in_r`` | 1 | 1 |
107 +------------+-----------------------+---------------+
109 +------------+-----------------------+---------------+
110 | **Range** | **Scale - Reference** | **Scale - 1** |
111 +============+=======================+===============+
112 | ``out_r`` | 1 | 1 |
113 +------------+-----------------------+---------------+
115 References
116 ----------
117 :cite:`Fujifilm2022`
119 Examples
120 --------
121 >>> log_encoding_FLog(0.18) # doctest: +ELLIPSIS
122 0.4593184...
124 The values of *2-2. F-Log Code Value* table in :cite:`Fujifilm2022`
125 are obtained as follows:
127 >>> x = np.array([0, 18, 90]) / 100
128 >>> np.around(log_encoding_FLog(x, 10, False) * 100, 1)
129 array([ 3.5, 46.3, 73.2])
130 >>> np.around(log_encoding_FLog(x) * (2**10 - 1)).astype(np.int_)
131 array([ 95, 470, 705])
132 """
134 in_r = to_domain_1(in_r)
135 constants = optional(constants, CONSTANTS_FLOG)
137 if not in_reflection:
138 in_r = in_r * 0.9
140 cut1 = constants.cut1
141 a = constants.a
142 b = constants.b
143 c = constants.c
144 d = constants.d
145 e = constants.e
146 f = constants.f
148 out_r = np.where(
149 in_r < cut1,
150 e * in_r + f,
151 c * np.log10(a * in_r + b) + d,
152 )
154 out_r_cv = out_r if out_normalised_code_value else legal_to_full(out_r, bit_depth)
156 return as_float(from_range_1(out_r_cv))
159def log_decoding_FLog(
160 out_r: Domain1,
161 bit_depth: int = 10,
162 in_normalised_code_value: bool = True,
163 out_reflection: bool = True,
164 constants: Structure | None = None,
165) -> Range1:
166 """
167 Apply the *Fujifilm F-Log* log decoding inverse opto-electronic transfer
169 function (OETF).
171 Parameters
172 ----------
173 out_r
174 *Fujifilm F-Log* non-linear encoded data :math:`out`.
175 bit_depth
176 Bit-depth used for conversion.
177 in_normalised_code_value
178 Whether the *Fujifilm F-Log* non-linear data :math:`out` is encoded as
179 normalised code values.
180 out_reflection
181 Whether the light level :math:`in` to a camera is reflection.
182 constants
183 *Fujifilm F-Log* constants.
185 Returns
186 -------
187 :class:`numpy.ndarray`
188 Linear reflection data :math:`in`.
190 Notes
191 -----
192 +------------+-----------------------+---------------+
193 | **Domain** | **Scale - Reference** | **Scale - 1** |
194 +============+=======================+===============+
195 | ``out_r`` | 1 | 1 |
196 +------------+-----------------------+---------------+
198 +------------+-----------------------+---------------+
199 | **Range** | **Scale - Reference** | **Scale - 1** |
200 +============+=======================+===============+
201 | ``in_r`` | 1 | 1 |
202 +------------+-----------------------+---------------+
204 References
205 ----------
206 :cite:`Fujifilm2022`
208 Examples
209 --------
210 >>> log_decoding_FLog(0.45931845866162124) # doctest: +ELLIPSIS
211 0.1800000...
212 """
214 out_r = to_domain_1(out_r)
215 constants = optional(constants, CONSTANTS_FLOG)
217 out_r = out_r if in_normalised_code_value else full_to_legal(out_r, bit_depth)
219 cut2 = constants.cut2
220 a = constants.a
221 b = constants.b
222 c = constants.c
223 d = constants.d
224 e = constants.e
225 f = constants.f
227 in_r = np.where(
228 out_r < cut2,
229 (out_r - f) / e,
230 (10 ** ((out_r - d) / c)) / a - b / a,
231 )
233 if not out_reflection:
234 in_r = in_r / 0.9
236 return as_float(from_range_1(in_r))
239def log_encoding_FLog2(
240 in_r: Domain1,
241 bit_depth: int = 10,
242 out_normalised_code_value: bool = True,
243 in_reflection: bool = True,
244 constants: Structure | None = None,
245) -> Range1:
246 """
247 Apply the *Fujifilm F-Log2* log encoding opto-electronic transfer function (OETF).
249 Parameters
250 ----------
251 in_r
252 Linear reflection data :math:`in`.
253 bit_depth
254 Bit-depth used for conversion.
255 out_normalised_code_value
256 Whether the *Fujifilm F-Log2* non-linear data :math:`out` is encoded as
257 normalised code values.
258 in_reflection
259 Whether the light level :math:`in` to a camera is reflection.
260 constants
261 *Fujifilm F-Log2* constants.
263 Returns
264 -------
265 :class:`numpy.floating` or :class:`numpy.ndarray`
266 *Fujifilm F-Log2* non-linear encoded data :math:`out`.
268 Notes
269 -----
270 +------------+-----------------------+---------------+
271 | **Domain** | **Scale - Reference** | **Scale - 1** |
272 +============+=======================+===============+
273 | ``in_r`` | 1 | 1 |
274 +------------+-----------------------+---------------+
276 +------------+-----------------------+---------------+
277 | **Range** | **Scale - Reference** | **Scale - 1** |
278 +============+=======================+===============+
279 | ``out_r`` | 1 | 1 |
280 +------------+-----------------------+---------------+
282 References
283 ----------
284 :cite:`Fujifilm2022a`
286 Examples
287 --------
288 >>> log_encoding_FLog2(0.18) # doctest: +ELLIPSIS
289 0.3910072...
291 The values of *2-2. F-Log2 Code Value* table in
292 :cite:`Fujifilm2022a` are obtained as follows:
294 >>> x = np.array([0, 18, 90]) / 100
295 >>> np.around(log_encoding_FLog2(x, 10, False) * 100, 1)
296 array([ 3.5, 38.4, 57.8])
297 >>> np.around(log_encoding_FLog2(x) * (2**10 - 1)).astype(np.int_)
298 array([ 95, 400, 570])
299 """
301 constants = optional(constants, CONSTANTS_FLOG2)
303 return log_encoding_FLog(
304 in_r, bit_depth, out_normalised_code_value, in_reflection, constants
305 )
308def log_decoding_FLog2(
309 out_r: Domain1,
310 bit_depth: int = 10,
311 in_normalised_code_value: bool = True,
312 out_reflection: bool = True,
313 constants: Structure | None = None,
314) -> Range1:
315 """
316 Apply the *Fujifilm F-Log2* log decoding inverse opto-electronic transfer
317 function (OETF).
319 Parameters
320 ----------
321 out_r
322 *Fujifilm F-Log2* non-linear encoded data :math:`out`.
323 bit_depth
324 Bit-depth used for conversion.
325 in_normalised_code_value
326 Whether the *Fujifilm F-Log2* non-linear data :math:`out` is encoded as
327 normalised code values.
328 out_reflection
329 Whether the light level :math:`in` to a camera is reflection.
330 constants
331 *Fujifilm F-Log2* constants.
333 Returns
334 -------
335 :class:`numpy.floating` or :class:`numpy.ndarray`
336 Linear reflection data :math:`in`.
338 Notes
339 -----
340 +------------+-----------------------+---------------+
341 | **Domain** | **Scale - Reference** | **Scale - 1** |
342 +============+=======================+===============+
343 | ``out_r`` | 1 | 1 |
344 +------------+-----------------------+---------------+
346 +------------+-----------------------+---------------+
347 | **Range** | **Scale - Reference** | **Scale - 1** |
348 +============+=======================+===============+
349 | ``in_r`` | 1 | 1 |
350 +------------+-----------------------+---------------+
352 References
353 ----------
354 :cite:`Fujifilm2022a`
356 Examples
357 --------
358 >>> log_decoding_FLog2(0.39100724189123004) # doctest: +ELLIPSIS
359 0.1799999...
360 """
362 constants = optional(constants, CONSTANTS_FLOG2)
364 return log_decoding_FLog(
365 out_r, bit_depth, in_normalised_code_value, out_reflection, constants
366 )