From d0152dcc9e49f912bd116b502aee613dc91c486c Mon Sep 17 00:00:00 2001 From: Thomas Mansencal Date: Mon, 24 Oct 2022 21:14:41 +1300 Subject: [PATCH] Implement support for "ARRI Wide Gamut 4" and "ARRI LogC4" Closes #992. --- README.rst | 3 + colour/models/__init__.py | 6 + colour/models/rgb/__init__.py | 6 + colour/models/rgb/datasets/__init__.py | 6 +- colour/models/rgb/datasets/arri.py | 62 +++++++ .../models/rgb/transfer_functions/__init__.py | 17 +- colour/models/rgb/transfer_functions/arri.py | 147 ++++++++++++++++ .../rgb/transfer_functions/tests/test_arri.py | 162 ++++++++++++++++++ docs/colour.models.rst | 1 + docs/index.rst | 3 + 10 files changed, 411 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index f898dddd28..d9f3d41f08 100644 --- a/README.rst +++ b/README.rst @@ -1011,6 +1011,7 @@ RGB Colourspaces 'ACEScg', 'ACESproxy', 'ARRI Wide Gamut 3', + 'ARRI Wide Gamut 4', 'Adobe RGB (1998)', 'Adobe Wide Gamut RGB', 'Apple RGB', @@ -1127,6 +1128,7 @@ Log Encoding / Decoding 'ACEScct', 'ACESproxy', 'ARRI LogC3', + 'ARRI LogC4', 'Canon Log', 'Canon Log 2', 'Canon Log 3', @@ -1162,6 +1164,7 @@ CCTFs Encoding / Decoding 'ACEScct', 'ACESproxy', 'ARRI LogC3', + 'ARRI LogC4', 'ARIB STD-B67', 'Canon Log', 'Canon Log 2', diff --git a/colour/models/__init__.py b/colour/models/__init__.py index ff4addcbec..a7d96fdfcc 100644 --- a/colour/models/__init__.py +++ b/colour/models/__init__.py @@ -128,6 +128,8 @@ oetf_inverse_ARIBSTDB67, log_encoding_ARRILogC3, log_decoding_ARRILogC3, + log_encoding_ARRILogC4, + log_decoding_ARRILogC4, oetf_BlackmagicFilmGeneration5, oetf_inverse_BlackmagicFilmGeneration5, log_encoding_CanonLog, @@ -271,6 +273,7 @@ RGB_COLOURSPACE_ADOBE_RGB1998, RGB_COLOURSPACE_ADOBE_WIDE_GAMUT_RGB, RGB_COLOURSPACE_ARRI_WIDE_GAMUT_3, + RGB_COLOURSPACE_ARRI_WIDE_GAMUT_4, RGB_COLOURSPACE_APPLE_RGB, RGB_COLOURSPACE_BEST_RGB, RGB_COLOURSPACE_BETA_RGB, @@ -526,6 +529,8 @@ "oetf_inverse_ARIBSTDB67", "log_encoding_ARRILogC3", "log_decoding_ARRILogC3", + "log_encoding_ARRILogC4", + "log_decoding_ARRILogC4", "oetf_BlackmagicFilmGeneration5", "oetf_inverse_BlackmagicFilmGeneration5", "log_encoding_CanonLog", @@ -669,6 +674,7 @@ "RGB_COLOURSPACE_ADOBE_RGB1998", "RGB_COLOURSPACE_ADOBE_WIDE_GAMUT_RGB", "RGB_COLOURSPACE_ARRI_WIDE_GAMUT_3", + "RGB_COLOURSPACE_ARRI_WIDE_GAMUT_4", "RGB_COLOURSPACE_APPLE_RGB", "RGB_COLOURSPACE_BEST_RGB", "RGB_COLOURSPACE_BETA_RGB", diff --git a/colour/models/rgb/__init__.py b/colour/models/rgb/__init__.py index 2beb7298a1..e1e7558744 100644 --- a/colour/models/rgb/__init__.py +++ b/colour/models/rgb/__init__.py @@ -23,6 +23,8 @@ oetf_inverse_ARIBSTDB67, log_encoding_ARRILogC3, log_decoding_ARRILogC3, + log_encoding_ARRILogC4, + log_decoding_ARRILogC4, oetf_BlackmagicFilmGeneration5, oetf_inverse_BlackmagicFilmGeneration5, log_encoding_CanonLog, @@ -166,6 +168,7 @@ RGB_COLOURSPACE_ADOBE_RGB1998, RGB_COLOURSPACE_ADOBE_WIDE_GAMUT_RGB, RGB_COLOURSPACE_ARRI_WIDE_GAMUT_3, + RGB_COLOURSPACE_ARRI_WIDE_GAMUT_4, RGB_COLOURSPACE_APPLE_RGB, RGB_COLOURSPACE_BEST_RGB, RGB_COLOURSPACE_BETA_RGB, @@ -288,6 +291,8 @@ "oetf_inverse_ARIBSTDB67", "log_encoding_ARRILogC3", "log_decoding_ARRILogC3", + "log_encoding_ARRILogC4", + "log_decoding_ARRILogC4", "oetf_BlackmagicFilmGeneration5", "oetf_inverse_BlackmagicFilmGeneration5", "log_encoding_CanonLog", @@ -431,6 +436,7 @@ "RGB_COLOURSPACE_ADOBE_RGB1998", "RGB_COLOURSPACE_ADOBE_WIDE_GAMUT_RGB", "RGB_COLOURSPACE_ARRI_WIDE_GAMUT_3", + "RGB_COLOURSPACE_ARRI_WIDE_GAMUT_4", "RGB_COLOURSPACE_APPLE_RGB", "RGB_COLOURSPACE_BEST_RGB", "RGB_COLOURSPACE_BETA_RGB", diff --git a/colour/models/rgb/datasets/__init__.py b/colour/models/rgb/datasets/__init__.py index d9b2eac0b7..0cae684fe1 100644 --- a/colour/models/rgb/datasets/__init__.py +++ b/colour/models/rgb/datasets/__init__.py @@ -11,7 +11,10 @@ from .adobe_rgb_1998 import RGB_COLOURSPACE_ADOBE_RGB1998 from .adobe_wide_gamut_rgb import RGB_COLOURSPACE_ADOBE_WIDE_GAMUT_RGB from .apple_rgb import RGB_COLOURSPACE_APPLE_RGB -from .arri import RGB_COLOURSPACE_ARRI_WIDE_GAMUT_3 +from .arri import ( + RGB_COLOURSPACE_ARRI_WIDE_GAMUT_3, + RGB_COLOURSPACE_ARRI_WIDE_GAMUT_4, +) from .best_rgb import RGB_COLOURSPACE_BEST_RGB from .beta_rgb import RGB_COLOURSPACE_BETA_RGB from .blackmagic_design import RGB_COLOURSPACE_BLACKMAGIC_WIDE_GAMUT @@ -113,6 +116,7 @@ "RGB_COLOURSPACE_ADOBE_RGB1998", "RGB_COLOURSPACE_ADOBE_WIDE_GAMUT_RGB", "RGB_COLOURSPACE_ARRI_WIDE_GAMUT_3", + "RGB_COLOURSPACE_ARRI_WIDE_GAMUT_4", "RGB_COLOURSPACE_APPLE_RGB", "RGB_COLOURSPACE_BEST_RGB", "RGB_COLOURSPACE_BETA_RGB", diff --git a/colour/models/rgb/datasets/arri.py b/colour/models/rgb/datasets/arri.py index 4e36c7b119..452307c5c1 100644 --- a/colour/models/rgb/datasets/arri.py +++ b/colour/models/rgb/datasets/arri.py @@ -5,11 +5,16 @@ Defines the *ARRI* colourspaces: - :attr:`colour.models.RGB_COLOURSPACE_ARRI_WIDE_GAMUT_3`. +- :attr:`colour.models.RGB_COLOURSPACE_ARRI_WIDE_GAMUT_4`. References ---------- - :cite:`ARRI2012a` : ARRI. (2012). ALEXA - Log C Curve - Usage in VFX. https://drive.google.com/open?id=1t73fAG_QpV7hJxoQPYZDWvOojYkYDgvn +- :cite:`Cooper2022` : Cooper, S., & Brendel, H. (2022). ARRI LogC4 + Logarithmic Color Space SPECIFICATION. Retrieved October 24, 2022, from + https://www.arri.com/resource/blob/278790/bea879ac0d041a925bed27a096ab3ec2/\ +2022-05-arri-logc4-specification-data.pdf """ from __future__ import annotations @@ -22,6 +27,8 @@ RGB_Colourspace, log_encoding_ARRILogC3, log_decoding_ARRILogC3, + log_encoding_ARRILogC4, + log_decoding_ARRILogC4, ) __author__ = "Colour Developers" @@ -38,6 +45,12 @@ "MATRIX_ARRI_WIDE_GAMUT_3_TO_XYZ", "MATRIX_XYZ_TO_ARRI_WIDE_GAMUT_3", "RGB_COLOURSPACE_ARRI_WIDE_GAMUT_3", + "PRIMARIES_ARRI_WIDE_GAMUT_4", + "WHITEPOINT_NAME_ARRI_WIDE_GAMUT_4", + "CCS_WHITEPOINT_ARRI_WIDE_GAMUT_4", + "MATRIX_ARRI_WIDE_GAMUT_4_TO_XYZ", + "MATRIX_XYZ_TO_ARRI_WIDE_GAMUT_4", + "RGB_COLOURSPACE_ARRI_WIDE_GAMUT_4", ] PRIMARIES_ARRI_WIDE_GAMUT_3: NDArray = np.array( @@ -92,3 +105,52 @@ ---------- :cite:`ARRI2012a` """ + +PRIMARIES_ARRI_WIDE_GAMUT_4: NDArray = np.array( + [ + [0.7347, 0.2653], + [0.1424, 0.8576], + [0.0991, -0.0308], + ] +) +"""*ARRI Wide Gamut 4* colourspace primaries.""" + +WHITEPOINT_NAME_ARRI_WIDE_GAMUT_4: str = "D65" +"""*ARRI Wide Gamut 4* colourspace whitepoint name.""" + +CCS_WHITEPOINT_ARRI_WIDE_GAMUT_4: NDArray = CCS_ILLUMINANTS[ + "CIE 1931 2 Degree Standard Observer" +][WHITEPOINT_NAME_ARRI_WIDE_GAMUT_4] +"""*ARRI Wide Gamut 4* colourspace whitepoint chromaticity coordinates.""" + +MATRIX_ARRI_WIDE_GAMUT_4_TO_XYZ: NDArray = np.array( + [ + [0.7048583204, 0.1297602952, 0.1158373115], + [0.2545241764, 0.7814777327, -0.0360019091], + [0.0000000000, 0.0000000000, 1.0890577508], + ] +) +"""*ARRI Wide Gamut 4* colourspace to *CIE XYZ* tristimulus values matrix.""" + +MATRIX_XYZ_TO_ARRI_WIDE_GAMUT_4: NDArray = np.linalg.inv( + MATRIX_ARRI_WIDE_GAMUT_4_TO_XYZ +) +"""*CIE XYZ* tristimulus values to *ARRI Wide Gamut 4* colourspace matrix.""" + +RGB_COLOURSPACE_ARRI_WIDE_GAMUT_4: RGB_Colourspace = RGB_Colourspace( + "ARRI Wide Gamut 4", + PRIMARIES_ARRI_WIDE_GAMUT_4, + CCS_WHITEPOINT_ARRI_WIDE_GAMUT_4, + WHITEPOINT_NAME_ARRI_WIDE_GAMUT_4, + MATRIX_ARRI_WIDE_GAMUT_4_TO_XYZ, + MATRIX_XYZ_TO_ARRI_WIDE_GAMUT_4, + log_encoding_ARRILogC4, + log_decoding_ARRILogC4, +) +RGB_COLOURSPACE_ARRI_WIDE_GAMUT_4.__doc__ = """ +*ARRI Wide Gamut 4* colourspace. + +References +---------- +:cite:`Cooper2022` +""" diff --git a/colour/models/rgb/transfer_functions/__init__.py b/colour/models/rgb/transfer_functions/__init__.py index 85eaf61e1c..77214268c8 100644 --- a/colour/models/rgb/transfer_functions/__init__.py +++ b/colour/models/rgb/transfer_functions/__init__.py @@ -27,7 +27,12 @@ log_decoding_ACEScct, ) from .arib_std_b67 import oetf_ARIBSTDB67, oetf_inverse_ARIBSTDB67 -from .arri import log_encoding_ARRILogC3, log_decoding_ARRILogC3 +from .arri import ( + log_encoding_ARRILogC3, + log_decoding_ARRILogC3, + log_encoding_ARRILogC4, + log_decoding_ARRILogC4, +) from .blackmagic_design import ( oetf_BlackmagicFilmGeneration5, oetf_inverse_BlackmagicFilmGeneration5, @@ -160,6 +165,8 @@ __all__ += [ "log_encoding_ARRILogC3", "log_decoding_ARRILogC3", + "log_encoding_ARRILogC4", + "log_decoding_ARRILogC4", ] __all__ += [ "oetf_BlackmagicFilmGeneration5", @@ -344,6 +351,7 @@ "ACEScct": log_encoding_ACEScct, "ACESproxy": log_encoding_ACESproxy, "ARRI LogC3": log_encoding_ARRILogC3, + "ARRI LogC4": log_encoding_ARRILogC4, "Canon Log 2": log_encoding_CanonLog2, "Canon Log 3": log_encoding_CanonLog3, "Canon Log": log_encoding_CanonLog, @@ -383,6 +391,7 @@ def log_encoding( "ACEScct", "ACESproxy", "ARRI LogC3", + "ARRI LogC4", "Canon Log 2", "Canon Log 3", "Canon Log", @@ -430,6 +439,7 @@ def log_encoding( :func:`colour.models.log_encoding_ACEScct`, :func:`colour.models.log_encoding_ACESproxy`, :func:`colour.models.log_encoding_ARRILogC3`, + :func:`colour.models.log_encoding_ARRILogC4`, :func:`colour.models.log_encoding_CanonLog2`, :func:`colour.models.log_encoding_CanonLog3`, :func:`colour.models.log_encoding_CanonLog`, @@ -491,6 +501,7 @@ def log_encoding( "ACEScct": log_decoding_ACEScct, "ACESproxy": log_decoding_ACESproxy, "ARRI LogC3": log_decoding_ARRILogC3, + "ARRI LogC4": log_decoding_ARRILogC4, "Canon Log 2": log_decoding_CanonLog2, "Canon Log 3": log_decoding_CanonLog3, "Canon Log": log_decoding_CanonLog, @@ -530,6 +541,7 @@ def log_decoding( "ACEScct", "ACESproxy", "ARRI LogC3", + "ARRI LogC4", "Canon Log 2", "Canon Log 3", "Canon Log", @@ -577,6 +589,7 @@ def log_decoding( :func:`colour.models.log_decoding_ACEScct`, :func:`colour.models.log_decoding_ACESproxy`, :func:`colour.models.log_decoding_ARRILogC3`, + :func:`colour.models.log_decoding_ARRILogC4`, :func:`colour.models.log_decoding_CanonLog2`, :func:`colour.models.log_decoding_CanonLog3`, :func:`colour.models.log_decoding_CanonLog`, @@ -1044,6 +1057,7 @@ def cctf_encoding( "ACEScct", "ACESproxy", "ARRI LogC3", + "ARRI LogC4", "ARIB STD-B67", "Blackmagic Film Generation 5", "Canon Log 2", @@ -1199,6 +1213,7 @@ def cctf_decoding( "ACEScct", "ACESproxy", "ARRI LogC3", + "ARRI LogC4", "ARIB STD-B67", "Blackmagic Film Generation 5", "Canon Log 2", diff --git a/colour/models/rgb/transfer_functions/arri.py b/colour/models/rgb/transfer_functions/arri.py index 7bd2c6c73a..e2c156b307 100644 --- a/colour/models/rgb/transfer_functions/arri.py +++ b/colour/models/rgb/transfer_functions/arri.py @@ -11,6 +11,10 @@ ---------- - :cite:`ARRI2012a` : ARRI. (2012). ALEXA - Log C Curve - Usage in VFX. https://drive.google.com/open?id=1t73fAG_QpV7hJxoQPYZDWvOojYkYDgvn +- :cite:`Cooper2022` : Cooper, S., & Brendel, H. (2022). ARRI LogC4 + Logarithmic Color Space SPECIFICATION. Retrieved October 24, 2022, from + https://www.arri.com/resource/blob/278790/bea879ac0d041a925bed27a096ab3ec2/\ +2022-05-arri-logc4-specification-data.pdf """ from __future__ import annotations @@ -20,6 +24,7 @@ from colour.hints import FloatingOrArrayLike, FloatingOrNDArray, Literal, Union from colour.utilities import ( CanonicalMapping, + Structure, as_float, from_range_1, to_domain_1, @@ -38,6 +43,9 @@ "DATA_ALEXA_LOG_C_CURVE_CONVERSION", "log_encoding_ARRILogC3", "log_decoding_ARRILogC3", + "CONSTANTS_ARRILOGC4", + "log_encoding_ARRILogC4", + "log_decoding_ARRILogC4", ] DATA_ALEXA_LOG_C_CURVE_BCL: CanonicalMapping = CanonicalMapping( @@ -679,3 +687,142 @@ def log_decoding_ARRILogC3( x = np.where(t > e * cut + f, (10 ** ((t - d) / c) - b) / a, (t - f) / e) return as_float(from_range_1(x)) + + +CONSTANTS_ARRILOGC4: Structure = Structure( + a=(2**18 - 16) / 117.45, + b=(1023 - 95) / 1023, + c=95 / 1023, +) +"""*ARRI LogC4* constants.""" + +_a = CONSTANTS_ARRILOGC4.a +_b = CONSTANTS_ARRILOGC4.b +_c = CONSTANTS_ARRILOGC4.c + +CONSTANTS_ARRILOGC4.s = (7 * np.log(2) * 2 ** (7 - 14 * _c / _b)) / (_a * _b) +CONSTANTS_ARRILOGC4.t = (2 ** (14 * (-_c / _b) + 6) - 64) / _a + +del _a, _b, _c + + +def log_encoding_ARRILogC4( + E_scene: FloatingOrArrayLike, + constants: Structure = CONSTANTS_ARRILOGC4, +) -> FloatingOrNDArray: + """ + Define the *ARRI LogC4* log encoding curve / opto-electronic transfer + function. + + Parameters + ---------- + E_scene + Relative scene linear signal :math:`E_{scene}`. + constants + *ARRI LogC4* constants. + + Returns + ------- + :class:`numpy.floating` or :class:`numpy.ndarray` + *ARRI LogC4* encoded signal :math:`E'`. + + References + ---------- + :cite:`Cooper2022` + + Notes + ----- + +-------------+-----------------------+---------------+ + | **Domain** | **Scale - Reference** | **Scale - 1** | + +=============+=======================+===============+ + | ``E_scene`` | [0, 1] | [0, 1] | + +-------------+-----------------------+---------------+ + + +------------+-----------------------+---------------+ + | **Range** | **Scale - Reference** | **Scale - 1** | + +============+=======================+===============+ + | ``E_p`` | [0, 1] | [0, 1] | + +------------+-----------------------+---------------+ + + Examples + -------- + >>> log_encoding_ARRILogC4(0.18) # doctest: +ELLIPSIS + 0.2783958... + """ + + E_scene = to_domain_1(E_scene) + + a = constants.a + b = constants.b + c = constants.c + s = constants.s + t = constants.t + + E_p = np.where( + E_scene >= t, + (np.log2(a * E_scene + 64) - 6) / 14 * b + c, + (E_scene - t) / s, + ) + + return as_float(from_range_1(E_p)) + + +def log_decoding_ARRILogC4( + E_p: FloatingOrArrayLike, + constants: Structure = CONSTANTS_ARRILOGC4, +) -> FloatingOrNDArray: + """ + Define the *ARRI LogC4* log decoding curve / electro-optical transfer + function. + + Parameters + ---------- + E_p + *ARRI LogC4* encoded signal :math:`E'`. + constants + *ARRI LogC4* constants. + + Returns + ------- + :class:`numpy.floating` or :class:`numpy.ndarray` + Linear data :math:`E_{scene}`. + + Notes + ----- + +------------+-----------------------+---------------+ + | **Domain** | **Scale - Reference** | **Scale - 1** | + +============+=======================+===============+ + | ``E_p`` | [0, 1] | [0, 1] | + +------------+-----------------------+---------------+ + + +-------------+-----------------------+---------------+ + | **Range** | **Scale - Reference** | **Scale - 1** | + +=============+=======================+===============+ + | ``E_scene`` | [0, 1] | [0, 1] | + +-------------+-----------------------+---------------+ + + References + ---------- + :cite:`Cooper2022` + + Examples + -------- + >>> log_decoding_ARRILogC4(0.27839583654826527) # doctest: +ELLIPSIS + 0.18... + """ + + E_p = to_domain_1(E_p) + + a = constants.a + b = constants.b + c = constants.c + s = constants.s + t = constants.t + + E_scene = np.where( + E_p >= 0, + (2 ** (14 * ((E_p - c) / b) + 6) - 64) / a, + E_p * s + t, + ) + + return as_float(from_range_1(E_scene)) diff --git a/colour/models/rgb/transfer_functions/tests/test_arri.py b/colour/models/rgb/transfer_functions/tests/test_arri.py index db73def727..b5c8452294 100644 --- a/colour/models/rgb/transfer_functions/tests/test_arri.py +++ b/colour/models/rgb/transfer_functions/tests/test_arri.py @@ -9,6 +9,8 @@ from colour.models.rgb.transfer_functions import ( log_encoding_ARRILogC3, log_decoding_ARRILogC3, + log_encoding_ARRILogC4, + log_decoding_ARRILogC4, ) from colour.utilities import domain_range_scale, ignore_numpy_errors @@ -22,6 +24,8 @@ __all__ = [ "TestLogEncoding_ARRILogC3", "TestLogDecoding_ARRILogC3", + "TestLogEncoding_ARRILogC4", + "TestLogDecoding_ARRILogC4", ] @@ -181,5 +185,163 @@ def test_nan_log_decoding_ARRILogC3(self): ) +class TestLogEncoding_ARRILogC4(unittest.TestCase): + """ + Define :func:`colour.models.rgb.transfer_functions.arri.\ +log_encoding_ARRILogC4` definition unit tests methods. + """ + + def test_log_encoding_ARRILogC4(self): + """ + Test :func:`colour.models.rgb.transfer_functions.arri.\ +log_encoding_ARRILogC4` definition. + """ + + self.assertAlmostEqual( + log_encoding_ARRILogC4(0.0), 0.092864125122190, places=7 + ) + + self.assertAlmostEqual( + log_encoding_ARRILogC4(0.18), 0.278395836548265, places=7 + ) + + self.assertAlmostEqual( + log_encoding_ARRILogC4(1.0), 0.427519364835306, places=7 + ) + + def test_n_dimensional_log_encoding_ARRILogC4(self): + """ + Test :func:`colour.models.rgb.transfer_functions.arri.\ +log_encoding_ARRILogC4` definition n-dimensional arrays support. + """ + + x = 0.18 + t = log_encoding_ARRILogC4(x) + + x = np.tile(x, 6) + t = np.tile(t, 6) + np.testing.assert_array_almost_equal( + log_encoding_ARRILogC4(x), t, decimal=7 + ) + + x = np.reshape(x, (2, 3)) + t = np.reshape(t, (2, 3)) + np.testing.assert_array_almost_equal( + log_encoding_ARRILogC4(x), t, decimal=7 + ) + + x = np.reshape(x, (2, 3, 1)) + t = np.reshape(t, (2, 3, 1)) + np.testing.assert_array_almost_equal( + log_encoding_ARRILogC4(x), t, decimal=7 + ) + + def test_domain_range_scale_log_encoding_ARRILogC4(self): + """ + Test :func:`colour.models.rgb.transfer_functions.arri.\ +log_encoding_ARRILogC4` definition domain and range scale support. + """ + + x = 0.18 + t = log_encoding_ARRILogC4(x) + + d_r = (("reference", 1), ("1", 1), ("100", 100)) + for scale, factor in d_r: + with domain_range_scale(scale): + np.testing.assert_array_almost_equal( + log_encoding_ARRILogC4(x * factor), t * factor, decimal=7 + ) + + @ignore_numpy_errors + def test_nan_log_encoding_ARRILogC4(self): + """ + Test :func:`colour.models.rgb.transfer_functions.arri.\ +log_encoding_ARRILogC4` definition nan support. + """ + + log_encoding_ARRILogC4( + np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]) + ) + + +class TestLogDecoding_ARRILogC4(unittest.TestCase): + """ + Define :func:`colour.models.rgb.transfer_functions.arri.\ +log_decoding_ARRILogC4` definition unit tests methods. + """ + + def test_log_decoding_ARRILogC4(self): + """ + Test :func:`colour.models.rgb.transfer_functions.arri.\ +log_decoding_ARRILogC4` definition. + """ + + self.assertAlmostEqual( + log_decoding_ARRILogC4(0.092864125122190), 0.0, places=7 + ) + + self.assertAlmostEqual( + log_decoding_ARRILogC4(0.278395836548265), 0.18, places=7 + ) + + self.assertAlmostEqual( + log_decoding_ARRILogC4(0.427519364835306), 1.0, places=7 + ) + + def test_n_dimensional_log_decoding_ARRILogC4(self): + """ + Test :func:`colour.models.rgb.transfer_functions.arri.\ +log_decoding_ARRILogC4` definition n-dimensional arrays support. + """ + + t = 0.278395836548265 + x = log_decoding_ARRILogC4(t) + + t = np.tile(t, 6) + x = np.tile(x, 6) + np.testing.assert_array_almost_equal( + log_decoding_ARRILogC4(t), x, decimal=7 + ) + + t = np.reshape(t, (2, 3)) + x = np.reshape(x, (2, 3)) + np.testing.assert_array_almost_equal( + log_decoding_ARRILogC4(t), x, decimal=7 + ) + + t = np.reshape(t, (2, 3, 1)) + x = np.reshape(x, (2, 3, 1)) + np.testing.assert_array_almost_equal( + log_decoding_ARRILogC4(t), x, decimal=7 + ) + + def test_domain_range_scale_log_decoding_ARRILogC4(self): + """ + Test :func:`colour.models.rgb.transfer_functions.arri.\ +log_decoding_ARRILogC4` definition domain and range scale support. + """ + + t = 0.278395836548265 + x = log_decoding_ARRILogC4(t) + + d_r = (("reference", 1), ("1", 1), ("100", 100)) + for scale, factor in d_r: + with domain_range_scale(scale): + np.testing.assert_array_almost_equal( + log_decoding_ARRILogC4(t * factor), x * factor, decimal=7 + ) + + @ignore_numpy_errors + def test_nan_log_decoding_ARRILogC4(self): + """ + Test :func:`colour.models.rgb.transfer_functions.arri.\ +log_decoding_ARRILogC4` definition nan support. + """ + + log_decoding_ARRILogC4( + np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]) + ) + + if __name__ == "__main__": unittest.main() diff --git a/docs/colour.models.rst b/docs/colour.models.rst index a4f0b0c5e4..738041bd9c 100644 --- a/docs/colour.models.rst +++ b/docs/colour.models.rst @@ -415,6 +415,7 @@ RGB Colourspaces RGB_COLOURSPACE_ADOBE_RGB1998 RGB_COLOURSPACE_ADOBE_WIDE_GAMUT_RGB RGB_COLOURSPACE_ARRI_WIDE_GAMUT_3 + RGB_COLOURSPACE_ARRI_WIDE_GAMUT_4 RGB_COLOURSPACE_APPLE_RGB RGB_COLOURSPACE_BEST_RGB RGB_COLOURSPACE_BETA_RGB diff --git a/docs/index.rst b/docs/index.rst index 24b7c84575..35435954ba 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -792,6 +792,7 @@ RGB Colourspaces 'ACEScg', 'ACESproxy', 'ARRI Wide Gamut 3', + 'ARRI Wide Gamut 4', 'Adobe RGB (1998)', 'Adobe Wide Gamut RGB', 'Apple RGB', @@ -909,6 +910,7 @@ Log Encoding / Decoding 'ACEScct', 'ACESproxy', 'ARRI LogC3', + 'ARRI LogC4', 'Canon Log', 'Canon Log 2', 'Canon Log 3', @@ -944,6 +946,7 @@ CCTFs Encoding / Decoding 'ACEScct', 'ACESproxy', 'ARRI LogC3', + 'ARRI LogC4', 'ARIB STD-B67', 'Canon Log', 'Canon Log 2',