Source code for colour.models.log

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Log Conversion
==============

Defines various *linear* to *log* and *log* to *linear* conversion functions:

-   :attr:`linear_to_cineon`
-   :attr:`cineon_to_linear`
-   :attr:`linear_to_panalog`
-   :attr:`panalog_to_linear`
-   :attr:`linear_to_red_log`
-   :attr:`red_log_to_linear`
-   :attr:`linear_to_viper_log`
-   :attr:`viper_log_to_linear`
-   :attr:`linear_to_pivoted_log`
-   :attr:`pivoted_log_to_linear`
-   :attr:`linear_to_c_log`
-   :attr:`c_log_to_linear`
-   :attr:`linear_to_aces_cc`
-   :attr:`aces_cc_to_linear`
-   :attr:`linear_to_alexa_log_c`
-   :attr:`alexa_log_c_to_linear`
-   :attr:`linear_to_dci_p3_log`
-   :attr:`dci_p3_log_to_linear`
-   :attr:`linear_to_s_log`
-   :attr:`s_log_to_linear`
-   :attr:`linear_to_s_log2`
-   :attr:`s_log2_to_linear`
-   :attr:`linear_to_s_log3`
-   :attr:`s_log3_to_linear`

See Also
--------
`Log Conversion IPython Notebook
<http://nbviewer.ipython.org/github/colour-science/colour-ipython/blob/master/notebooks/models/log.ipynb>`_  # noqa

References
----------
.. [1]  Sony Imageworks. (2012). make.py. Retrieved November 27, 2014, from
        https://github.com/imageworks/OpenColorIO-Configs/blob/master/nuke-default/make.py  # noqa
