Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 30 additions & 10 deletions colour/models/rgb/transfer_functions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from colour.utilities import CaseInsensitiveMapping, filter_kwargs

from .common import CV_range, legal_to_full, full_to_legal
from .aces import (log_encoding_ACESproxy, log_decoding_ACESproxy,
log_encoding_ACEScc, log_decoding_ACEScc,
log_encoding_ACEScct, log_decoding_ACEScct)
Expand Down Expand Up @@ -39,7 +40,8 @@
from .st_2084 import oetf_ST2084, eotf_ST2084
from .viper_log import log_encoding_ViperLog, log_decoding_ViperLog

__all__ = [
__all__ = ['CV_range', 'legal_to_full', 'full_to_legal']
__all__ += [
'log_encoding_ACESproxy', 'log_decoding_ACESproxy', 'log_encoding_ACEScc',
'log_decoding_ACEScc', 'log_encoding_ACEScct', 'log_decoding_ACEScct'
]
Expand Down Expand Up @@ -145,9 +147,10 @@ def log_encoding_curve(value, curve='Cineon', **kwargs):
Maximum code value: 255, 4095 and 650535 for respectively 8-bit,
12-bit and 16-bit per channel.
bit_depth : unicode, optional
{:func:`log_encoding_ACESproxy`},
**{'10 Bit', '12 Bit'}**,
*ACESproxy* bit depth.
{:func:`log_encoding_ACESproxy`, :func:`log_encoding_SLog`,
:func:`log_encoding_SLog2`},
**{8, 10, 12}**,
Bit depth used for conversion, *ACESproxy* uses **{10, 12}**.
black_offset : numeric or array_like
{:func:`log_encoding_Cineon`, :func:`log_encoding_Panalog`,
:func:`log_encoding_REDLog`, :func:`log_encoding_REDLogFilm`},
Expand All @@ -159,12 +162,20 @@ def log_encoding_curve(value, curve='Cineon', **kwargs):
{:func:`log_encoding_ALEXALogC`},
**{'SUP 3.x', 'SUP 2.x'}**,
Alexa firmware version.
in_reflection : bool, optional
{:func:`log_encoding_SLog`, :func:`log_encoding_SLog2`},
Whether the light level :math:`x` to a camera is reflection.
linear_reference : numeric or array_like
{:func:`log_encoding_PivotedLog`},
Linear reference.
log_reference : numeric or array_like
{:func:`log_encoding_PivotedLog`},
Log reference.
out_legal : bool, optional
{:func:`log_encoding_SLog`, :func:`log_encoding_SLog2`,
:func:`log_encoding_SLog3`},
Whether the non-linear *Sony S-Log*, *Sony S-Log2* or *Sony S-Log3*
data :math:`y` is encoded in legal range.
negative_gamma : numeric or array_like
{:func:`log_encoding_PivotedLog`},
Negative gamma.
Expand All @@ -188,7 +199,7 @@ def log_encoding_curve(value, curve='Cineon', **kwargs):
... 0.18, curve='PLog', log_reference=400)
0.3910068...
>>> log_encoding_curve(0.18, curve='S-Log') # doctest: +ELLIPSIS
0.3599878...
0.3849708...
"""

function = LOG_ENCODING_CURVES[curve]
Expand Down Expand Up @@ -262,10 +273,11 @@ def log_decoding_curve(value, curve='Cineon', **kwargs):
{:func:`log_decoding_ERIMMRGB`},
Maximum code value: 255, 4095 and 650535 for respectively 8-bit,
12-bit and 16-bit per channel.
bit_depth : unicode, optional
{:func:`log_decoding_ACESproxy`},
**{'10 Bit', '12 Bit'}**,
*ACESproxy* bit depth.
bit_depth : int, optional
{:func:`log_decoding_ACESproxy`, :func:`log_decoding_SLog`,
:func:`log_decoding_SLog2`},
**{8, 10, 12}**,
Bit depth used for conversion, *ACESproxy* uses **{10, 12}**.
black_offset : numeric or array_like
{:func:`log_decoding_Cineon`, :func:`log_decoding_Panalog`,
:func:`log_decoding_REDLog`, :func:`log_decoding_REDLogFilm`},
Expand All @@ -277,6 +289,11 @@ def log_decoding_curve(value, curve='Cineon', **kwargs):
{:func:`log_decoding_ALEXALogC`},
**{'SUP 3.x', 'SUP 2.x'}**,
Alexa firmware version.
in_legal : bool, optional
{:func:`log_decoding_SLog`, :func:`log_decoding_SLog2`,
:func:`log_decoding_SLog3`},
Whether the non-linear *Sony S-Log*, *Sony S-Log2* or *Sony S-Log3*
data :math:`y` is encoded in legal range.
linear_reference : numeric or array_like
{:func:`log_decoding_PivotedLog`},
Linear reference.
Expand All @@ -286,6 +303,9 @@ def log_decoding_curve(value, curve='Cineon', **kwargs):
negative_gamma : numeric or array_like
{:func:`log_decoding_PivotedLog`},
Negative gamma.
out_reflection : bool, optional
{:func:`log_decoding_SLog`, :func:`log_decoding_SLog2`},
Whether the light level :math:`x` to a camera is reflection.
method : unicode, optional
{:func:`log_decoding_ALEXALogC`},
**{'Linear Scene Exposure Factor', 'Normalised Sensor Signal'}**,
Expand All @@ -307,7 +327,7 @@ def log_decoding_curve(value, curve='Cineon', **kwargs):
... 0.391006842619746, curve='PLog', log_reference=400)
0.1...
>>> log_decoding_curve( # doctest: +ELLIPSIS
... 0.359987846422154, curve='S-Log')
... 0.376512722254600, curve='S-Log')
0.1...
"""

