Source code for colour.models.rgb.transfer_functions.leica_l_log
"""
Leica L-Log Log Encoding
========================
Define the *Leica L-Log* log encoding:
- :func:`colour.models.log_encoding_LLog`
- :func:`colour.models.log_decoding_LLog`
References
----------
- :cite:`LeicaCameraAG2022` : Leica Camera AG. (2022). Leica L-Log Reference
Manual. https://leica-camera.com/sites/default/files/\
pm-65976-210914__L-Log_Reference_Manual_EN.pdf
"""
from __future__ import annotations
import typing
import numpy as np
from colour.algebra import spow
if typing.TYPE_CHECKING:
from colour.hints import ArrayLike, NDArrayFloat
from colour.models.rgb.transfer_functions import full_to_legal, legal_to_full
from colour.utilities import Structure, as_float, from_range_1, to_domain_1
__author__ = "Colour Developers"
__copyright__ = "Copyright 2013 Colour Developers"
__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
__maintainer__ = "Colour Developers"
__email__ = "colour-developers@colour-science.org"
__status__ = "Production"
__all__ = [
"CONSTANTS_LLOG",
"log_encoding_LLog",
"log_decoding_LLog",
]
CONSTANTS_LLOG: Structure = Structure(
cut1=0.006,
cut2=0.1380,
a=8,
b=0.09,
c=0.27,
d=1.3,
e=0.0115,
f=0.6,
)
"""*Leica L-Log* constants."""
[docs]
def log_encoding_LLog(
LSR: ArrayLike,
bit_depth: int = 10,
out_normalised_code_value: bool = True,
in_reflection: bool = True,
constants: Structure = CONSTANTS_LLOG,
) -> NDArrayFloat:
"""
Define the *Leica L-Log* log encoding curve / opto-electronic transfer
function.
Parameters
----------
LSR
Linear scene reflection :math:`LSR` values.
bit_depth
Bit-depth used for conversion.
out_normalised_code_value
Whether the non-linear *Leica L-Log* data :math:`L-Log` is encoded as
normalised code values.
in_reflection
Whether the light level :math`in` to a camera is reflection.
constants
*Leica L-Log* constants.
Returns
-------
:class:`numpy.ndarray`
*L-Log* 10-bit equivalent code value :math:`L-Log`.
Notes
-----
+------------+-----------------------+---------------+
| **Domain** | **Scale - Reference** | **Scale - 1** |
+============+=======================+===============+
| ``LSR`` | [0, 1] | [0, 1] |
+------------+-----------------------+---------------+
+------------+-----------------------+---------------+
| **Range** | **Scale - Reference** | **Scale - 1** |
+============+=======================+===============+
| ``LLog`` | [0, 1] | [0, 1] |
+------------+-----------------------+---------------+
References
----------
:cite:`LeicaCameraAG2022`
Examples
--------
>>> log_encoding_LLog(0.18) # doctest: +ELLIPSIS
0.4353139...
"""
LSR = to_domain_1(LSR)
if not in_reflection:
LSR = LSR * 0.9
cut1 = constants.cut1
a = constants.a
b = constants.b
c = constants.c
d = constants.d
e = constants.e
f = constants.f
LLog = np.where(
cut1 >= LSR,
a * LSR + b,
c * np.log10(d * LSR + e) + f,
)
LLog_cv = LLog if out_normalised_code_value else legal_to_full(LLog, bit_depth)
return as_float(from_range_1(LLog_cv))
[docs]
def log_decoding_LLog(
LLog: ArrayLike,
bit_depth: int = 10,
in_normalised_code_value: bool = True,
out_reflection: bool = True,
constants: Structure = CONSTANTS_LLOG,
) -> NDArrayFloat:
"""
Define the *Leica L-Log* log decoding curve / electro-optical transfer
function.
Parameters
----------
LLog
*L-Log* 10-bit equivalent code value :math:`L-Log`.
bit_depth
Bit-depth used for conversion.
in_normalised_code_value
Whether the non-linear *Leica L-Log* data :math:`L-Log` is encoded as
normalised code values.
out_reflection
Whether the light level :math`in` to a camera is reflection.
constants
*Leica L-Log* constants.
Returns
-------
:class:`numpy.ndarray`
Linear scene reflection :math:`LSR` values.
Notes
-----
+------------+-----------------------+---------------+
| **Domain** | **Scale - Reference** | **Scale - 1** |
+============+=======================+===============+
| ``LLog`` | [0, 1] | [0, 1] |
+------------+-----------------------+---------------+
+------------+-----------------------+---------------+
| **Range** | **Scale - Reference** | **Scale - 1** |
+============+=======================+===============+
| ``LSR`` | [0, 1] | [0, 1] |
+------------+-----------------------+---------------+
References
----------
:cite:`LeicaCameraAG2022`
Examples
--------
>>> log_decoding_LLog(0.43531390404392656) # doctest: +ELLIPSIS
0.1800000...
"""
LLog = to_domain_1(LLog)
LLog = LLog if in_normalised_code_value else full_to_legal(LLog, bit_depth)
cut2 = constants.cut2
a = constants.a
b = constants.b
c = constants.c
d = constants.d
e = constants.e
f = constants.f
LSR = np.where(
LLog <= cut2,
(LLog - b) / a,
(spow(10, (LLog - f) / c) - e) / d,
)
if not out_reflection:
LSR = LSR / 0.9
return as_float(from_range_1(LSR))