Source code for colour.models.rgb.transfer_functions.exponent

# -*- coding: utf-8 -*-
"""
Basic and Monitor-Curve Exponent Transfer Functions
===================================================

Defines the exponent transfer functions:

-   :func:`colour.models.exponent_function_basic`
-   :func:`colour.models.exponent_function_monitor_curve`

References
----------
-   :cite: `TheAcademyofMotionPictureArtsandSciences2020` : The Academy of
    Motion Picture Arts and Sciences, Science and Technology Council, & Academy
    Color Encoding System (ACES) Project Subcommittee. (2020). Specification
    S-2014-006 - Common LUT Format (CLF) - A Common File Format for Look-Up
    Tables. Retrieved June 24, 2020, from http://j.mp/S-2014-006
"""

from __future__ import division, unicode_literals

import numpy as np

from colour.utilities import as_float, as_float_array, suppress_warnings

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

__all__ = ['exponent_function_basic', 'exponent_function_monitor_curve']


[docs]def exponent_function_basic(x, exponent=1, style='basicFwd'): """ Defines the *basic* exponent transfer function. Parameters ---------- x : numeric or array_like Data to undergo the basic exponent conversion. exponent : numeric or array_like, optional Exponent value used for the conversion. style : unicode, optional **{'basicFwd', 'basicRev', 'basicMirrorFwd', 'basicMirrorRev', 'basicPassThruFwd', 'basicPassThruRev'}**, Defines the behaviour for the transfer function to operate: - *basicFwd*: *Basic Forward* exponential behaviour where the definition applies a basic power law using the exponent. Values less than zero are clamped. - *basicRev*: *Basic Reverse* exponential behaviour where the definition applies a basic power law using the exponent. Values less than zero are clamped. - *basicMirrorFwd*: *Basic Mirror Forward* exponential behaviour where the definition applies a basic power law using the exponent for values greater than or equal to zero and mirrors the function for values less than zero (i.e. rotationally symmetric around the origin). - *basicMirrorRev*: *Basic Mirror Reverse* exponential behaviour where the definition applies a basic power law using the exponent for values greater than or equal to zero and mirrors the function for values less than zero (i.e. rotationally symmetric around the origin). - *basicPassThruFwd*: *Basic Pass Forward* exponential behaviour where the definition applies a basic power law using the exponent for values greater than or equal to zero and passes values less than zero unchanged. - *basicPassThruRev*: *Basic Pass Reverse* exponential behaviour where the definition applies a basic power law using the exponent for values greater than or equal to zero and passes values less than zero unchanged. Returns ------- numeric or ndarray Exponentially converted data. Raises ------ ValueError If the *style* is not defined. Examples -------- >>> exponent_function_basic(0.18, 2.2) # doctest: +ELLIPSIS 0.0229932... >>> exponent_function_basic(-0.18, 2.2) 0.0 >>> exponent_function_basic(0.18, 2.2, 'basicRev') # doctest: +ELLIPSIS 0.4586564... >>> exponent_function_basic(-0.18, 2.2, 'basicRev') 0.0 >>> exponent_function_basic( # doctest: +ELLIPSIS ... 0.18, 2.2, 'basicMirrorFwd') 0.0229932... >>> exponent_function_basic( # doctest: +ELLIPSIS ... -0.18, 2.2, 'basicMirrorFwd') -0.0229932... >>> exponent_function_basic( # doctest: +ELLIPSIS ... 0.18, 2.2, 'basicMirrorRev') 0.4586564... >>> exponent_function_basic( # doctest: +ELLIPSIS ... -0.18, 2.2, 'basicMirrorRev') -0.4586564... >>> exponent_function_basic( # doctest: +ELLIPSIS ... 0.18, 2.2, 'basicPassThruFwd') 0.0229932... >>> exponent_function_basic( # doctest: +ELLIPSIS ... -0.18, 2.2, 'basicPassThruFwd') -0.1799999... >>> exponent_function_basic( # doctest: +ELLIPSIS ... 0.18, 2.2, 'basicPassThruRev') 0.4586564... >>> exponent_function_basic( # doctest: +ELLIPSIS ... -0.18, 2.2, 'basicPassThruRev') -0.1799999... """ x = as_float_array(x) exponent = as_float_array(exponent) def exponent_forward(x): """ Returns the input raised to the exponent value. """ return x ** exponent def exponent_reverse(y): """ Returns the input raised to the inverse exponent value. """ return y ** (1 / exponent) style = style.lower() if style == 'basicfwd': return as_float(np.where(x >= 0, exponent_forward(x), 0)) elif style == 'basicrev': return as_float(np.where(x >= 0, exponent_reverse(x), 0)) elif style == 'basicmirrorfwd': return as_float( np.where(x >= 0, exponent_forward(x), -exponent_forward(-x))) elif style == 'basicmirrorrev': return as_float( np.where(x >= 0, exponent_reverse(x), -exponent_reverse(-x))) elif style == 'basicpassthrufwd': return as_float(np.where(x >= 0, exponent_forward(x), x)) elif style == 'basicpassthrurev': return as_float(np.where(x >= 0, exponent_reverse(x), x)) else: raise ValueError( 'Undefined style used: "{0}", must be one of the following: ' '"{1}".'.format( style, ', '.join([ 'basicFwd', 'basicRev', 'basicMirrorFwd', 'basicMirrorRev', 'basicPassThruFwd', 'basicPassThruRev' ])))
[docs]def exponent_function_monitor_curve(x, exponent=1, offset=0, style='monCurveFwd'): """ Defines the *Monitor Curve* exponent transfer function. Parameters ---------- x : numeric or array_like Data to undergo the monitor curve exponential conversion. exponent : numeric or array_like, optional Exponent value used for the conversion. offset: numeric or array_like, optional Offset value used for the conversion. style : unicode, optional **{'monCurveFwd', 'monCurveRev', 'monCurveMirrorFwd', 'monCurveMirrorRev'}**, Defines the behaviour for the transfer function to operate: - *monCurveFwd*: *Monitor Curve Forward* exponential behaviour where the definition applies a power law function with a linear segment near the origin. - *monCurveRev*: *Monitor Curve Reverse* exponential behaviour where the definition applies a power law function with a linear segment near the origin. - *monCurveMirrorFwd*: *Monitor Curve Mirror Forward* exponential behaviour where the definition applies a power law function with a linear segment near the origin and mirrors the function for values less than zero (i.e. rotationally symmetric around the origin). - *monCurveMirrorRev*: *Monitor Curve Mirror Reverse* exponential behaviour where the definition applies a power law function with a linear segment near the origin and mirrors the function for values less than zero (i.e. rotationally symmetric around the origin). Returns ------- numeric or ndarray Exponentially converted data. Raises ------ ValueError If the *style* is not defined. Examples -------- >>> exponent_function_monitor_curve( # doctest: +ELLIPSIS ... 0.18, 2.2, 0.001) 0.0232240... >>> exponent_function_monitor_curve( # doctest: +ELLIPSIS ... -0.18, 2.2, 0.001) -0.0002054... >>> exponent_function_monitor_curve( # doctest: +ELLIPSIS ... 0.18, 2.2, 0.001, 'monCurveRev') 0.4581151... >>> exponent_function_monitor_curve( # doctest: +ELLIPSIS ... -0.18, 2.2, 0.001, 'monCurveRev') -157.7302795... >>> exponent_function_monitor_curve( # doctest: +ELLIPSIS ... 0.18, 2.2, 2, 'monCurveMirrorFwd') 0.1679399... >>> exponent_function_monitor_curve( # doctest: +ELLIPSIS ... -0.18, 2.2, 0.001, 'monCurveMirrorFwd') -0.0232240... >>> exponent_function_monitor_curve( # doctest: +ELLIPSIS ... 0.18, 2.2, 0.001, 'monCurveMirrorRev') 0.4581151... >>> exponent_function_monitor_curve( # doctest: +ELLIPSIS ... -0.18, 2.2, 0.001, 'monCurveMirrorRev') -0.4581151... """ x = as_float_array(x) exponent = as_float_array(exponent) offset = as_float_array(offset) with suppress_warnings(python_warnings=True): s = as_float_array(((exponent - 1) / offset) * ((exponent * offset) / ( (exponent - 1) * (offset + 1))) ** exponent) s[np.isnan(s)] = 1 def monitor_curve_forward(x): """ Defines the *Monitor Curve Forward* function. """ x_break = offset / (exponent - 1) return np.where( x >= x_break, ((x + offset) / (1 + offset)) ** exponent, x * s, ) def monitor_curve_reverse(y): """ Defines the *Monitor Curve Reverse* function. """ y_break = ((exponent * offset) / ( (exponent - 1) * (1 + offset))) ** exponent return np.where( y >= y_break, ((1 + offset) * (y ** (1 / exponent))) - offset, y / s, ) style = style.lower() if style == 'moncurvefwd': return as_float(monitor_curve_forward(x)) elif style == 'moncurverev': return as_float(monitor_curve_reverse(x)) elif style == 'moncurvemirrorfwd': return as_float( np.where( x >= 0, monitor_curve_forward(x), -monitor_curve_forward(-x), )) elif style == 'moncurvemirrorrev': return as_float( np.where( x >= 0, monitor_curve_reverse(x), -monitor_curve_reverse(-x), )) else: raise ValueError( 'Undefined style used: "{0}", must be one of the following: ' '"{1}".'.format( style, ', '.join([ 'monCurveFwd', 'monCurveRev', 'monCurveMirrorFwd', 'monCurveMirrorRev' ])))