Expand Down
26 changes: 13 additions & 13 deletions colour/models/rgb/transfer_functions/aces.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@

import numpy as np

from colour.utilities import CaseInsensitiveMapping, Structure, as_numeric
from colour.utilities import Structure, as_numeric

__author__ = 'Colour Developers'
__copyright__ = 'Copyright (C) 2013-2017 - Colour Developers'
Expand Down Expand Up @@ -94,15 +94,15 @@
ACES_PROXY_12_CONSTANTS : Structure
"""

ACES_PROXY_CONSTANTS = CaseInsensitiveMapping({
'10 Bit': ACES_PROXY_10_CONSTANTS,
'12 Bit': ACES_PROXY_12_CONSTANTS
})
ACES_PROXY_CONSTANTS = {
10: ACES_PROXY_10_CONSTANTS,
12: ACES_PROXY_12_CONSTANTS
}
"""
Aggregated *ACESproxy* colourspace constants.

ACES_PROXY_CONSTANTS : CaseInsensitiveMapping
**{'10 Bit', '12 Bit'}**
ACES_PROXY_CONSTANTS : dict
**{10, 12}**
"""

ACES_CCT_CONSTANTS = Structure(
Expand All @@ -117,7 +117,7 @@
"""


def log_encoding_ACESproxy(lin_AP1, bit_depth='10 Bit'):
def log_encoding_ACESproxy(lin_AP1, bit_depth=10):
"""
Defines the *ACESproxy* colourspace log encoding curve / opto-electronic
transfer function.
Expand All @@ -126,8 +126,8 @@ def log_encoding_ACESproxy(lin_AP1, bit_depth='10 Bit'):
----------
lin_AP1 : numeric or array_like
*lin_AP1* value.
bit_depth : unicode, optional
**{'10 Bit', '12 Bit'}**,
bit_depth : int, optional
**{10, 12}**,
*ACESproxy* bit depth.

Returns
Expand Down Expand Up @@ -164,7 +164,7 @@ def float_2_cv(x):
return as_numeric(output, int)


def log_decoding_ACESproxy(ACESproxy, bit_depth='10 Bit'):
def log_decoding_ACESproxy(ACESproxy, bit_depth=10):
"""
Defines the *ACESproxy* colourspace log decoding curve / electro-optical
transfer function.
Expand All @@ -173,8 +173,8 @@ def log_decoding_ACESproxy(ACESproxy, bit_depth='10 Bit'):
----------
ACESproxy : numeric or array_like
*ACESproxy* non-linear value.
bit_depth : unicode, optional
**{'10 Bit', '12 Bit'}**,
bit_depth : int, optional
**{10, 12}**,
*ACESproxy* bit depth.

Returns
Expand Down
186 changes: 186 additions & 0 deletions colour/models/rgb/transfer_functions/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Common Transfer Functions Utilities
===================================

Defines various transfer functions common utilities.

