diff --git a/colour/models/rgb/transfer_functions/__init__.py b/colour/models/rgb/transfer_functions/__init__.py index 987d0e4aad..eb2c34140c 100644 --- a/colour/models/rgb/transfer_functions/__init__.py +++ b/colour/models/rgb/transfer_functions/__init__.py @@ -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) @@ -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' ] @@ -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`}, @@ -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. @@ -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] @@ -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`}, @@ -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. @@ -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'}**, @@ -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... """ diff --git a/colour/models/rgb/transfer_functions/aces.py b/colour/models/rgb/transfer_functions/aces.py index 9a9b3968ff..c8c33d5df7 100644 --- a/colour/models/rgb/transfer_functions/aces.py +++ b/colour/models/rgb/transfer_functions/aces.py @@ -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' @@ -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( @@ -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. @@ -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 @@ -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. @@ -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 diff --git a/colour/models/rgb/transfer_functions/common.py b/colour/models/rgb/transfer_functions/common.py new file mode 100644 index 0000000000..532b49bcbf --- /dev/null +++ b/colour/models/rgb/transfer_functions/common.py @@ -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 +`_ +""" + +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 diff --git a/colour/models/rgb/transfer_functions/sony_slog.py b/colour/models/rgb/transfer_functions/sony_slog.py index 146a6ceca4..61441e6b7b 100644 --- a/colour/models/rgb/transfer_functions/sony_slog.py +++ b/colour/models/rgb/transfer_functions/sony_slog.py @@ -21,14 +21,10 @@ References ---------- -.. [1] Gaggioni, H., Dhanendra, P., Yamashita, J., Kawada, N., Endo, K., & - Clark, C. (n.d.). S-Log: A new LUT for digital production mastering - and interchange applications. Retrieved from - http://pro.sony.com/bbsccms/assets/files/mkt/cinema/solutions/\ -slog_manual.pdf -.. [2] Sony Corporation. (n.d.). S-Log Whitepaper. Retrieved from - http://www.theodoropoulos.info/attachments/076_on S-Log.pdf -.. [3] Sony Corporation. (n.d.). Technical Summary for +.. [1] Sony Corporation. (2012). S-Log2 Technical Paper. Retrieved from + https://pro.sony.com/bbsccms/assets/files/micro/dmpc/training/\ +S-Log2_Technical_PaperV1_0.pdf +.. [2] Sony Corporation. (n.d.). Technical Summary for S-Gamut3.Cine/S-Log3 and S-Gamut3/S-Log3. Retrieved from http://community.sony.com/sony/attachments/sony/\ large-sensor-camera-F5-F55/12359/2/\ @@ -39,6 +35,7 @@ import numpy as np from colour.utilities import as_numeric +from colour.models.rgb.transfer_functions import full_to_legal, legal_to_full __author__ = 'Colour Developers' __copyright__ = 'Copyright (C) 2013-2017 - Colour Developers' @@ -53,33 +50,54 @@ ] -def log_encoding_SLog(t): +def log_encoding_SLog(x, bit_depth=10, out_legal=True, in_reflection=True): """ Defines the *Sony S-Log* log encoding curve / opto-electronic transfer function. Parameters ---------- - t : numeric or array_like - Input light level :math:`t` to a camera. + x : numeric or array_like + Reflection or :math:`IRE / 100` input light level :math:`x` to a + camera. + bit_depth : int, optional + Bit depth used for conversion. + out_legal : bool, optional + Whether the non-linear *Sony S-Log* data :math:`y` is encoded in legal + range. + in_reflection : bool, optional + Whether the light level :math:`x` to a camera is reflection. Returns ------- numeric or ndarray - Camera output code :math:`y`. + Non-linear *Sony S-Log* data :math:`y`. Examples -------- >>> log_encoding_SLog(0.18) # doctest: +ELLIPSIS - 0.3599878... + 0.3849708... + >>> log_encoding_SLog(0.18, out_legal=False) # doctest: +ELLIPSIS + 0.3765127... + >>> log_encoding_SLog(0.18, in_reflection=False) # doctest: +ELLIPSIS + 0.3708204... """ - t = np.asarray(t) + x = np.asarray(x) + + if in_reflection: + x = x / 0.9 + + y = np.where(x >= 0, + ((0.432699 * np.log10(x + 0.037584) + 0.616596) + 0.03), + x * 5 + 0.030001222851889303) - return (0.432699 * np.log10(t + 0.037584) + 0.616596) + 0.03 + y = full_to_legal(y, bit_depth) if out_legal else y + return as_numeric(y) -def log_decoding_SLog(y): + +def log_decoding_SLog(y, bit_depth=10, in_legal=True, out_reflection=True): """ Defines the *Sony S-Log* log decoding curve / electro-optical transfer function. @@ -87,52 +105,85 @@ def log_decoding_SLog(y): Parameters ---------- y : numeric or array_like - Camera output code :math:`y`. + Non-linear *Sony S-Log* data :math:`y`. + bit_depth : int, optional + Bit depth used for conversion. + in_legal : bool, optional + Whether the non-linear *Sony S-Log* data :math:`y` is encoded in legal + range. + out_reflection : bool, optional + Whether the light level :math:`x` to a camera is reflection. Returns ------- numeric or ndarray - Input light level :math:`t` to a camera. + Reflection or :math:`IRE / 100` input light level :math:`x` to a + camera. Examples -------- - >>> log_decoding_SLog(0.359987846422154) # doctest: +ELLIPSIS + >>> log_decoding_SLog(0.384970815928670) # doctest: +ELLIPSIS + 0.1... + >>> log_decoding_SLog( + ... 0.376512722254600, in_legal=False) # doctest: +ELLIPSIS + 0.1... + >>> log_decoding_SLog( + ... 0.370820482371268, out_reflection=False) # doctest: +ELLIPSIS 0.1... """ y = np.asarray(y) - return 10 ** ((y - 0.616596 - 0.03) / 0.432699) - 0.037584 + x = legal_to_full(y, bit_depth) if in_legal else y + x = np.where(y >= log_encoding_SLog(0.0, bit_depth, in_legal), + 10 ** ((x - 0.616596 - 0.03) / 0.432699) - 0.037584, + (x - 0.030001222851889303) / 5.0) -def log_encoding_SLog2(t): + if out_reflection: + x = x * 0.9 + + return as_numeric(x) + + +def log_encoding_SLog2(x, bit_depth=10, out_legal=True, in_reflection=True): """ Defines the *Sony S-Log2* log encoding curve / opto-electronic transfer function. Parameters ---------- - t : numeric or array_like - Input light level :math:`t` to a camera. + x : numeric or array_like + Reflection or :math:`IRE / 100` input light level :math:`x` to a + camera. + bit_depth : int, optional + Bit depth used for conversion. + out_legal : bool, optional + Whether the non-linear *Sony S-Log2* data :math:`y` is encoded in legal + range. + in_reflection : bool, optional + Whether the light level :math:`x` to a camera is reflection. Returns ------- numeric or ndarray - Camera output code :math:`y`. + Non-linear *Sony S-Log2* data :math:`y`. Examples -------- >>> log_encoding_SLog2(0.18) # doctest: +ELLIPSIS - 0.3849708... + 0.3395325... + >>> log_encoding_SLog2(0.18, out_legal=False) # doctest: +ELLIPSIS + 0.3234495... + >>> log_encoding_SLog2(0.18, in_reflection=False) # doctest: +ELLIPSIS + 0.3262865... """ - t = np.asarray(t) - - return ((4 * (16 + 219 * (0.616596 + 0.03 + 0.432699 * - (np.log10(0.037584 + t / 0.9))))) / 1023) + return log_encoding_SLog(x * 155 / 219, bit_depth, out_legal, + in_reflection) -def log_decoding_SLog2(y): +def log_decoding_SLog2(y, bit_depth=10, in_legal=True, out_reflection=True): """ Defines the *Sony S-Log2* log decoding curve / electro-optical transfer function. @@ -140,56 +191,85 @@ def log_decoding_SLog2(y): Parameters ---------- y : numeric or array_like - Camera output code :math:`y`. + Non-linear *Sony S-Log2* data :math:`y`. + bit_depth : int, optional + Bit depth used for conversion. + in_legal : bool, optional + Whether the non-linear *Sony S-Log2* data :math:`y` is encoded in legal + range. + out_reflection : bool, optional + Whether the light level :math:`x` to a camera is reflection. Returns ------- numeric or ndarray - Input light level :math:`t` to a camera. + Reflection or :math:`IRE / 100` input light level :math:`x` to a + camera. Examples -------- - >>> log_decoding_SLog2(0.384970815928670) # doctest: +ELLIPSIS + >>> log_decoding_SLog2(0.339532524633774) # doctest: +ELLIPSIS + 0.1... + >>> log_decoding_SLog2( + ... 0.323449512215013, in_legal=False) # doctest: +ELLIPSIS + 0.1... + >>> log_decoding_SLog2( + ... 0.326286538946799, out_reflection=False) # doctest: +ELLIPSIS 0.1... """ - y = np.asarray(y) - - return ((10 ** (((( - (y * 1023 / 4 - 16) / 219) - 0.616596 - 0.03) / 0.432699)) - 0.037584) - * 0.9) + return 219 * log_decoding_SLog(y, bit_depth, in_legal, + out_reflection) / 155 -def log_encoding_SLog3(t): +def log_encoding_SLog3(x, bit_depth=10, out_legal=True, in_reflection=True): """ Defines the *Sony S-Log3* log encoding curve / opto-electronic transfer function. Parameters ---------- - t : numeric or array_like - Input light level :math:`t` to a camera. + x : numeric or array_like + Reflection or :math:`IRE / 100` input light level :math:`x` to a + camera. + bit_depth : int, optional + Bit depth used for conversion. + out_legal : bool, optional + Whether the non-linear *Sony S-Log3* data :math:`y` is encoded in legal + range. + in_reflection : bool, optional + Whether the light level :math:`x` to a camera is reflection. Returns ------- numeric or ndarray - Camera output code :math:`y`. + Non-linear *Sony S-Log3* data :math:`y`. Examples -------- >>> log_encoding_SLog3(0.18) # doctest: +ELLIPSIS 0.4105571... + >>> log_encoding_SLog3(0.18, out_legal=False) # doctest: +ELLIPSIS + 0.4063926... + >>> log_encoding_SLog3(0.18, in_reflection=False) # doctest: +ELLIPSIS + 0.3995079... """ - t = np.asarray(t) + x = np.asarray(x) + + if not in_reflection: + x = x * 0.9 + + y = np.where(x >= 0.01125000, (420 + np.log10( + (x + 0.01) / (0.18 + 0.01)) * 261.5) / 1023, + (x * (171.2102946929 - 95) / 0.01125000 + 95) / 1023) + + y = y if out_legal else legal_to_full(y, bit_depth) - return as_numeric( - np.where(t >= 0.01125000, (420 + np.log10( - (t + 0.01) / (0.18 + 0.01)) * 261.5) / 1023, ( - t * (171.2102946929 - 95) / 0.01125000 + 95) / 1023)) + return as_numeric(y) -def log_decoding_SLog3(y): +def log_decoding_SLog3(y, bit_depth=10, in_legal=True, out_reflection=True): """ Defines the *Sony S-Log3* log decoding curve / electro-optical transfer function. @@ -197,22 +277,42 @@ def log_decoding_SLog3(y): Parameters ---------- y : numeric or array_like - Camera output code :math:`y`. + Non-linear *Sony S-Log3* data :math:`y`. + bit_depth : int, optional + Bit depth used for conversion. + in_legal : bool, optional + Whether the non-linear *Sony S-Log3* data :math:`y` is encoded in legal + range. + out_reflection : bool, optional + Whether the light level :math:`x` to a camera is reflection. Returns ------- numeric or ndarray - Input light level :math:`t` to a camera. + Reflection or :math:`IRE / 100` input light level :math:`x` to a + camera. Examples -------- >>> log_decoding_SLog3(0.410557184750733) # doctest: +ELLIPSIS 0.1... + >>> log_decoding_SLog3( + ... 0.406392694063927, in_legal=False) # doctest: +ELLIPSIS + 0.1... + >>> log_decoding_SLog3( + ... 0.399507939606216, out_reflection=False) # doctest: +ELLIPSIS + 0.1... """ y = np.asarray(y) - return as_numeric( - np.where(y >= 171.2102946929 / 1023, - ((10 ** ((y * 1023 - 420) / 261.5)) * (0.18 + 0.01) - 0.01), ( - y * 1023 - 95) * 0.01125000 / (171.2102946929 - 95))) + y = y if in_legal else full_to_legal(y, bit_depth) + + x = np.where(y >= 171.2102946929 / 1023, + ((10 ** ((y * 1023 - 420) / 261.5)) * (0.18 + 0.01) - 0.01), + (y * 1023 - 95) * 0.01125000 / (171.2102946929 - 95)) + + if not out_reflection: + x = x / 0.9 + + return as_numeric(x) diff --git a/colour/models/rgb/transfer_functions/tests/tests_aces.py b/colour/models/rgb/transfer_functions/tests/tests_aces.py index 4cf37c6f8d..661ad79961 100644 --- a/colour/models/rgb/transfer_functions/tests/tests_aces.py +++ b/colour/models/rgb/transfer_functions/tests/tests_aces.py @@ -46,6 +46,8 @@ def test_log_encoding_ACESproxy(self): self.assertEqual(log_encoding_ACESproxy(0.18), 426) + self.assertEqual(log_encoding_ACESproxy(0.18, 12), 1705) + self.assertEqual(log_encoding_ACESproxy(1.0), 550) def test_n_dimensional_log_encoding_ACESproxy(self): @@ -100,6 +102,9 @@ def test_log_decoding_ACESproxy(self): self.assertAlmostEqual( log_decoding_ACESproxy(426), 0.179244406001978, places=7) + self.assertAlmostEqual( + log_decoding_ACESproxy(1705, 12), 0.179866697501353, places=7) + self.assertAlmostEqual(log_decoding_ACESproxy(550), 1.0, places=7) def test_n_dimensional_log_decoding_ACESproxy(self): diff --git a/colour/models/rgb/transfer_functions/tests/tests_common.py b/colour/models/rgb/transfer_functions/tests/tests_common.py new file mode 100644 index 0000000000..35050eb170 --- /dev/null +++ b/colour/models/rgb/transfer_functions/tests/tests_common.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +Defines unit tests for :mod:`colour.models.rgb.transfer_functions.common` +module. +""" + +from __future__ import division, unicode_literals + +import numpy as np +import unittest + +from colour.models.rgb.transfer_functions import CV_range, legal_to_full, \ + full_to_legal +from colour.utilities import ignore_numpy_errors + +__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__ = 'Development' + +__all__ = ['TestCV_range', 'TestLegalToFull', 'TestFullToLegal'] + + +class TestCV_range(unittest.TestCase): + """ + Defines :func:`colour.models.rgb.transfer_functions.common.CV_range` + definition unit tests methods. + """ + + def test_CV_range(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.common.CV_range` + definition. + """ + + np.testing.assert_array_equal( + CV_range(8, True, True), np.array([16, 235])) + + np.testing.assert_array_equal( + CV_range(8, False, True), np.array([0, 255])) + + np.testing.assert_array_almost_equal( + CV_range(8, True, False), + np.array([0.06274510, 0.92156863]), + decimal=7) + + np.testing.assert_array_equal( + CV_range(8, False, False), np.array([0, 1])) + + np.testing.assert_array_equal( + CV_range(10, True, True), np.array([64, 940])) + + np.testing.assert_array_equal( + CV_range(10, False, True), np.array([0, 1023])) + + np.testing.assert_array_almost_equal( + CV_range(10, True, False), + np.array([0.06256109, 0.91886608]), + decimal=7) + + np.testing.assert_array_equal( + CV_range(10, False, False), np.array([0, 1])) + + +class TestLegalToFull(unittest.TestCase): + """ + Defines :func:`colour.models.rgb.transfer_functions.common.legal_to_full` + definition unit tests methods. + """ + + def test_legal_to_full(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.common.legal_to_full` + definition. + """ + + self.assertAlmostEqual(legal_to_full(64 / 1023), 0.0) + + self.assertAlmostEqual(legal_to_full(940 / 1023), 1.0) + + self.assertAlmostEqual(legal_to_full(64 / 1023, out_int=True), 0) + + self.assertAlmostEqual(legal_to_full(940 / 1023, out_int=True), 1023) + + self.assertAlmostEqual(legal_to_full(64, in_int=True), 0.0) + + self.assertAlmostEqual(legal_to_full(940, in_int=True), 1.0) + + self.assertAlmostEqual(legal_to_full(64, in_int=True, out_int=True), 0) + + self.assertAlmostEqual( + legal_to_full(940, in_int=True, out_int=True), 1023) + + def test_n_dimensional_legal_to_full(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.common.legal_to_full` + definition n-dimensional arrays support. + """ + + CV_l = 0.918866080156403 + CV_f = 1.0 + np.testing.assert_almost_equal( + legal_to_full(CV_l, 10), CV_f, decimal=7) + + CV_l = np.tile(CV_l, 6) + CV_f = np.tile(CV_f, 6) + np.testing.assert_almost_equal( + legal_to_full(CV_l, 10), CV_f, decimal=7) + + CV_l = np.reshape(CV_l, (2, 3)) + CV_f = np.reshape(CV_f, (2, 3)) + np.testing.assert_almost_equal( + legal_to_full(CV_l, 10), CV_f, decimal=7) + + CV_l = np.reshape(CV_l, (2, 3, 1)) + CV_f = np.reshape(CV_f, (2, 3, 1)) + np.testing.assert_almost_equal( + legal_to_full(CV_l, 10), CV_f, decimal=7) + + @ignore_numpy_errors + def test_nan_legal_to_full(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.common.legal_to_full` + definition nan support. + """ + + legal_to_full(np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]), 10) + + +class TestFullToLegal(unittest.TestCase): + """ + Defines :func:`colour.models.rgb.transfer_functions.common.full_to_legal` + definition unit tests methods. + """ + + def test_full_to_legal(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.common.full_to_legal` + definition. + """ + + self.assertAlmostEqual(full_to_legal(0.0), 0.062561094819159) + + self.assertAlmostEqual(full_to_legal(1.0), 0.918866080156403) + + self.assertAlmostEqual(full_to_legal(0.0, out_int=True), 64) + + self.assertAlmostEqual(full_to_legal(1.0, out_int=True), 940) + + self.assertAlmostEqual( + full_to_legal(0, in_int=True), 0.062561094819159) + + self.assertAlmostEqual( + full_to_legal(1023, in_int=True), 0.918866080156403) + + self.assertAlmostEqual(full_to_legal(0, in_int=True, out_int=True), 64) + + self.assertAlmostEqual( + full_to_legal(1023, in_int=True, out_int=True), 940) + + def test_n_dimensional_full_to_legal(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.common.full_to_legal` + definition n-dimensional arrays support. + """ + + CF_f = 1.0 + CV_l = 0.918866080156403 + np.testing.assert_almost_equal( + full_to_legal(CF_f, 10), CV_l, decimal=7) + + CF_f = np.tile(CF_f, 6) + CV_l = np.tile(CV_l, 6) + np.testing.assert_almost_equal( + full_to_legal(CF_f, 10), CV_l, decimal=7) + + CF_f = np.reshape(CF_f, (2, 3)) + CV_l = np.reshape(CV_l, (2, 3)) + np.testing.assert_almost_equal( + full_to_legal(CF_f, 10), CV_l, decimal=7) + + CF_f = np.reshape(CF_f, (2, 3, 1)) + CV_l = np.reshape(CV_l, (2, 3, 1)) + np.testing.assert_almost_equal( + full_to_legal(CF_f, 10), CV_l, decimal=7) + + @ignore_numpy_errors + def test_nan_full_to_legal(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.common.full_to_legal` + definition nan support. + """ + + full_to_legal(np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]), 10) + + +if __name__ == '__main__': + unittest.main() diff --git a/colour/models/rgb/transfer_functions/tests/tests_sony_slog.py b/colour/models/rgb/transfer_functions/tests/tests_sony_slog.py index 97d95bfc6e..85daf126f6 100644 --- a/colour/models/rgb/transfer_functions/tests/tests_sony_slog.py +++ b/colour/models/rgb/transfer_functions/tests/tests_sony_slog.py @@ -10,8 +10,9 @@ import numpy as np import unittest -from colour.models.rgb.transfer_functions import (log_encoding_SLog, - log_decoding_SLog) +from colour.models.rgb.transfer_functions import ( + log_encoding_SLog, log_decoding_SLog, log_encoding_SLog2, + log_decoding_SLog2, log_encoding_SLog3, log_decoding_SLog3) from colour.utilities import ignore_numpy_errors __author__ = 'Colour Developers' @@ -21,7 +22,14 @@ __email__ = 'colour-science@googlegroups.com' __status__ = 'Production' -__all__ = ['TestLogEncoding_SLog', 'TestLogDecoding_SLog'] +__all__ = [ + 'TestLogEncoding_SLog', + 'TestLogDecoding_SLog', + 'TestLogEncoding_SLog2', + 'TestLogDecoding_SLog2', + 'TestLogEncoding_SLog3', + 'TestLogDecoding_SLog3', +] class TestLogEncoding_SLog(unittest.TestCase): @@ -37,13 +45,24 @@ def test_log_encoding_SLog(self): """ self.assertAlmostEqual( - log_encoding_SLog(0.0), 0.030001222851889, places=7) + log_encoding_SLog(0.0), 0.088251291513446, places=7) self.assertAlmostEqual( - log_encoding_SLog(0.18), 0.359987846422154, places=7) + log_encoding_SLog(0.18), 0.384970815928670, places=7) self.assertAlmostEqual( - log_encoding_SLog(1.0), 0.653529251225308, places=7) + log_encoding_SLog(0.18, 12), 0.384688786026891, places=7) + + self.assertAlmostEqual( + log_encoding_SLog(0.18, 10, False), 0.376512722254600, places=7) + + self.assertAlmostEqual( + log_encoding_SLog(0.18, 10, False, False), + 0.359987846422154, + places=7) + + self.assertAlmostEqual( + log_encoding_SLog(1.0), 0.638551684622532, places=7) def test_n_dimensional_log_encoding_SLog(self): """ @@ -52,7 +71,7 @@ def test_n_dimensional_log_encoding_SLog(self): """ L = 0.18 - V = 0.359987846422154 + V = 0.384970815928670 np.testing.assert_almost_equal(log_encoding_SLog(L), V, decimal=7) L = np.tile(L, 6) @@ -90,13 +109,24 @@ def test_log_decoding_SLog(self): """ self.assertAlmostEqual( - log_decoding_SLog(0.0), -0.005545814446077, places=7) + log_decoding_SLog(0.088251291513446), 0.0, places=7) + + self.assertAlmostEqual( + log_decoding_SLog(0.384970815928670), 0.18, places=7) + + self.assertAlmostEqual( + log_decoding_SLog(0.384688786026891, 12), 0.18, places=7) + + self.assertAlmostEqual( + log_decoding_SLog(0.376512722254600, 10, False), 0.18, places=7) self.assertAlmostEqual( - log_decoding_SLog(0.359987846422154), 0.18, places=7) + log_decoding_SLog(0.359987846422154, 10, False, False), + 0.18, + places=7) self.assertAlmostEqual( - log_decoding_SLog(0.653529251225308), 1.0, places=7) + log_decoding_SLog(0.638551684622532), 1.0, places=7) def test_n_dimensional_log_decoding_SLog(self): """ @@ -104,7 +134,7 @@ def test_n_dimensional_log_decoding_SLog(self): log_decoding_SLog` definition n-dimensional arrays support. """ - V = 0.359987846422154 + V = 0.384970815928670 L = 0.18 np.testing.assert_almost_equal(log_decoding_SLog(V), L, decimal=7) @@ -130,5 +160,261 @@ def test_nan_log_decoding_SLog(self): log_decoding_SLog(np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan])) +class TestLogEncoding_SLog2(unittest.TestCase): + """ + Defines :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_encoding_SLog2` definition unit tests methods. + """ + + def test_log_encoding_SLog2(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_encoding_SLog2` definition. + """ + + self.assertAlmostEqual( + log_encoding_SLog2(0.0), 0.088251291513446, places=7) + + self.assertAlmostEqual( + log_encoding_SLog2(0.18), 0.339532524633774, places=7) + + self.assertAlmostEqual( + log_encoding_SLog2(0.18, 12), 0.339283782857486, places=7) + + self.assertAlmostEqual( + log_encoding_SLog2(0.18, 10, False), 0.323449512215013, places=7) + + self.assertAlmostEqual( + log_encoding_SLog2(0.18, 10, False, False), + 0.307980741258647, + places=7) + + self.assertAlmostEqual( + log_encoding_SLog2(1.0), 0.585091059564112, places=7) + + def test_n_dimensional_log_encoding_SLog2(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_encoding_SLog2` definition n-dimensional arrays support. + """ + + L = 0.18 + V = 0.339532524633774 + np.testing.assert_almost_equal(log_encoding_SLog2(L), V, decimal=7) + + L = np.tile(L, 6) + V = np.tile(V, 6) + np.testing.assert_almost_equal(log_encoding_SLog2(L), V, decimal=7) + + L = np.reshape(L, (2, 3)) + V = np.reshape(V, (2, 3)) + np.testing.assert_almost_equal(log_encoding_SLog2(L), V, decimal=7) + + L = np.reshape(L, (2, 3, 1)) + V = np.reshape(V, (2, 3, 1)) + np.testing.assert_almost_equal(log_encoding_SLog2(L), V, decimal=7) + + @ignore_numpy_errors + def test_nan_log_encoding_SLog2(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_encoding_SLog2` definition nan support. + """ + + log_encoding_SLog2(np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan])) + + +class TestLogDecoding_SLog2(unittest.TestCase): + """ + Defines :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_decoding_SLog2` definition unit tests methods. + """ + + def test_log_decoding_SLog2(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_decoding_SLog2` definition. + """ + + self.assertAlmostEqual( + log_decoding_SLog2(0.088251291513446), 0.0, places=7) + + self.assertAlmostEqual( + log_decoding_SLog2(0.339532524633774), 0.18, places=7) + + self.assertAlmostEqual( + log_decoding_SLog2(0.339283782857486, 12), 0.18, places=7) + + self.assertAlmostEqual( + log_decoding_SLog2(0.323449512215013, 10, False), 0.18, places=7) + + self.assertAlmostEqual( + log_decoding_SLog2(0.307980741258647, 10, False, False), + 0.18, + places=7) + + self.assertAlmostEqual( + log_decoding_SLog2(0.585091059564112), 1.0, places=7) + + def test_n_dimensional_log_decoding_SLog2(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_decoding_SLog2` definition n-dimensional arrays support. + """ + + V = 0.339532524633774 + L = 0.18 + np.testing.assert_almost_equal(log_decoding_SLog2(V), L, decimal=7) + + V = np.tile(V, 6) + L = np.tile(L, 6) + np.testing.assert_almost_equal(log_decoding_SLog2(V), L, decimal=7) + + V = np.reshape(V, (2, 3)) + L = np.reshape(L, (2, 3)) + np.testing.assert_almost_equal(log_decoding_SLog2(V), L, decimal=7) + + V = np.reshape(V, (2, 3, 1)) + L = np.reshape(L, (2, 3, 1)) + np.testing.assert_almost_equal(log_decoding_SLog2(V), L, decimal=7) + + @ignore_numpy_errors + def test_nan_log_decoding_SLog2(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_decoding_SLog2` definition nan support. + """ + + log_decoding_SLog2(np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan])) + + +class TestLogEncoding_SLog3(unittest.TestCase): + """ + Defines :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_encoding_SLog3` definition unit tests methods. + """ + + def test_log_encoding_SLog3(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_encoding_SLog3` definition. + """ + + self.assertAlmostEqual( + log_encoding_SLog3(0.0), 0.092864125122190, places=7) + + self.assertAlmostEqual( + log_encoding_SLog3(0.18), 0.41055718475073, places=7) + + self.assertAlmostEqual( + log_encoding_SLog3(0.18, 12), 0.410557184750733, places=7) + + self.assertAlmostEqual( + log_encoding_SLog3(0.18, 10, False), 0.406392694063927, places=7) + + self.assertAlmostEqual( + log_encoding_SLog3(0.18, 10, False, False), + 0.393489294768447, + places=7) + + self.assertAlmostEqual( + log_encoding_SLog3(1.0), 0.596027343690123, places=7) + + def test_n_dimensional_log_encoding_SLog3(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_encoding_SLog3` definition n-dimensional arrays support. + """ + + L = 0.18 + V = 0.41055718475073 + np.testing.assert_almost_equal(log_encoding_SLog3(L), V, decimal=7) + + L = np.tile(L, 6) + V = np.tile(V, 6) + np.testing.assert_almost_equal(log_encoding_SLog3(L), V, decimal=7) + + L = np.reshape(L, (2, 3)) + V = np.reshape(V, (2, 3)) + np.testing.assert_almost_equal(log_encoding_SLog3(L), V, decimal=7) + + L = np.reshape(L, (2, 3, 1)) + V = np.reshape(V, (2, 3, 1)) + np.testing.assert_almost_equal(log_encoding_SLog3(L), V, decimal=7) + + @ignore_numpy_errors + def test_nan_log_encoding_SLog3(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_encoding_SLog3` definition nan support. + """ + + log_encoding_SLog3(np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan])) + + +class TestLogDecoding_SLog3(unittest.TestCase): + """ + Defines :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_decoding_SLog3` definition unit tests methods. + """ + + def test_log_decoding_SLog3(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_decoding_SLog3` definition. + """ + + self.assertAlmostEqual( + log_decoding_SLog3(0.092864125122190), 0.0, places=7) + + self.assertAlmostEqual( + log_decoding_SLog3(0.41055718475073), 0.18, places=7) + + self.assertAlmostEqual( + log_decoding_SLog3(0.410557184750733, 12), 0.18, places=7) + + self.assertAlmostEqual( + log_decoding_SLog3(0.406392694063927, 10, False), 0.18, places=7) + + self.assertAlmostEqual( + log_decoding_SLog3(0.393489294768447, 10, False, False), + 0.18, + places=7) + + self.assertAlmostEqual( + log_decoding_SLog3(0.596027343690123), 1.0, places=7) + + def test_n_dimensional_log_decoding_SLog3(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_decoding_SLog3` definition n-dimensional arrays support. + """ + + V = 0.41055718475073 + L = 0.18 + np.testing.assert_almost_equal(log_decoding_SLog3(V), L, decimal=7) + + V = np.tile(V, 6) + L = np.tile(L, 6) + np.testing.assert_almost_equal(log_decoding_SLog3(V), L, decimal=7) + + V = np.reshape(V, (2, 3)) + L = np.reshape(L, (2, 3)) + np.testing.assert_almost_equal(log_decoding_SLog3(V), L, decimal=7) + + V = np.reshape(V, (2, 3, 1)) + L = np.reshape(L, (2, 3, 1)) + np.testing.assert_almost_equal(log_decoding_SLog3(V), L, decimal=7) + + @ignore_numpy_errors + def test_nan_log_decoding_SLog3(self): + """ + Tests :func:`colour.models.rgb.transfer_functions.sony_slog.\ +log_decoding_SLog3` definition nan support. + """ + + log_decoding_SLog3(np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan])) + + if __name__ == '__main__': unittest.main() diff --git a/colour/models/rgb/ycbcr.py b/colour/models/rgb/ycbcr.py index 51a2e26312..9b3a82b8ea 100644 --- a/colour/models/rgb/ycbcr.py +++ b/colour/models/rgb/ycbcr.py @@ -52,7 +52,8 @@ import numpy as np from colour.utilities import CaseInsensitiveMapping, tsplit, tstack -from colour.models.rgb.transfer_functions import oetf_BT2020, eotf_BT2020 +from colour.models.rgb.transfer_functions import (CV_range, oetf_BT2020, + eotf_BT2020) __author__ = 'Colour Developers' __copyright__ = 'Copyright (C) 2013-2017 - Colour Developers' @@ -62,15 +63,19 @@ __status__ = 'Development' __all__ = [ - 'YCBCR_WEIGHTS', 'RGB_range', 'YCbCr_ranges', 'RGB_to_YCbCr', - 'YCbCr_to_RGB', 'RGB_to_YcCbcCrc', 'YcCbcCrc_to_RGB' + 'YCBCR_WEIGHTS', 'YCbCr_ranges', 'RGB_to_YCbCr', 'YCbCr_to_RGB', + 'RGB_to_YcCbcCrc', 'YcCbcCrc_to_RGB' ] YCBCR_WEIGHTS = CaseInsensitiveMapping({ - 'Rec. 601': np.array([0.2990, 0.1140]), - 'Rec. 709': np.array([0.2126, 0.0722]), - 'Rec. 2020': np.array([0.2627, 0.0593]), - 'SMPTE-240M': np.array([0.2122, 0.0865]) + 'Rec. 601': + np.array([0.2990, 0.1140]), + 'Rec. 709': + np.array([0.2126, 0.0722]), + 'Rec. 2020': + np.array([0.2627, 0.0593]), + 'SMPTE-240M': + np.array([0.2122, 0.0865]) }) """ Luma weightings presets. @@ -80,47 +85,6 @@ """ -def RGB_range(bits, is_legal, is_int): - """" - Returns the *RGB* range array for given bit depth, range legality and - representation. - - Parameters - ---------- - bits : int - Bit depth of the *RGB* output ranges array. - is_legal : bool - Whether the *RGB* output ranges array is legal. - is_int : bool - Whether the *RGB* output ranges array represents integer code values. - - Returns - ------- - ndarray - *RGB* ranges array. - - Examples - -------- - >>> RGB_range(8, True, True) - array([ 16, 235]) - >>> RGB_range(8, True, False) # doctest: +ELLIPSIS - array([ 0.0627451..., 0.9215686...]) - >>> RGB_range(10, False, False) - array([ 0., 1.]) - """ - - if is_legal: - ranges = np.array([16, 235]) - ranges *= 2 ** (bits - 8) - else: - ranges = np.array([0, 2 ** bits - 1]) - - if not is_int: - ranges = ranges.astype(np.float_) / (2 ** bits - 1) - - return ranges - - def YCbCr_ranges(bits, is_legal, is_int): """" Returns the *Y'CbCr* colour encoding ranges array for given bit depth, @@ -153,15 +117,15 @@ def YCbCr_ranges(bits, is_legal, is_int): if is_legal: ranges = np.array([16, 235, 16, 240]) - ranges *= 2 ** (bits - 8) + ranges *= 2**(bits - 8) else: - ranges = np.array([0, 2 ** bits - 1, 0, 2 ** bits - 1]) + ranges = np.array([0, 2**bits - 1, 0, 2**bits - 1]) if not is_int: - ranges = ranges.astype(np.float_) / (2 ** bits - 1) + ranges = ranges.astype(np.float_) / (2**bits - 1) if is_int and not is_legal: - ranges[3] = 2 ** bits + ranges[3] = 2**bits if not is_int and not is_legal: ranges[2] = -0.5 @@ -216,7 +180,7 @@ def RGB_to_YCbCr(RGB, in_range : array_like, optional Array overriding the computed range such as `in_range = (RGB_min, RGB_max)`. If `in_range` is undefined, `RGB_min` - and `RGB_max` will be computed using :func:`RGB_range` definition. + and `RGB_max` will be computed using :func:`CV_range` definition. out_range : array_like, optional Array overriding the computed range such as `out_range = (Y_min, Y_max, C_min, C_max)`. If `out_range` is @@ -306,7 +270,7 @@ def RGB_to_YCbCr(RGB, RGB = np.asarray(RGB) Kr, Kb = K RGB_min, RGB_max = kwargs.get('in_range', - RGB_range(in_bits, in_legal, in_int)) + CV_range(in_bits, in_legal, in_int)) Y_min, Y_max, C_min, C_max = kwargs.get('out_range', YCbCr_ranges( out_bits, out_legal, out_int)) @@ -382,7 +346,7 @@ def YCbCr_to_RGB(YCbCr, out_range : array_like, optional Array overriding the computed range such as `out_range = (RGB_min, RGB_max)`. If `out_range` is undefined, - `RGB_min` and `RGB_max` will be computed using :func:`RGB_range` + `RGB_min` and `RGB_max` will be computed using :func:`CV_range` definition. Returns @@ -415,7 +379,7 @@ def YCbCr_to_RGB(YCbCr, YCbCr_ranges( in_bits, in_legal, in_int)) RGB_min, RGB_max = kwargs.get('out_range', - RGB_range(out_bits, out_legal, out_int)) + CV_range(out_bits, out_legal, out_int)) Y -= Y_min Cb -= (C_max + C_min) / 2