"""

from __future__ import division, unicode_literals

import numpy as np

from colour.models.dataset.aces import (
    ACES_CC_TRANSFER_FUNCTION,
    ACES_CC_INVERSE_TRANSFER_FUNCTION)
from colour.models.dataset.alexa_wide_gamut_rgb import (
    ALEXA_WIDE_GAMUT_RGB_TRANSFER_FUNCTION,
    ALEXA_WIDE_GAMUT_RGB_INVERSE_TRANSFER_FUNCTION)
from colour.models.dataset.dci_p3 import (
    DCI_P3_TRANSFER_FUNCTION,
    DCI_P3_INVERSE_TRANSFER_FUNCTION)
from colour.models.dataset.s_gamut import (
    S_LOG_TRANSFER_FUNCTION,
    S_LOG2_TRANSFER_FUNCTION,
    S_LOG3_TRANSFER_FUNCTION,
    S_LOG_INVERSE_TRANSFER_FUNCTION,
    S_LOG2_INVERSE_TRANSFER_FUNCTION,
    S_LOG3_INVERSE_TRANSFER_FUNCTION)
from colour.utilities import CaseInsensitiveMapping

__author__ = 'Colour Developers'
__copyright__ = 'Copyright (C) 2013 - 2015 - Colour Developers'
__license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause'
__maintainer__ = 'Colour Developers'
__email__ = 'colour-science@googlegroups.com'
__status__ = 'Production'

__all__ = ['linear_to_cineon',
           'cineon_to_linear',
           'linear_to_panalog',
           'panalog_to_linear',
           'linear_to_red_log',
           'red_log_to_linear',
           'linear_to_viper_log',
           'viper_log_to_linear',
           'linear_to_pivoted_log',
           'pivoted_log_to_linear',
           'linear_to_c_log',
           'c_log_to_linear',
           'linear_to_aces_cc',
           'aces_cc_to_linear',
           'linear_to_alexa_log_c',
           'alexa_log_c_to_linear',
           'linear_to_dci_p3_log',
           'dci_p3_log_to_linear',
           'linear_to_s_log',
           's_log_to_linear',
           'linear_to_s_log2',
           's_log2_to_linear',
           'linear_to_s_log3',
           's_log3_to_linear',
           'LINEAR_TO_LOG_METHODS',
           'LOG_TO_LINEAR_METHODS',
           'linear_to_log',
           'log_to_linear']


[docs]def linear_to_cineon(value, black_offset=10 ** ((95 - 685) / 300), **kwargs): """ Defines the *linear* to *Cineon* conversion function. Parameters ---------- value : numeric *Linear* value. black_offset : numeric Black offset. \*\*kwargs : \*\*, optional Unused parameter provided for signature compatibility with other *linear* / *log* conversion objects. Returns ------- numeric *Cineon* value. Examples -------- >>> linear_to_cineon(0.18) # doctest: +ELLIPSIS 0.4573196... """ return ((685 + 300 * np.log10(value * (1 - black_offset) + black_offset)) / 1023)
[docs]def cineon_to_linear(value, black_offset=10 ** ((95 - 685) / 300), **kwargs): """ Defines the *Cineon* to *linear* conversion function. Parameters ---------- value : numeric *Cineon* value. black_offset : numeric Black offset. \*\*kwargs : \*\*, optional Unused parameter provided for signature compatibility with other *linear* / *log* conversion objects. Returns ------- numeric *Linear* value. Examples -------- >>> cineon_to_linear(0.45731961308541841) # doctest: +ELLIPSIS 0.18... """ return ((10 ** ((1023 * value - 685) / 300) - black_offset) / (1 - black_offset))
[docs]def linear_to_panalog(value, black_offset=10 ** ((64 - 681) / 444), **kwargs): """ Defines the *linear* to *Panalog* conversion function. Parameters ---------- value : numeric *Linear* value. black_offset : numeric Black offset. \*\*kwargs : \*\*, optional Unused parameter provided for signature compatibility with other *linear* / *log* conversion objects. Returns ------- numeric *Panalog* value. Examples -------- >>> linear_to_panalog(0.18) # doctest: +ELLIPSIS 0.3745767... """ return ((681 + 444 * np.log10(value * (1 - black_offset) + black_offset)) / 1023)
[docs]def panalog_to_linear(value, black_offset=10 ** ((64 - 681) / 444), **kwargs): """ Defines the *Panalog* to *linear* conversion function. Parameters ---------- value : numeric *Panalog* value. black_offset : numeric Black offset. \*\*kwargs : \*\*, optional Unused parameter provided for signature compatibility with other *linear* / *log* conversion objects. Returns ------- numeric *Linear* value. Examples -------- >>> panalog_to_linear(0.37457679138229816) # doctest: +ELLIPSIS 0.1... """ return ((10 ** ((1023 * value - 681) / 444) - black_offset) / (1 - black_offset))
[docs]def linear_to_red_log(value, black_offset=10 ** ((0 - 1023) / 511), **kwargs): """ Defines the *linear* to *REDLog* conversion function. Parameters ---------- value : numeric *Linear* value. black_offset : numeric Black offset. \*\*kwargs : \*\*, optional Unused parameter provided for signature compatibility with other *linear* / *log* conversion objects. Returns ------- numeric *REDLog* value. Examples -------- >>> linear_to_red_log(0.18) # doctest: +ELLIPSIS 0.6376218... """ return ((1023 + 511 * np.log10(value * (1 - black_offset) + black_offset)) / 1023)
[docs]def red_log_to_linear(value, black_offset=10 ** ((0 - 1023) / 511), **kwargs): """ Defines the *REDLog* to *linear* conversion function. Parameters ---------- value : numeric *REDLog* value. black_offset : numeric Black offset. \*\*kwargs : \*\*, optional Unused parameter provided for signature compatibility with other *linear* / *log* conversion objects. Returns ------- numeric *Linear* value. Examples -------- >>> red_log_to_linear(0.63762184598817484) # doctest: +ELLIPSIS 0.1... """ return (((10 ** ((1023 * value - 1023) / 511)) - black_offset) / (1 - black_offset))
[docs]def linear_to_viper_log(value, **kwargs): """ Defines the *linear* to *ViperLog* conversion function. Parameters ---------- value : numeric *Linear* value. \*\*kwargs : \*\*, optional Unused parameter provided for signature compatibility with other *linear* / *log* conversion objects. Returns ------- numeric *ViperLog* value. Examples -------- >>> linear_to_viper_log(0.18) # doctest: +ELLIPSIS 0.6360080... """ return (1023 + 500 * np.log10(value)) / 1023
[docs]def viper_log_to_linear(value, **kwargs): """ Defines the *ViperLog* to *linear* conversion function. Parameters ---------- value : numeric *ViperLog* value. \*\*kwargs : \*\*, optional Unused parameter provided for signature compatibility with other *linear* / *log* conversion objects. Returns ------- numeric *Linear* value. Examples -------- >>> viper_log_to_linear(0.63600806701041346) # doctest: +ELLIPSIS 0.1799999... """ return 10 ** ((1023 * value - 1023) / 500)
[docs]def linear_to_pivoted_log(value, log_reference=445, linear_reference=0.18, negative_gamma=0.6, density_per_code_value=0.002): """ Defines the *linear* to *Josh Pines* style pivoted log conversion function. Parameters ---------- value : numeric *Linear* value. log_reference : numeric Log reference. linear_reference : numeric Linear reference. negative_gamma : numeric Negative gamma. density_per_code_value : numeric Density per code value. Returns ------- numeric *Josh Pines* style pivoted log value. Examples -------- >>> linear_to_pivoted_log(0.18) # doctest: +ELLIPSIS 0.4349951... """ return ((log_reference + np.log10(value / linear_reference) / (density_per_code_value / negative_gamma)) / 1023)
[docs]def pivoted_log_to_linear(value, log_reference=445, linear_reference=0.18, negative_gamma=0.6, density_per_code_value=0.002): """ Defines the *Josh Pines* style pivoted log to *linear* conversion function. Parameters ---------- value : numeric *Josh Pines* style pivoted log value. log_reference : numeric Log reference. linear_reference : numeric Linear reference. negative_gamma : numeric Negative gamma. density_per_code_value : numeric Density per code value. Returns ------- numeric *Linear* value. Examples -------- >>> pivoted_log_to_linear(0.43499511241446726) # doctest: +ELLIPSIS 0.1... """ return (10 ** ((value * 1023 - log_reference) * (density_per_code_value / negative_gamma)) * linear_reference)
[docs]def linear_to_c_log(value, **kwargs): """ Defines the *linear* to *Canon Log* conversion function. Parameters ---------- value : numeric *Linear* value. \*\*kwargs : \*\*, optional Unused parameter provided for signature compatibility with other *linear* / *log* conversion objects. Returns ------- numeric *Canon Log* value. References ---------- .. [2] Thorpe, L. (2012). CANON-LOG TRANSFER CHARACTERISTIC. Retrieved from http://downloads.canon.com/CDLC/Canon-Log_Transfer_Characteristic_6-20-2012.pdf # noqa Examples -------- >>> linear_to_c_log(0.20) * 100 # doctest: +ELLIPSIS 32.7953896... """ return 0.529136 * np.log10(10.1596 * value + 1) + 0.0730597
[docs]def c_log_to_linear(value, **kwargs): """ Defines the *Canon Log* to *linear* conversion function. [2]_ Parameters ---------- value : numeric *Canon Log* value. \*\*kwargs : \*\*, optional Unused parameter provided for signature compatibility with other *linear* / *log* conversion objects. Returns ------- numeric *Linear* value. Examples -------- >>> c_log_to_linear(32.795389693580908 / 100) # doctest: +ELLIPSIS 0.19999999... """ return -0.071622555735168 * ( 1.3742747797867 - np.exp(1) ** (4.3515940948906 * value))
linear_to_aces_cc = ( lambda x, **kwargs: ACES_CC_TRANSFER_FUNCTION(x)) aces_cc_to_linear = ( lambda x, **kwargs: ACES_CC_INVERSE_TRANSFER_FUNCTION(x)) linear_to_alexa_log_c = ( lambda x, **kwargs: ALEXA_WIDE_GAMUT_RGB_TRANSFER_FUNCTION(x)) alexa_log_c_to_linear = ( lambda x, **kwargs: ALEXA_WIDE_GAMUT_RGB_INVERSE_TRANSFER_FUNCTION(x)) linear_to_dci_p3_log = ( lambda x, **kwargs: DCI_P3_TRANSFER_FUNCTION(x)) dci_p3_log_to_linear = ( lambda x, **kwargs: DCI_P3_INVERSE_TRANSFER_FUNCTION(x)) linear_to_s_log = lambda x, **kwargs: S_LOG_TRANSFER_FUNCTION(x) s_log_to_linear = lambda x, **kwargs: S_LOG_INVERSE_TRANSFER_FUNCTION(x) linear_to_s_log2 = lambda x, **kwargs: S_LOG2_TRANSFER_FUNCTION(x) s_log2_to_linear = lambda x, **kwargs: S_LOG2_INVERSE_TRANSFER_FUNCTION(x) linear_to_s_log3 = lambda x, **kwargs: S_LOG3_TRANSFER_FUNCTION(x) s_log3_to_linear = lambda x, **kwargs: S_LOG3_INVERSE_TRANSFER_FUNCTION(x) LINEAR_TO_LOG_METHODS = CaseInsensitiveMapping( {'Cineon': linear_to_cineon, 'Panalog': linear_to_panalog, 'REDLog': linear_to_red_log, 'ViperLog': linear_to_viper_log, 'PLog': linear_to_pivoted_log, 'C-Log': linear_to_c_log, 'ACEScc': linear_to_aces_cc, 'ALEXA Log C': linear_to_alexa_log_c, 'DCI-P3': linear_to_dci_p3_log, 'S-Log': linear_to_s_log, 'S-Log2': linear_to_s_log2, 'S-Log3': linear_to_s_log3}) """ Supported *linear* to *log* computations methods. LINEAR_TO_LOG_METHODS : CaseInsensitiveMapping {'Cineon', 'Panalog', 'REDLog', 'ViperLog', 'PLog', 'C-Log', 'ACEScc', 'ALEXA Log C', 'DCI-P3', 'S-Log', 'S-Log2', 'S-Log3'} """
[docs]def linear_to_log(value, method='Cineon', **kwargs): """ Converts from *linear* to *log* using given method. Parameters ---------- value : numeric Value. method : unicode, optional {'Cineon', 'Panalog', 'REDLog', 'ViperLog', 'PLog', 'C-Log', 'ACEScc', 'ALEXA Log C', 'DCI-P3', 'S-Log', 'S-Log2', 'S-Log3'}, Computation method. \*\*kwargs : \*\* Keywords arguments. Returns ------- numeric *Log* value. Examples -------- >>> linear_to_log(0.18) # doctest: +ELLIPSIS 0.4573196... >>> linear_to_log(0.18, method='ACEScc') # doctest: +ELLIPSIS 0.4135884... >>> linear_to_log(0.18, method='PLog', log_reference=400) # noqa # doctest: +ELLIPSIS 0.3910068... >>> linear_to_log(0.18, method='S-Log') # doctest: +ELLIPSIS 0.3599878... """ return LINEAR_TO_LOG_METHODS.get(method)(value, **kwargs)
LOG_TO_LINEAR_METHODS = CaseInsensitiveMapping( {'Cineon': cineon_to_linear, 'Panalog': panalog_to_linear, 'REDLog': red_log_to_linear, 'ViperLog': viper_log_to_linear, 'PLog': pivoted_log_to_linear, 'C-Log': c_log_to_linear, 'ACEScc': aces_cc_to_linear, 'ALEXA Log C': alexa_log_c_to_linear, 'DCI-P3': dci_p3_log_to_linear, 'S-Log': s_log_to_linear, 'S-Log2': s_log2_to_linear, 'S-Log3': s_log3_to_linear}) """ Supported *log* to *linear* computations methods. LOG_TO_LINEAR_METHODS : CaseInsensitiveMapping {'Cineon', 'Panalog', 'REDLog', 'ViperLog', 'PLog', 'C-Log', 'ACEScc', 'ALEXA Log C', 'DCI-P3', 'S-Log', 'S-Log2', 'S-Log3'} """
[docs]def log_to_linear(value, method='Cineon', **kwargs): """ Converts from *log* to *linear* using given method. Parameters ---------- value : numeric Value. method : unicode, optional {'Cineon', 'Panalog', 'REDLog', 'ViperLog', 'PLog', 'C-Log', 'ACEScc', 'ALEXA Log C', 'DCI-P3', 'S-Log', 'S-Log2', 'S-Log3'}, Computation method. \*\*kwargs : \*\* Keywords arguments. Returns ------- numeric *Log* value. Examples -------- >>> log_to_linear(0.45731961308541841) # doctest: +ELLIPSIS 0.18... >>> log_to_linear(0.41358840249244228, method='ACEScc') # noqa # doctest: +ELLIPSIS 0.18... >>> log_to_linear(0.39100684261974583, method='PLog', log_reference=400) # noqa # doctest: +ELLIPSIS 0.1... >>> log_to_linear(0.35998784642215442, method='S-Log') # noqa # doctest: +ELLIPSIS 0.1799999... """ return LOG_TO_LINEAR_METHODS.get(method)(value, **kwargs)