Coverage for colour/models/rgb/transfer_functions/panasonic_v_log.py: 100%
38 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"""
2Panasonic V-Log Log Encoding
3============================
5Define the *Panasonic V-Log* log encoding.
7- :func:`colour.models.log_encoding_VLog`
8- :func:`colour.models.log_decoding_VLog`
10References
11----------
12- :cite:`Panasonic2014a` : Panasonic. (2014). VARICAM V-Log/V-Gamut (pp.
13 1-7).
14 http://pro-av.panasonic.net/en/varicam/common/pdf/VARICAM_V-Log_V-Gamut.pdf
15"""
17from __future__ import annotations
19import numpy as np
21from colour.hints import ( # noqa: TC001
22 Domain1,
23 Range1,
24)
25from colour.models.rgb.transfer_functions import full_to_legal, legal_to_full
26from colour.utilities import Structure, as_float, from_range_1, optional, to_domain_1
28__author__ = "Colour Developers"
29__copyright__ = "Copyright 2013 Colour Developers"
30__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
31__maintainer__ = "Colour Developers"
32__email__ = "colour-developers@colour-science.org"
33__status__ = "Production"
35__all__ = [
36 "CONSTANTS_VLOG",
37 "log_encoding_VLog",
38 "log_decoding_VLog",
39]
41CONSTANTS_VLOG: Structure = Structure(
42 cut1=0.01, cut2=0.181, b=0.00873, c=0.241514, d=0.598206
43)
44"""*Panasonic V-Log* constants."""
47def log_encoding_VLog(
48 L_in: Domain1,
49 bit_depth: int = 10,
50 out_normalised_code_value: bool = True,
51 in_reflection: bool = True,
52 constants: Structure | None = None,
53) -> Range1:
54 """
55 Apply the *Panasonic V-Log* log encoding opto-electronic transfer function (OETF).
57 Parameters
58 ----------
59 L_in
60 Linear reflection data :math:`L_{in}`.
61 bit_depth
62 Bit-depth used for conversion.
63 out_normalised_code_value
64 Whether the *Panasonic V-Log* non-linear data :math:`V_{out}` is
65 encoded as normalised code values.
66 in_reflection
67 Whether the light level :math:`L_{in}` to a camera is reflection.
68 constants
69 *Panasonic V-Log* constants.
71 Returns
72 -------
73 :class:`numpy.ndarray`
74 *Panasonic V-Log* mon-linear encoded data :math:`V_{out}`.
76 Notes
77 -----
78 +------------+-----------------------+---------------+
79 | **Domain** | **Scale - Reference** | **Scale - 1** |
80 +============+=======================+===============+
81 | ``L_in`` | 1 | 1 |
82 +------------+-----------------------+---------------+
84 +------------+-----------------------+---------------+
85 | **Range** | **Scale - Reference** | **Scale - 1** |
86 +============+=======================+===============+
87 | ``V_out`` | 1 | 1 |
88 +------------+-----------------------+---------------+
90 References
91 ----------
92 :cite:`Panasonic2014a`
94 Examples
95 --------
96 >>> log_encoding_VLog(0.18) # doctest: +ELLIPSIS
97 0.4233114...
99 The values of *Fig.2.2 V-Log Code Value* table in :cite:`Panasonic2014a`
100 are obtained as follows:
102 >>> L_in = np.array([0, 18, 90]) / 100
103 >>> np.around(log_encoding_VLog(L_in, 10, False) * 100).astype(np.int_)
104 array([ 7, 42, 61])
105 >>> np.around(log_encoding_VLog(L_in) * (2**10 - 1)).astype(np.int_)
106 array([128, 433, 602])
107 >>> np.around(log_encoding_VLog(L_in) * (2**12 - 1)).astype(np.int_)
108 array([ 512, 1733, 2409])
110 Note that some values in the last column values of
111 *Fig.2.2 V-Log Code Value* table in :cite:`Panasonic2014a` are different
112 by a code: [512, 1732, 2408].
113 """
115 L_in = to_domain_1(L_in)
116 constants = optional(constants, CONSTANTS_VLOG)
118 if not in_reflection:
119 L_in = L_in * 0.9
121 cut1 = constants.cut1
122 b = constants.b
123 c = constants.c
124 d = constants.d
126 V_out = np.where(
127 L_in < cut1,
128 5.6 * L_in + 0.125,
129 c * np.log10(L_in + b) + d,
130 )
132 V_out_cv = V_out if out_normalised_code_value else legal_to_full(V_out, bit_depth)
134 return as_float(from_range_1(V_out_cv))
137def log_decoding_VLog(
138 V_out: Domain1,
139 bit_depth: int = 10,
140 in_normalised_code_value: bool = True,
141 out_reflection: bool = True,
142 constants: Structure | None = None,
143) -> Range1:
144 """
145 Apply the *Panasonic V-Log* log decoding inverse opto-electronic transfer
147 function (OETF).
149 Parameters
150 ----------
151 V_out
152 *Panasonic V-Log* mon-linear encoded data :math:`V_{out}`.
153 bit_depth
154 Bit-depth used for conversion.
155 in_normalised_code_value
156 Whether the *Panasonic V-Log* non-linear data :math:`V_{out}` is
157 encoded as normalised code values.
158 out_reflection
159 Whether the light level :math:`L_{in}` to a camera is reflection.
160 constants
161 *Panasonic V-Log* constants.
163 Returns
164 -------
165 :class:`numpy.ndarray`
166 Linear reflection data :math:`L_{in}`.
168 Notes
169 -----
170 +------------+-----------------------+---------------+
171 | **Domain** | **Scale - Reference** | **Scale - 1** |
172 +============+=======================+===============+
173 | ``V_out`` | 1 | 1 |
174 +------------+-----------------------+---------------+
176 +------------+-----------------------+---------------+
177 | **Range** | **Scale - Reference** | **Scale - 1** |
178 +============+=======================+===============+
179 | ``L_in`` | 1 | 1 |
180 +------------+-----------------------+---------------+
182 References
183 ----------
184 :cite:`Panasonic2014a`
186 Examples
187 --------
188 >>> log_decoding_VLog(0.423311448760136) # doctest: +ELLIPSIS
189 0.1799999...
190 """
192 V_out = to_domain_1(V_out)
193 constants = optional(constants, CONSTANTS_VLOG)
195 V_out = V_out if in_normalised_code_value else full_to_legal(V_out, bit_depth)
197 cut2 = constants.cut2
198 b = constants.b
199 c = constants.c
200 d = constants.d
202 L_in = np.where(
203 V_out < cut2,
204 (V_out - 0.125) / 5.6,
205 10 ** ((V_out - d) / c) - b,
206 )
208 if not out_reflection:
209 L_in = L_in / 0.9
211 return as_float(from_range_1(L_in))