See Also
--------
`RGB Colourspaces Jupyter Notebook
<http://nbviewer.jupyter.org/github/colour-science/colour-notebooks/\
blob/master/notebooks/models/rgb.ipynb>`_
"""

from __future__ import division, unicode_literals

import numpy as np

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

__all__ = ['CV_range', 'legal_to_full', 'full_to_legal']


def CV_range(bit_depth=10, is_legal=False, is_int=False):
""""
Returns the code value :math:`CV` range for given bit depth, range legality
and representation.

Parameters
----------
bit_depth : int, optional
Bit depth of the code value :math:`CV` range.
is_legal : bool, optional
Whether the code value :math:`CV` range is legal.
is_int : bool, optional
Whether the code value :math:`CV` range represents integer code values.

Returns
-------
ndarray
Code value :math:`CV` range.

Examples
--------
>>> CV_range(8, True, True)
array([ 16, 235])
>>> CV_range(8, True, False) # doctest: +ELLIPSIS
array([ 0.0627451..., 0.9215686...])
>>> CV_range(10, False, False)
array([ 0., 1.])
"""

if is_legal:
ranges = np.array([16, 235])
ranges *= 2 ** (bit_depth - 8)
else:
ranges = np.array([0, 2 ** bit_depth - 1])

if not is_int:
ranges = ranges.astype(np.float_) / (2 ** bit_depth - 1)

return ranges


def legal_to_full(CV, bit_depth=10, in_int=False, out_int=False):
"""
Converts given code value :math:`CV` or float equivalent of a code value at
a given bit depth from legal range (studio swing) to full range
(full swing).

Parameters
----------
CV : array_like
Legal range code value :math:`CV` or float equivalent of a code value
at a given bit depth.
bit_depth : int, optional
Bit depth used for conversion.
in_int : bool, optional
Whether to treat the input value as integer code value or float
equivalent of a code value at a given bit depth.
out_int : bool, optional
Whether to return value as integer code value or float equivalent of a
code value at a given bit depth.

Returns
-------
ndarray
Full range code value :math:`CV` or float equivalent of a code value
at a given bit depth.

Examples
--------
>>> legal_to_full(64 / 1023)
0.0
>>> legal_to_full(940 / 1023)
1.0
>>> legal_to_full(64 / 1023, out_int=True)
0
>>> legal_to_full(940 / 1023, out_int=True)
1023
>>> legal_to_full(64, in_int=True)
0.0
>>> legal_to_full(940, in_int=True)
1.0
>>> legal_to_full(64, in_int=True, out_int=True)
0
>>> legal_to_full(940, in_int=True, out_int=True)
1023
"""

CV = np.asarray(CV)

MV = 2 ** bit_depth - 1

CV = np.round(CV).astype(np.int_) if in_int else CV * MV

B, W = CV_range(bit_depth, True, True)

CV = (CV - B) / (W - B)

return np.round(CV * MV).astype(np.int_) if out_int else CV


def full_to_legal(CV, bit_depth=10, in_int=False, out_int=False):
"""
Converts given code value :math:`CV` or float equivalent of a code value at
a given bit depth from full range (full swing) to legal range
(studio swing).

Parameters
----------
CV : array_like
Full range code value :math:`CV` or float equivalent of a code value at
a given bit depth.
bit_depth : int, optional
Bit depth used for conversion.
in_int : bool, optional
Whether to treat the input value as integer code value or float
equivalent of a code value at a given bit depth.
out_int : bool, optional
Whether to return value as integer code value or float equivalent of a
code value at a given bit depth.

Returns
-------
ndarray
Legal range code value :math:`CV` or float equivalent of a code value
at a given bit depth.

Examples
--------
>>> full_to_legal(0.0) # doctest: +ELLIPSIS
0.0625610...
>>> full_to_legal(1.0) # doctest: +ELLIPSIS
0.9188660...
>>> full_to_legal(0.0, out_int=True)
64
>>> full_to_legal(1.0, out_int=True)
940
>>> full_to_legal(0, in_int=True) # doctest: +ELLIPSIS
0.0625610...
>>> full_to_legal(1023, in_int=True) # doctest: +ELLIPSIS
0.9188660...
>>> full_to_legal(0, in_int=True, out_int=True)
64
>>> full_to_legal(1023, in_int=True, out_int=True)
940
"""

CV = np.asarray(CV)

MV = 2 ** bit_depth - 1

CV = np.round(CV / MV).astype(np.int_) if in_int else CV

B, W = CV_range(bit_depth, True, True)

CV = (W - B) * CV + B

return np.round(CV).astype(np.int_) if out_int else CV / MV
Loading