def test_handle_arguments_deprecation(self): """ Tests :func:`colour.utilities.deprecation.handle_arguments_deprecation` definition. """ changes = { 'ArgumentRenamed': [[ 'argument_1_name', 'argument_1_new_name', ]], 'ArgumentFutureRename': [[ 'argument_2_name', 'argument_2_new_name', ]], 'ArgumentRemoved': ['argument_3_name'], 'ArgumentFutureRemove': ['argument_4_name'], } self.assertDictEqual( handle_arguments_deprecation(changes, argument_1_name=True, argument_2_name=True, argument_4_name=True), { 'argument_1_new_name': True, 'argument_2_new_name': True, 'argument_4_name': True }) self.assertRaises( ValueError, lambda: handle_arguments_deprecation(changes, argument_3_name=True ), )
def log_decoding_Log3G10(y, method='v2', **kwargs): """ Defines the *Log3G10* log decoding curve / electro-optical transfer function. Parameters ---------- y : numeric or array_like Non-linear data :math:`y`. method : unicode, optional **{'v1', 'v2'}**, Computation method. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray Linear data :math:`x`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``y`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`Nattress2016a` Examples -------- >>> log_decoding_Log3G10(1.0) # doctest: +ELLIPSIS 184.3223476... >>> log_decoding_Log3G10(1.0 / 3, method='v1') # doctest: +ELLIPSIS 0.1799994... """ method = handle_arguments_deprecation( { 'ArgumentRenamed': [['legacy_curve', 'method']], }, **kwargs).get('method', method) method = {True: 'v1', False: 'v2'}.get(method, method) return LOG3G10_DECODING_METHODS[method](y)
def apply(self, RGB, inverse=False, interpolator=LinearInterpolator, interpolator_kwargs=None, **kwargs): """ Applies the *LUT* to given *RGB* colourspace array using given method. Parameters ---------- RGB : array_like *RGB* colourspace array to apply the *LUT* onto. inverse : boolean, optional Checks if the LUT has to be applied in forward or backward direction. interpolator : object, optional Interpolator class type to use as interpolating function. interpolator_kwargs : dict_like, optional Arguments to use when instantiating the interpolating function. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- ndarray Interpolated *RGB* colourspace array. """ interpolator_kwargs = handle_arguments_deprecation({ 'ArgumentRenamed': [['interpolator_args', 'interpolator_kwargs']], }, **kwargs).get('interpolator_kwargs', interpolator_kwargs) if interpolator_kwargs is None: interpolator_kwargs = {} if inverse: SIZE = len(self._table) LUT_inverse = colour.LUT1D(size=SIZE) LUT_inverse.table = colour.Extrapolator( colour.LinearInterpolator(self._table, LUT_inverse.table))(LUT_inverse.table) RGB_i = LUT_inverse.apply(RGB) return RGB_i else: if self.is_domain_explicit(): samples = self.domain else: domain_min, domain_max = self.domain samples = np.linspace(domain_min, domain_max, self._table.size) RGB_interpolator = interpolator(samples, self._table, **interpolator_kwargs) return RGB_interpolator(RGB)
def test_handle_arguments_deprecation(self): """ Test :func:`colour.utilities.deprecation.handle_arguments_deprecation` definition. """ changes = { "ArgumentRenamed": [ [ "argument_1_name", "argument_1_new_name", ] ], "ArgumentFutureRename": [ [ "argument_2_name", "argument_2_new_name", ] ], "ArgumentRemoved": ["argument_3_name"], "ArgumentFutureRemove": ["argument_4_name"], } self.assertDictEqual( handle_arguments_deprecation( changes, argument_1_name=True, argument_2_name=True, argument_3_name=True, argument_4_name=True, argument_5_name=True, ), { "argument_1_new_name": True, "argument_2_new_name": True, "argument_4_name": True, "argument_5_name": True, }, )
def plot_sds_in_chromaticity_diagram_CIE1960UCS( sds, cmfs='CIE 1931 2 Degree Standard Observer', chromaticity_diagram_callable_CIE1960UCS=( plot_chromaticity_diagram_CIE1960UCS), annotate_kwargs=None, plot_kwargs=None, **kwargs): """ Plots given spectral distribution chromaticity coordinates into the *CIE 1960 UCS Chromaticity Diagram*. Parameters ---------- sds : array_like or MultiSpectralDistributions Spectral distributions or multi-spectral distributions to plot. `sds` can be a single :class:`colour.MultiSpectralDistributions` class instance, a list of :class:`colour.MultiSpectralDistributions` class instances or a list of :class:`colour.SpectralDistribution` class instances. cmfs : unicode or XYZ_ColourMatchingFunctions, optional Standard observer colour matching functions used for computing the spectral locus boundaries. ``cmfs`` can be of any type or form supported by the :func:`colour.plotting.filter_cmfs` definition. chromaticity_diagram_callable_CIE1960UCS : callable, optional Callable responsible for drawing the *CIE 1960 UCS Chromaticity Diagram*. annotate_kwargs : dict or array_like, optional Keyword arguments for the :func:`plt.annotate` definition, used to annotate the resulting chromaticity coordinates with their respective spectral distribution names. ``annotate_kwargs`` can be either a single dictionary applied to all the arrows with same settings or a sequence of dictionaries with different settings for each spectral distribution. The following special keyword arguments can also be used: - *annotate* : bool, whether to annotate the spectral distributions. plot_kwargs : dict or array_like, optional Keyword arguments for the :func:`plt.plot` definition, used to control the style of the plotted spectral distributions. ``plot_kwargs`` can be either a single dictionary applied to all the plotted spectral distributions with same settings or a sequence of dictionaries with different settings for each plotted spectral distributions. The following special keyword arguments can also be used: - *illuminant* : unicode or :class:`colour.SpectralDistribution`, the illuminant used to compute the spectral distributions colours. The default is the illuminant associated with the whitepoint of the default plotting colourspace. ``illuminant`` can be of any type or form supported by the :func:`colour.plotting.filter_cmfs` definition. - *cmfs* : unicode, the standard observer colour matching functions used for computing the spectral distributions colours. ``cmfs`` can be of any type or form supported by the :func:`colour.plotting.filter_cmfs` definition. - *normalise_sd_colours* : bool, whether to normalise the computed spectral distributions colours. The default is *True*. - *use_sd_colours* : bool, whether to use the computed spectral distributions colours under the plotting colourspace illuminant. Alternatively, it is possible to use the :func:`plt.plot` definition ``color`` argument with pre-computed values. The default is *True*. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.diagrams.plot_chromaticity_diagram`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Also handles keywords arguments for deprecation management. Returns ------- tuple Current figure and axes. Examples -------- >>> A = SDS_ILLUMINANTS['A'] >>> D65 = SDS_ILLUMINANTS['D65'] >>> plot_sds_in_chromaticity_diagram_CIE1960UCS([A, D65]) ... # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, <...AxesSubplot...>) .. image:: ../_static/Plotting_\ Plot_SDS_In_Chromaticity_Diagram_CIE1960UCS.png :align: center :alt: plot_sds_in_chromaticity_diagram_CIE1960UCS """ annotate_kwargs = handle_arguments_deprecation( { 'ArgumentRenamed': [['annotate_parameters', 'annotate_kwargs']], }, **kwargs).get('annotate_kwargs', annotate_kwargs) settings = dict(kwargs) settings.update({'method': 'CIE 1960 UCS'}) return plot_sds_in_chromaticity_diagram( sds, cmfs, chromaticity_diagram_callable_CIE1960UCS, annotate_kwargs=annotate_kwargs, plot_kwargs=plot_kwargs, **settings)
def log_decoding_CanonLog2(clog2, bit_depth=10, in_normalised_code_value=True, out_reflection=True, **kwargs): """ Defines the *Canon Log 2* log decoding curve / electro-optical transfer function. Parameters ---------- clog2 : numeric or array_like *Canon Log 2* non-linear data. bit_depth : int, optional Bit depth used for conversion. in_normalised_code_value : bool, optional Whether the *Canon Log 2* non-linear data is encoded with normalised code values. out_reflection : bool, optional Whether the light level :math:`x` to a camera is reflection. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray Linear data :math:`x`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``clog2`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`Canona` Examples -------- >>> log_decoding_CanonLog2(39.825469498316735 / 100) # doctest: +ELLIPSIS 0.1799999... """ in_normalised_code_value = handle_arguments_deprecation( { 'ArgumentRenamed': [['in_legal', 'in_normalised_code_value']], }, **kwargs).get('in_normalised_code_value', in_normalised_code_value) clog2 = to_domain_1(clog2) clog2 = (legal_to_full(clog2, bit_depth) if in_normalised_code_value else clog2) x = np.where( clog2 < 0.035388128, -(10**((0.035388128 - clog2) / 0.281863093) - 1) / 87.09937546, (10**((clog2 - 0.035388128) / 0.281863093) - 1) / 87.09937546, ) if out_reflection: x = x * 0.9 return as_float(from_range_1(x))
def plot_sds_in_chromaticity_diagram( sds, cmfs='CIE 1931 2 Degree Standard Observer', chromaticity_diagram_callable=plot_chromaticity_diagram, method='CIE 1931', annotate_kwargs=None, plot_kwargs=None, **kwargs): """ Plots given spectral distribution chromaticity coordinates into the *Chromaticity Diagram* using given method. Parameters ---------- sds : array_like or MultiSpectralDistributions Spectral distributions or multi-spectral distributions to plot. `sds` can be a single :class:`colour.MultiSpectralDistributions` class instance, a list of :class:`colour.MultiSpectralDistributions` class instances or a list of :class:`colour.SpectralDistribution` class instances. cmfs : unicode or XYZ_ColourMatchingFunctions, optional Standard observer colour matching functions used for computing the spectral locus boundaries. ``cmfs`` can be of any type or form supported by the :func:`colour.plotting.filter_cmfs` definition. chromaticity_diagram_callable : callable, optional Callable responsible for drawing the *Chromaticity Diagram*. method : unicode, optional **{'CIE 1931', 'CIE 1960 UCS', 'CIE 1976 UCS'}**, *Chromaticity Diagram* method. annotate_kwargs : dict or array_like, optional Keyword arguments for the :func:`plt.annotate` definition, used to annotate the resulting chromaticity coordinates with their respective spectral distribution names. ``annotate_kwargs`` can be either a single dictionary applied to all the arrows with same settings or a sequence of dictionaries with different settings for each spectral distribution. The following special keyword arguments can also be used: - *annotate* : bool, whether to annotate the spectral distributions. plot_kwargs : dict or array_like, optional Keyword arguments for the :func:`plt.plot` definition, used to control the style of the plotted spectral distributions. ``plot_kwargs`` can be either a single dictionary applied to all the plotted spectral distributions with same settings or a sequence of dictionaries with different settings for each plotted spectral distributions. The following special keyword arguments can also be used: - *illuminant* : unicode or :class:`colour.SpectralDistribution`, the illuminant used to compute the spectral distributions colours. The default is the illuminant associated with the whitepoint of the default plotting colourspace. ``illuminant`` can be of any type or form supported by the :func:`colour.plotting.filter_cmfs` definition. - *cmfs* : unicode, the standard observer colour matching functions used for computing the spectral distributions colours. ``cmfs`` can be of any type or form supported by the :func:`colour.plotting.filter_cmfs` definition. - *normalise_sd_colours* : bool, whether to normalise the computed spectral distributions colours. The default is *True*. - *use_sd_colours* : bool, whether to use the computed spectral distributions colours under the plotting colourspace illuminant. Alternatively, it is possible to use the :func:`plt.plot` definition ``color`` argument with pre-computed values. The default is *True*. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.diagrams.plot_chromaticity_diagram`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Also handles keywords arguments for deprecation management. Returns ------- tuple Current figure and axes. Examples -------- >>> A = SDS_ILLUMINANTS['A'] >>> D65 = SDS_ILLUMINANTS['D65'] >>> annotate_kwargs = [ ... {'xytext': (-25, 15), 'arrowprops':{'arrowstyle':'-'}}, ... {} ... ] >>> plot_kwargs = [ ... { ... 'illuminant': SDS_ILLUMINANTS['E'], ... 'markersize' : 15, ... 'normalise_sd_colours': True, ... 'use_sd_colours': True ... }, ... {'illuminant': SDS_ILLUMINANTS['E']}, ... ] >>> plot_sds_in_chromaticity_diagram( ... [A, D65], annotate_kwargs=annotate_kwargs, plot_kwargs=plot_kwargs) ... # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, <...AxesSubplot...>) .. image:: ../_static/Plotting_Plot_SDS_In_Chromaticity_Diagram.png :align: center :alt: plot_sds_in_chromaticity_diagram """ annotate_kwargs = handle_arguments_deprecation( { 'ArgumentRenamed': [['annotate_parameters', 'annotate_kwargs']], }, **kwargs).get('annotate_kwargs', annotate_kwargs) sds = sds_and_msds_to_sds(sds) settings = {'uniform': True} settings.update(kwargs) _figure, axes = artist(**settings) method = method.upper() settings.update({ 'axes': axes, 'standalone': False, 'method': method, 'cmfs': cmfs, }) chromaticity_diagram_callable(**settings) if method == 'CIE 1931': def XYZ_to_ij(XYZ): """ Converts given *CIE XYZ* tristimulus values to *ij* chromaticity coordinates. """ return XYZ_to_xy(XYZ) bounding_box = (-0.1, 0.9, -0.1, 0.9) elif method == 'CIE 1960 UCS': def XYZ_to_ij(XYZ): """ Converts given *CIE XYZ* tristimulus values to *ij* chromaticity coordinates. """ return UCS_to_uv(XYZ_to_UCS(XYZ)) bounding_box = (-0.1, 0.7, -0.2, 0.6) elif method == 'CIE 1976 UCS': def XYZ_to_ij(XYZ): """ Converts given *CIE XYZ* tristimulus values to *ij* chromaticity coordinates. """ return Luv_to_uv(XYZ_to_Luv(XYZ)) bounding_box = (-0.1, 0.7, -0.1, 0.7) else: raise ValueError( 'Invalid method: "{0}", must be one of ' '[\'CIE 1931\', \'CIE 1960 UCS\', \'CIE 1976 UCS\']'.format( method)) annotate_settings_collection = [{ 'annotate': True, 'xytext': (-50, 30), 'textcoords': 'offset points', 'arrowprops': CONSTANTS_ARROW_STYLE, } for _ in range(len(sds))] if annotate_kwargs is not None: update_settings_collection(annotate_settings_collection, annotate_kwargs, len(sds)) plot_settings_collection = [{ 'color': CONSTANTS_COLOUR_STYLE.colour.brightest, 'label': '{0}'.format(sd.strict_name), 'marker': 'o', 'markeredgecolor': CONSTANTS_COLOUR_STYLE.colour.dark, 'markeredgewidth': CONSTANTS_COLOUR_STYLE.geometry.short * 0.75, 'markersize': (CONSTANTS_COLOUR_STYLE.geometry.short * 6 + CONSTANTS_COLOUR_STYLE.geometry.short * 0.75), 'cmfs': cmfs, 'illuminant': SDS_ILLUMINANTS[ CONSTANTS_COLOUR_STYLE.colour.colourspace.whitepoint_name], 'use_sd_colours': False, 'normalise_sd_colours': False, } for sd in sds] if plot_kwargs is not None: update_settings_collection(plot_settings_collection, plot_kwargs, len(sds)) for i, sd in enumerate(sds): plot_settings = plot_settings_collection[i] cmfs = first_item(filter_cmfs(plot_settings.pop('cmfs')).values()) illuminant = first_item( filter_illuminants(plot_settings.pop('illuminant')).values()) normalise_sd_colours = plot_settings.pop('normalise_sd_colours') use_sd_colours = plot_settings.pop('use_sd_colours') with domain_range_scale('1'): XYZ = sd_to_XYZ(sd, cmfs, illuminant) if use_sd_colours: if normalise_sd_colours: XYZ /= XYZ[..., 1] plot_settings['color'] = np.clip(XYZ_to_plotting_colourspace(XYZ), 0, 1) ij = XYZ_to_ij(XYZ) axes.plot(ij[0], ij[1], **plot_settings) if (sd.name is not None and annotate_settings_collection[i]['annotate']): annotate_settings = annotate_settings_collection[i] annotate_settings.pop('annotate') axes.annotate(sd.name, xy=ij, **annotate_settings) settings.update({'standalone': True, 'bounding_box': bounding_box}) settings.update(kwargs) return render(**settings)
def log_decoding_SLog3(y, bit_depth=10, in_normalised_code_value=True, out_reflection=True, **kwargs): """ Defines the *Sony S-Log3* log decoding curve / electro-optical transfer function. Parameters ---------- y : numeric or array_like Non-linear *Sony S-Log3* data :math:`y`. bit_depth : int, optional Bit depth used for conversion. in_normalised_code_value : bool, optional Whether the non-linear *Sony S-Log3* data :math:`y` is encoded as normalised code values. out_reflection : bool, optional Whether the light level :math:`x` to a camera is reflection. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray Reflection or :math:`IRE / 100` input light level :math:`x` to a camera. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``y`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`SonyCorporationd` Examples -------- >>> log_decoding_SLog3(0.410557184750733) # doctest: +ELLIPSIS 0.1... """ in_normalised_code_value = handle_arguments_deprecation( { 'ArgumentRenamed': [['in_legal', 'in_normalised_code_value']], }, **kwargs).get('in_normalised_code_value', in_normalised_code_value) y = to_domain_1(y) y = y if in_normalised_code_value 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_float(from_range_1(x))
def CCT_to_xy_Hernandez1999(CCT, optimisation_kwargs=None, **kwargs): """ Returns the *CIE xy* chromaticity coordinates from given correlated colour temperature :math:`T_{cp}` using *Hernandez-Andres et al. (1999)* method. Parameters ---------- CCT : numeric or array_like Correlated colour temperature :math:`T_{cp}`. optimisation_kwargs : dict_like, optional Parameters for :func:`scipy.optimize.minimize` definition. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- ndarray *CIE xy* chromaticity coordinates. Warnings -------- *Hernandez-Andres et al. (1999)* method for computing *CIE xy* chromaticity coordinates from given correlated colour temperature is not a bijective function and might produce unexpected results. It is given for consistency with other correlated colour temperature computation methods but should be avoided for practical applications. The current implementation relies on optimization using :func:`scipy.optimize.minimize` definition and thus has reduced precision and poor performance. References ---------- :cite:`Hernandez-Andres1999a` Examples -------- >>> CCT_to_xy_Hernandez1999(6500.7420431786531) # doctest: +ELLIPSIS array([ 0.3127..., 0.329...]) """ optimisation_kwargs = handle_arguments_deprecation( { 'ArgumentRenamed': [['optimisation_parameters', 'optimisation_kwargs']], }, **kwargs).get('optimisation_kwargs', optimisation_kwargs) usage_warning('"Hernandez-Andres et al. (1999)" method for computing ' '"CIE xy" chromaticity coordinates from given correlated ' 'colour temperature is not a bijective function and and' 'might produce unexpected results. It is given for ' 'consistency with other correlated colour temperature ' 'computation methods but should be avoided for practical ' 'applications.') CCT = as_float_array(CCT) shape = list(CCT.shape) CCT = np.atleast_1d(CCT.reshape([-1, 1])) def objective_function(xy, CCT): """ Objective function. """ objective = np.linalg.norm(xy_to_CCT_Hernandez1999(xy) - CCT) return objective optimisation_settings = { 'method': 'Nelder-Mead', 'options': { 'fatol': 1e-10, }, } if optimisation_kwargs is not None: optimisation_settings.update(optimisation_kwargs) CCT = as_float_array([ minimize( objective_function, x0=CCS_ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65'], args=(CCT_i, ), **optimisation_settings).x for CCT_i in CCT ]) return as_numeric(CCT.reshape(shape + [2]))
def log_decoding_SLog(y, bit_depth=10, in_normalised_code_value=True, out_reflection=True, **kwargs): """ Defines the *Sony S-Log* log decoding curve / electro-optical transfer function. Parameters ---------- y : numeric or array_like Non-linear *Sony S-Log* data :math:`y`. bit_depth : int, optional Bit depth used for conversion. in_normalised_code_value : bool, optional Whether the non-linear *Sony S-Log* data :math:`y` is encoded as normalised code values. out_reflection : bool, optional Whether the light level :math:`x` to a camera is reflection. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray Reflection or :math:`IRE / 100` input light level :math:`x` to a camera. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``y`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`SonyCorporation2012a` Examples -------- >>> log_decoding_SLog(0.384970815928670) # doctest: +ELLIPSIS 0.1... """ in_normalised_code_value = handle_arguments_deprecation( { 'ArgumentRenamed': [['in_legal', 'in_normalised_code_value']], }, **kwargs).get('in_normalised_code_value', in_normalised_code_value) y = to_domain_1(y) x = legal_to_full(y, bit_depth) if in_normalised_code_value else y with domain_range_scale('ignore'): x = np.where( y >= log_encoding_SLog(0.0, bit_depth, in_normalised_code_value), 10**((x - 0.616596 - 0.03) / 0.432699) - 0.037584, (x - 0.030001222851889303) / 5.0, ) if out_reflection: x = x * 0.9 return as_float(from_range_1(x))
def log_decoding_SLog2(y, bit_depth=10, in_normalised_code_value=True, out_reflection=True, **kwargs): """ Defines the *Sony S-Log2* log decoding curve / electro-optical transfer function. Parameters ---------- y : numeric or array_like Non-linear *Sony S-Log2* data :math:`y`. bit_depth : int, optional Bit depth used for conversion. in_normalised_code_value : bool, optional Whether the non-linear *Sony S-Log2* data :math:`y` is encoded as normalised code values. out_reflection : bool, optional Whether the light level :math:`x` to a camera is reflection. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray Reflection or :math:`IRE / 100` input light level :math:`x` to a camera. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``y`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`SonyCorporation2012a` Examples -------- >>> log_decoding_SLog2(0.339532524633774) # doctest: +ELLIPSIS 0.1... """ in_normalised_code_value = handle_arguments_deprecation( { 'ArgumentRenamed': [['in_legal', 'in_normalised_code_value']], }, **kwargs).get('in_normalised_code_value', in_normalised_code_value) return 219 * log_decoding_SLog(y, bit_depth, in_normalised_code_value, out_reflection) / 155
def log_decoding_CanonLog(clog, bit_depth=10, in_normalised_code_value=True, out_reflection=True, **kwargs): """ Defines the *Canon Log* log decoding curve / electro-optical transfer function. Parameters ---------- clog : numeric or array_like *Canon Log* non-linear data. bit_depth : int, optional Bit depth used for conversion. in_normalised_code_value : bool, optional Whether the *Canon Log* non-linear data is encoded with normalised code values. out_reflection : bool, optional Whether the light level :math:`x` to a camera is reflection. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray Linear data :math:`x`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``clog`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`Thorpe2012a` Examples -------- >>> log_decoding_CanonLog(34.338965172606912 / 100) # doctest: +ELLIPSIS 0.17999999... """ in_normalised_code_value = handle_arguments_deprecation( { 'ArgumentRenamed': [['in_legal', 'in_normalised_code_value']], }, **kwargs).get('in_normalised_code_value', in_normalised_code_value) clog = to_domain_1(clog) clog = (legal_to_full(clog, bit_depth) if in_normalised_code_value else clog) x = np.where( clog < 0.0730597, -(10**((0.0730597 - clog) / 0.529136) - 1) / 10.1596, (10**((clog - 0.0730597) / 0.529136) - 1) / 10.1596, ) if out_reflection: x = x * 0.9 return as_float(from_range_1(x))
def log_decoding_VLog(V_out, bit_depth=10, in_normalised_code_value=True, out_reflection=True, constants=VLOG_CONSTANTS, **kwargs): """ Defines the *Panasonic V-Log* log decoding curve / electro-optical transfer function. Parameters ---------- V_out : numeric or array_like Non-linear data :math:`V_{out}`. bit_depth : int, optional Bit depth used for conversion. in_normalised_code_value : bool, optional Whether the non-linear *Panasonic V-Log* data :math:`V_{out}` is encoded as normalised code values. out_reflection : bool, optional Whether the light level :math`L_{in}` to a camera is reflection. constants : Structure, optional *Panasonic V-Log* constants. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray Linear reflection data :math`L_{in}`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``V_out`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``L_in`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`Panasonic2014a` Examples -------- >>> log_decoding_VLog(0.423311448760136) # doctest: +ELLIPSIS 0.1799999... """ in_normalised_code_value = handle_arguments_deprecation({ 'ArgumentRenamed': [['in_legal', 'in_normalised_code_value']], }, **kwargs).get('in_normalised_code_value', in_normalised_code_value) V_out = to_domain_1(V_out) V_out = (V_out if in_normalised_code_value else full_to_legal(V_out, bit_depth)) cut2 = constants.cut2 b = constants.b c = constants.c d = constants.d L_in = np.where( V_out < cut2, (V_out - 0.125) / 5.6, 10 ** ((V_out - d) / c) - b, ) if not out_reflection: L_in = L_in / 0.9 return as_float(from_range_1(L_in))
def log_decoding(value, function='Cineon', **kwargs): """ Decodes :math:`R'G'B'` video component signal value to linear-light values using given *log* function. Parameters ---------- value : numeric or array_like Value. function : unicode, optional **{'ACEScc', 'ACEScct', 'ACESproxy', 'ALEXA Log C', 'Canon Log 2', 'Canon Log 3', 'Canon Log', 'Cineon', 'D-Log', 'ERIMM RGB', 'F-Log', 'Filmic Pro 6', 'Log2', 'Log3G10', 'Log3G12', 'Panalog', 'PLog', 'Protune', 'REDLog', 'REDLogFilm', 'S-Log', 'S-Log2', 'S-Log3', 'T-Log', 'V-Log', 'ViperLog'}**, Computation function. Other Parameters ---------------- EI : int, optional {:func:`colour.models.log_decoding_ALEXALogC`}, Ei. E_clip : numeric, optional {:func:`colour.models.log_decoding_ERIMMRGB`}, Maximum exposure limit. E_min : numeric, optional {:func:`colour.models.log_decoding_ERIMMRGB`}, Minimum exposure limit. I_max : numeric, optional {:func:`colour.models.log_decoding_ERIMMRGB`}, Maximum code value: 255, 4095 and 650535 for respectively 8-bit, 12-bit and 16-bit per channel. bit_depth : int, optional {:func:`colour.models.log_decoding_ACESproxy`, :func:`colour.models.log_decoding_SLog`, :func:`colour.models.log_decoding_SLog2`}, **{8, 10, 12}**, Bit depth used for conversion, *ACESproxy* uses **{10, 12}**. black_offset : numeric or array_like {:func:`colour.models.log_decoding_Cineon`, :func:`colour.models.log_decoding_Panalog`, :func:`colour.models.log_decoding_REDLog`, :func:`colour.models.log_decoding_REDLogFilm`}, Black offset. density_per_code_value : numeric or array_like {:func:`colour.models.log_decoding_PivotedLog`}, Density per code value. firmware : unicode, optional {:func:`colour.models.log_decoding_ALEXALogC`}, **{'SUP 3.x', 'SUP 2.x'}**, Alexa firmware version. in_normalised_code_value : bool, optional {:func:`colour.models.log_decoding_SLog`, :func:`colour.models.log_decoding_SLog2`, :func:`colour.models.log_decoding_SLog3`}, Whether the non-linear *Sony S-Log*, *Sony S-Log2* or *Sony S-Log3* data :math:`y` is encoded as normalised code values. linear_reference : numeric or array_like {:func:`colour.models.log_decoding_PivotedLog`}, Linear reference. log_reference : numeric or array_like {:func:`colour.models.log_decoding_PivotedLog`}, Log reference. method : unicode, optional {:func:`colour.models.log_decoding_Log3G10`}, Whether to use the *Log3G10* *v1* or *v2* log encoding curve. negative_gamma : numeric or array_like {:func:`colour.models.log_decoding_PivotedLog`}, Negative gamma. out_reflection : bool, optional {:func:`colour.models.log_decoding_SLog`, :func:`colour.models.log_decoding_SLog2`}, Whether the light level :math:`x` to a camera is reflection. method : unicode, optional {:func:`colour.models.log_decoding_ALEXALogC`}, **{'Linear Scene Exposure Factor', 'Normalised Sensor Signal'}**, Conversion method. Returns ------- numeric or ndarray *Log* value. Examples -------- >>> log_decoding(0.457319613085418) # doctest: +ELLIPSIS 0.1... >>> log_decoding(0.413588402492442, function='ACEScc') ... # doctest: +ELLIPSIS 0.1... >>> log_decoding(0.391006842619746, function='PLog', log_reference=400) ... # doctest: +ELLIPSIS 0.1... >>> log_decoding(0.376512722254600, function='S-Log') ... # doctest: +ELLIPSIS 0.1... """ function = handle_arguments_deprecation( { 'ArgumentRenamed': [['curve', 'function']], }, **kwargs).get('function', function) function = LOG_DECODINGS[function] return function(value, **filter_kwargs(function, **kwargs))
def log_encoding_Log3G10(x, method='v2', **kwargs): """ Defines the *Log3G10* log encoding curve / opto-electronic transfer function. Parameters ---------- x : numeric or array_like Linear data :math:`x`. method : unicode, optional **{'v1', 'v2'}**, Computation method. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray Non-linear data :math:`y`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``y`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ - The *Log3G10* *v1* log encoding curve is the one used in *REDCINE-X Beta 42*. *Resolve 12.5.2* also uses the *v1* curve. *RED* is planning to use the *Log3G10* *v2* log encoding curve in the release version of the *RED SDK*. - The intent of the *Log3G10* *v1* log encoding curve is that zero maps to zero, 0.18 maps to 1/3, and 10 stops above 0.18 maps to 1.0. The name indicates this in a similar way to the naming conventions of *Sony HyperGamma* curves. The constants used in the functions do not in fact quite hit these values, but rather than use corrected constants, the functions here use the official *RED* values, in order to match the output of the *RED SDK*. For those interested, solving for constants which exactly hit 1/3 and 1.0 yields the following values:: B = 25 * (np.sqrt(4093.0) - 3) / 9 A = 1 / np.log10(B * 184.32 + 1) where the function takes the form:: Log3G10(x) = A * np.log10(B * x + 1) Similarly for *Log3G12*, the values which hit exactly 1/3 and 1.0 are:: B = 25 * (np.sqrt(16381.0) - 3) / 9 A = 1 / np.log10(B * 737.28 + 1) References ---------- :cite:`Nattress2016a` Examples -------- >>> log_encoding_Log3G10(0.0) # doctest: +ELLIPSIS 0.0915514... >>> log_encoding_Log3G10(0.18, method='v1') # doctest: +ELLIPSIS 0.3333336... """ method = handle_arguments_deprecation( { 'ArgumentRenamed': [['legacy_curve', 'method']], }, **kwargs).get('method', method) method = {True: 'v1', False: 'v2'}.get(method, method) return LOG3G10_ENCODING_METHODS[method](x)
def log_encoding_CanonLog(x, bit_depth=10, out_normalised_code_value=True, in_reflection=True, **kwargs): """ Defines the *Canon Log* log encoding curve / opto-electronic transfer function. Parameters ---------- x : numeric or array_like Linear data :math:`x`. bit_depth : int, optional Bit depth used for conversion. out_normalised_code_value : bool, optional Whether the *Canon Log* non-linear data is encoded as normalised code values. in_reflection : bool, optional Whether the light level :math:`x` to a camera is reflection. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray *Canon Log* non-linear data. References ---------- :cite:`Thorpe2012a` Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``clog`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ Examples -------- >>> log_encoding_CanonLog(0.18) * 100 # doctest: +ELLIPSIS 34.3389651... The values of *Table 2 Canon-Log Code Values* table in :cite:`Thorpe2012a` are obtained as follows: >>> x = np.array([0, 2, 18, 90, 720]) / 100 >>> np.around(log_encoding_CanonLog(x) * (2 ** 10 - 1)).astype(np.int) array([ 128, 169, 351, 614, 1016]) >>> np.around(log_encoding_CanonLog(x, 10, False) * 100, 1) array([ 7.3, 12. , 32.8, 62.7, 108.7]) """ out_normalised_code_value = handle_arguments_deprecation( { 'ArgumentRenamed': [['out_legal', 'out_normalised_code_value']], }, **kwargs).get('out_normalised_code_value', out_normalised_code_value) x = to_domain_1(x) if in_reflection: x = x / 0.9 with domain_range_scale('ignore'): clog = np.where( x < log_decoding_CanonLog(0.0730597, bit_depth, False), -(0.529136 * (np.log10(-x * 10.1596 + 1)) - 0.0730597), 0.529136 * np.log10(10.1596 * x + 1) + 0.0730597, ) clog = (full_to_legal(clog, bit_depth) if out_normalised_code_value else clog) return as_float(from_range_1(clog))
def log_decoding_CanonLog3(clog3, bit_depth=10, in_normalised_code_value=True, out_reflection=True, **kwargs): """ Defines the *Canon Log 3* log decoding curve / electro-optical transfer function. Parameters ---------- clog3 : numeric or array_like *Canon Log 3* non-linear data. bit_depth : int, optional Bit depth used for conversion. in_normalised_code_value : bool, optional Whether the *Canon Log 3* non-linear data is encoded with normalised code values. out_reflection : bool, optional Whether the light level :math:`x` to a camera is reflection. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray Linear data :math:`x`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``clog3`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`Canona` Examples -------- >>> log_decoding_CanonLog3(34.338936938868677 / 100) # doctest: +ELLIPSIS 0.1800000... """ in_normalised_code_value = handle_arguments_deprecation( { 'ArgumentRenamed': [['in_legal', 'in_normalised_code_value']], }, **kwargs).get('in_normalised_code_value', in_normalised_code_value) clog3 = to_domain_1(clog3) clog3 = (legal_to_full(clog3, bit_depth) if in_normalised_code_value else clog3) x = np.select( (clog3 < 0.04076162, clog3 <= 0.105357102, clog3 > 0.105357102), (-(10**((0.07623209 - clog3) / 0.42889912) - 1) / 14.98325, (clog3 - 0.073059361) / 2.3069815, (10**((clog3 - 0.069886632) / 0.42889912) - 1) / 14.98325)) if out_reflection: x = x * 0.9 return as_float(from_range_1(x))
def log_encoding_CanonLog3(x, bit_depth=10, out_normalised_code_value=True, in_reflection=True, **kwargs): """ Defines the *Canon Log 3* log encoding curve / opto-electronic transfer function. Parameters ---------- x : numeric or array_like Linear data :math:`x`. bit_depth : int, optional Bit depth used for conversion. out_normalised_code_value : bool, optional Whether the *Canon Log 3* non-linear data is encoded as normalised code values. in_reflection : bool, optional Whether the light level :math:`x` to a camera is reflection. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray *Canon Log 3* non-linear data. Notes ----- - Introspection of the grafting points by Shaw, N. (2018) shows that the *Canon Log 3* IDT was likely derived from its encoding curve as the later is grafted at *+/-0.014*:: >>> clog3 = 0.04076162 >>> (clog3 - 0.073059361) / 2.3069815 -0.014000000000000002 >>> clog3 = 0.105357102 >>> (clog3 - 0.073059361) / 2.3069815 0.013999999999999997 Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``clog3`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`Canona` Examples -------- >>> log_encoding_CanonLog3(0.18) * 100 # doctest: +ELLIPSIS 34.3389369... """ out_normalised_code_value = handle_arguments_deprecation( { 'ArgumentRenamed': [['out_legal', 'out_normalised_code_value']], }, **kwargs).get('out_normalised_code_value', out_normalised_code_value) x = to_domain_1(x) if in_reflection: x = x / 0.9 with domain_range_scale('ignore'): clog3 = np.select( (x < log_decoding_CanonLog3(0.04076162, bit_depth, False, False), x <= log_decoding_CanonLog3(0.105357102, bit_depth, False, False), x > log_decoding_CanonLog3(0.105357102, bit_depth, False, False)), (-0.42889912 * np.log10(-x * 14.98325 + 1) + 0.07623209, 2.3069815 * x + 0.073059361, 0.42889912 * np.log10(x * 14.98325 + 1) + 0.069886632)) clog3 = (full_to_legal(clog3, bit_depth) if out_normalised_code_value else clog3) return as_float(from_range_1(clog3))
def xy_to_CCT_Kang2002(xy, optimisation_kwargs=None, **kwargs): """ Returns the correlated colour temperature :math:`T_{cp}` from given *CIE xy* chromaticity coordinates using *Kang et al. (2002)* method. Parameters ---------- xy : array_like *CIE xy* chromaticity coordinates. optimisation_kwargs : dict_like, optional Parameters for :func:`scipy.optimize.minimize` definition. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- ndarray Correlated colour temperature :math:`T_{cp}`. Warnings -------- *Kang et al. (2002)* does not give an analytical inverse transformation to compute the correlated colour temperature :math:`T_{cp}` from given *CIE xy* chromaticity coordinates, the current implementation relies on optimization using :func:`scipy.optimize.minimize` definition and thus has reduced precision and poor performance. References ---------- :cite:`Kang2002a` Examples -------- >>> xy_to_CCT_Kang2002(np.array([0.31342600, 0.32359597])) ... # doctest: +ELLIPSIS 6504.3893128... """ optimisation_kwargs = handle_arguments_deprecation( { 'ArgumentRenamed': [['optimisation_parameters', 'optimisation_kwargs']], }, **kwargs).get('optimisation_kwargs', optimisation_kwargs) xy = as_float_array(xy) shape = xy.shape xy = np.atleast_1d(xy.reshape([-1, 2])) def objective_function(CCT, xy): """ Objective function. """ objective = np.linalg.norm(CCT_to_xy_Kang2002(CCT) - xy) return objective optimisation_settings = { 'method': 'Nelder-Mead', 'options': { 'fatol': 1e-10, }, } if optimisation_kwargs is not None: optimisation_settings.update(optimisation_kwargs) CCT = as_float_array([ minimize(objective_function, x0=6500, args=(xy_i, ), **optimisation_settings).x for xy_i in xy ]) return as_numeric(CCT.reshape(shape[:-1]))
def log_encoding_VLog(L_in, bit_depth=10, out_normalised_code_value=True, in_reflection=True, constants=VLOG_CONSTANTS, **kwargs): """ Defines the *Panasonic V-Log* log encoding curve / opto-electronic transfer function. Parameters ---------- L_in : numeric or array_like Linear reflection data :math`L_{in}`. bit_depth : int, optional Bit depth used for conversion. out_normalised_code_value : bool, optional Whether the non-linear *Panasonic V-Log* data :math:`V_{out}` is encoded as normalised code values. in_reflection : bool, optional Whether the light level :math`L_{in}` to a camera is reflection. constants : Structure, optional *Panasonic V-Log* constants. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray Non-linear data :math:`V_{out}`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``L_in`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``V_out`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`Panasonic2014a` Examples -------- >>> log_encoding_VLog(0.18) # doctest: +ELLIPSIS 0.4233114... The values of *Fig.2.2 V-Log Code Value* table in :cite:`Panasonic2014a` are obtained as follows: >>> L_in = np.array([0, 18, 90]) / 100 >>> np.around(log_encoding_VLog(L_in, 10, False) * 100).astype(np.int) array([ 7, 42, 61]) >>> np.around(log_encoding_VLog(L_in) * (2 ** 10 - 1)).astype(np.int) array([128, 433, 602]) >>> np.around(log_encoding_VLog(L_in) * (2 ** 12 - 1)).astype(np.int) array([ 512, 1733, 2409]) Note that some values in the last column values of *Fig.2.2 V-Log Code Value* table in :cite:`Panasonic2014a` are different by a code: [512, 1732, 2408]. """ out_normalised_code_value = handle_arguments_deprecation({ 'ArgumentRenamed': [['out_legal', 'out_normalised_code_value']], }, **kwargs).get('out_normalised_code_value', out_normalised_code_value) L_in = to_domain_1(L_in) if not in_reflection: L_in = L_in * 0.9 cut1 = constants.cut1 b = constants.b c = constants.c d = constants.d V_out = np.where( L_in < cut1, 5.6 * L_in + 0.125, c * np.log10(L_in + b) + d, ) V_out = (V_out if out_normalised_code_value else legal_to_full(V_out, bit_depth)) return as_float(from_range_1(V_out))
def OSA_UCS_to_XYZ(Ljg, optimisation_kwargs=None, **kwargs): """ Converts from *OSA UCS* colourspace to *CIE XYZ* tristimulus values under the *CIE 1964 10 Degree Standard Observer*. Parameters ---------- Ljg : array_like *OSA UCS* :math:`Ljg` lightness, jaune (yellowness), and greenness. optimisation_kwargs : dict_like, optional Parameters for :func:`scipy.optimize.fmin` definition. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- ndarray *CIE XYZ* tristimulus values under the *CIE 1964 10 Degree Standard Observer*. Warnings -------- There is no analytical inverse transformation from *OSA UCS* to :math:`Ljg` lightness, jaune (yellowness), and greenness to *CIE XYZ* tristimulus values, the current implementation relies on optimization using :func:`scipy.optimize.fmin` definition and thus has reduced precision and poor performance. Notes ----- +------------+-----------------------+--------------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+====================+ | ``Ljg`` | ``L`` : [-100, 100] | ``L`` : [-1, 1] | | | | | | | ``j`` : [-100, 100] | ``j`` : [-1, 1] | | | | | | | ``g`` : [-100, 100] | ``g`` : [-1, 1] | +------------+-----------------------+--------------------+ +------------+-----------------------+--------------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+====================+ | ``XYZ`` | [0, 100] | [0, 1] | +------------+-----------------------+--------------------+ - *OSA UCS* uses the *CIE 1964 10 Degree Standard Observer*. References ---------- :cite:`Cao2013`, :cite:`Moroney2003` Examples -------- >>> import numpy as np >>> Ljg = np.array([-3.00499790, 2.99713697, -9.66784231]) >>> OSA_UCS_to_XYZ(Ljg) # doctest: +ELLIPSIS array([ 20.6540240..., 12.1972369..., 5.1369372...]) """ optimisation_kwargs = handle_arguments_deprecation( { 'ArgumentRenamed': [['optimisation_parameters', 'optimisation_kwargs']], }, **kwargs).get('optimisation_kwargs', optimisation_kwargs) Ljg = to_domain_100(Ljg) shape = Ljg.shape Ljg = np.atleast_1d(Ljg.reshape([-1, 3])) optimisation_settings = {'disp': False} if optimisation_kwargs is not None: optimisation_settings.update(optimisation_kwargs) def error_function(XYZ, Ljg): """ Error function. """ # Error must be computed in "reference" domain and range. with domain_range_scale('ignore'): error = np.linalg.norm(XYZ_to_OSA_UCS(XYZ) - Ljg) return error x_0 = np.array([30, 30, 30]) XYZ = as_float_array([ fmin(error_function, x_0, (Ljg_i, ), **optimisation_settings) for Ljg_i in Ljg ]) return from_range_100(XYZ.reshape(shape))
def XYZ_to_sRGB( XYZ, illuminant=CCS_ILLUMINANTS['CIE 1931 2 Degree Standard Observer'] ['D65'], chromatic_adaptation_transform='CAT02', apply_cctf_encoding=True, **kwargs): """ Converts from *CIE XYZ* tristimulus values to *sRGB* colourspace. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. illuminant : array_like, optional Source illuminant chromaticity coordinates. chromatic_adaptation_transform : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02 Brill 2008', 'Bianco 2010', 'Bianco PC 2010'}**, *Chromatic adaptation* transform. apply_cctf_encoding : bool, optional Apply *sRGB* encoding colour component transfer function / opto-electronic transfer function. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- ndarray *sRGB* colour array. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``RGB`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ Examples -------- >>> import numpy as np >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) >>> XYZ_to_sRGB(XYZ) # doctest: +ELLIPSIS array([ 0.7057393..., 0.1924826..., 0.2235416...]) """ apply_cctf_encoding = handle_arguments_deprecation( { 'ArgumentRenamed': [['apply_encoding_cctf', 'apply_cctf_encoding'] ], }, **kwargs).get('apply_cctf_encoding', apply_cctf_encoding) sRGB = RGB_COLOURSPACES['sRGB'] return XYZ_to_RGB( XYZ, illuminant, sRGB.whitepoint, sRGB.matrix_XYZ_to_RGB, chromatic_adaptation_transform, sRGB.cctf_encoding if apply_cctf_encoding else None, )
def log_encoding_SLog2(x, bit_depth=10, out_normalised_code_value=True, in_reflection=True, **kwargs): """ Defines the *Sony S-Log2* log encoding curve / opto-electronic transfer function. Parameters ---------- 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_normalised_code_value : bool, optional Whether the non-linear *Sony S-Log2* data :math:`y` is encoded as normalised code values. in_reflection : bool, optional Whether the light level :math:`x` to a camera is reflection. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray Non-linear *Sony S-Log2* data :math:`y`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``y`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`SonyCorporation2012a` Examples -------- >>> log_encoding_SLog2(0.18) # doctest: +ELLIPSIS 0.3395325... The values of *IRE and CV of S-Log2 @ISO800* table in :cite:`SonyCorporation2012a` are obtained as follows: >>> x = np.array([0, 18, 90]) / 100 >>> np.around(log_encoding_SLog2(x, 10, False) * 100).astype(np.int) array([ 3, 32, 59]) >>> np.around(log_encoding_SLog2(x) * (2 ** 10 - 1)).astype(np.int) array([ 90, 347, 582]) """ out_normalised_code_value = handle_arguments_deprecation( { 'ArgumentRenamed': [['out_legal', 'out_normalised_code_value']], }, **kwargs).get('out_normalised_code_value', out_normalised_code_value) return log_encoding_SLog(x * 155 / 219, bit_depth, out_normalised_code_value, in_reflection)
def plot_planckian_locus_in_chromaticity_diagram_CIE1960UCS( illuminants, chromaticity_diagram_callable_CIE1960UCS=( plot_chromaticity_diagram_CIE1960UCS), planckian_locus_callable_CIE1960UCS=plot_planckian_locus_CIE1960UCS, annotate_kwargs=None, plot_kwargs=None, **kwargs): """ Plots the *Planckian Locus* and given illuminants in *CIE 1960 UCS Chromaticity Diagram*. Parameters ---------- illuminants : unicode or object or array_like Illuminants to plot. ``illuminants`` elements can be of any type or form supported by the :func:`colour.plotting.filter_passthrough` definition. chromaticity_diagram_callable_CIE1960UCS : callable, optional Callable responsible for drawing the *CIE 1960 UCS Chromaticity Diagram*. planckian_locus_callable_CIE1960UCS : callable, optional Callable responsible for drawing the *Planckian Locus* according to *CIE 1960 UCS* method. annotate_kwargs : dict or array_like, optional Keyword arguments for the :func:`plt.annotate` definition, used to annotate the resulting chromaticity coordinates with their respective illuminant names. ``annotate_kwargs`` can be either a single dictionary applied to all the arrows with same settings or a sequence of dictionaries with different settings for each illuminant. The following special keyword arguments can also be used: - *annotate* : bool, whether to annotate the illuminants. plot_kwargs : dict or array_like, optional Keyword arguments for the :func:`plt.plot` definition, used to control the style of the plotted illuminants. ``plot_kwargs`` can be either a single dictionary applied to all the plotted illuminants with same settings or a sequence of dictionaries with different settings for each plotted illuminant. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.diagrams.plot_chromaticity_diagram`, :func:`colour.plotting.temperature.plot_planckian_locus`, :func:`colour.plotting.temperature.\ plot_planckian_locus_in_chromaticity_diagram`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Also handles keywords arguments for deprecation management. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_planckian_locus_in_chromaticity_diagram_CIE1960UCS( ... ['A', 'C', 'E']) # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, <...AxesSubplot...>) .. image:: ../_static/Plotting_\ Plot_Planckian_Locus_In_Chromaticity_Diagram_CIE1960UCS.png :align: center :alt: plot_planckian_locus_in_chromaticity_diagram_CIE1960UCS """ annotate_kwargs = handle_arguments_deprecation( { 'ArgumentRenamed': [['annotate_parameters', 'annotate_kwargs']], }, **kwargs).get('annotate_kwargs', annotate_kwargs) settings = dict(kwargs) settings.update({'method': 'CIE 1960 UCS'}) return plot_planckian_locus_in_chromaticity_diagram( illuminants, chromaticity_diagram_callable_CIE1960UCS, planckian_locus_callable_CIE1960UCS, annotate_kwargs=annotate_kwargs, plot_kwargs=plot_kwargs, **settings)
def log_encoding_SLog3(x, bit_depth=10, out_normalised_code_value=True, in_reflection=True, **kwargs): """ Defines the *Sony S-Log3* log encoding curve / opto-electronic transfer function. Parameters ---------- 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_normalised_code_value : bool, optional Whether the non-linear *Sony S-Log3* data :math:`y` is encoded as normalised code values. in_reflection : bool, optional Whether the light level :math:`x` to a camera is reflection. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray Non-linear *Sony S-Log3* data :math:`y`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``y`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`SonyCorporationd` Examples -------- >>> log_encoding_SLog3(0.18) # doctest: +ELLIPSIS 0.4105571... The values of *S-Log3 10bit code values (18%, 90%)* table in :cite:`SonyCorporationd` are obtained as follows: >>> x = np.array([0, 18, 90]) / 100 >>> np.around(log_encoding_SLog3(x, 10, False) * 100).astype(np.int) array([ 4, 41, 61]) >>> np.around(log_encoding_SLog3(x) * (2 ** 10 - 1)).astype(np.int) array([ 95, 420, 598]) """ out_normalised_code_value = handle_arguments_deprecation( { 'ArgumentRenamed': [['out_legal', 'out_normalised_code_value']], }, **kwargs).get('out_normalised_code_value', out_normalised_code_value) x = to_domain_1(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_normalised_code_value else legal_to_full(y, bit_depth) return as_float(from_range_1(y))
def RGB_to_RGB(RGB, input_colourspace, output_colourspace, chromatic_adaptation_transform='CAT02', apply_cctf_decoding=False, apply_cctf_encoding=False, **kwargs): """ Converts given *RGB* colourspace array from given input *RGB* colourspace to output *RGB* colourspace using given *chromatic adaptation* method. Parameters ---------- RGB : array_like *RGB* colourspace array. input_colourspace : RGB_Colourspace *RGB* input colourspace. output_colourspace : RGB_Colourspace *RGB* output colourspace. chromatic_adaptation_transform : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC', None}**, *Chromatic adaptation* transform, if *None* no chromatic adaptation is performed. apply_cctf_decoding : bool, optional Apply input colourspace decoding colour component transfer function / electro-optical transfer function. apply_cctf_encoding : bool, optional Apply output colourspace encoding colour component transfer function / opto-electronic transfer function. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for the colour component transfer functions. Returns ------- ndarray *RGB* colourspace array. Notes ----- +--------------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +====================+=======================+===============+ | ``RGB`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ +--------------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +====================+=======================+===============+ | ``RGB`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ Examples -------- >>> from colour.models import sRGB_COLOURSPACE, PROPHOTO_RGB_COLOURSPACE >>> RGB = np.array([0.45595571, 0.03039702, 0.04087245]) >>> RGB_to_RGB(RGB, sRGB_COLOURSPACE, PROPHOTO_RGB_COLOURSPACE) ... # doctest: +ELLIPSIS array([ 0.2568891..., 0.0721446..., 0.0465553...]) """ apply_cctf_decoding = handle_arguments_deprecation( { 'ArgumentRenamed': [['apply_decoding_cctf', 'apply_cctf_decoding'] ], }, **kwargs).get('apply_cctf_decoding', apply_cctf_decoding) apply_cctf_encoding = handle_arguments_deprecation( { 'ArgumentRenamed': [['apply_encoding_cctf', 'apply_cctf_encoding'] ], }, **kwargs).get('apply_cctf_encoding', apply_cctf_encoding) RGB = to_domain_1(RGB) if apply_cctf_decoding: with domain_range_scale('ignore'): RGB = input_colourspace.cctf_decoding( RGB, **filter_kwargs(input_colourspace.cctf_decoding, **kwargs)) M = RGB_to_RGB_matrix(input_colourspace, output_colourspace, chromatic_adaptation_transform) RGB = dot_vector(M, RGB) if apply_cctf_encoding: with domain_range_scale('ignore'): RGB = output_colourspace.cctf_encoding( RGB, **filter_kwargs(output_colourspace.cctf_encoding, **kwargs)) return from_range_1(RGB)
def log_encoding_SLog(x, bit_depth=10, out_normalised_code_value=True, in_reflection=True, **kwargs): """ Defines the *Sony S-Log* log encoding curve / opto-electronic transfer function. Parameters ---------- 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_normalised_code_value : bool, optional Whether the non-linear *Sony S-Log* data :math:`y` is encoded as normalised code values. in_reflection : bool, optional Whether the light level :math:`x` to a camera is reflection. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray Non-linear *Sony S-Log* data :math:`y`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``y`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`SonyCorporation2012a` Examples -------- >>> log_encoding_SLog(0.18) # doctest: +ELLIPSIS 0.3849708... The values of *IRE and CV of S-Log2 @ISO800* table in :cite:`SonyCorporation2012a` are obtained as follows: >>> x = np.array([0, 18, 90]) / 100 >>> np.around(log_encoding_SLog(x, 10, False) * 100).astype(np.int) array([ 3, 38, 65]) >>> np.around(log_encoding_SLog(x) * (2 ** 10 - 1)).astype(np.int) array([ 90, 394, 636]) """ out_normalised_code_value = handle_arguments_deprecation( { 'ArgumentRenamed': [['out_legal', 'out_normalised_code_value']], }, **kwargs).get('out_normalised_code_value', out_normalised_code_value) x = to_domain_1(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, ) y = full_to_legal(y, bit_depth) if out_normalised_code_value else y return as_float(from_range_1(y))
def XYZ_to_RGB(XYZ, illuminant_XYZ, illuminant_RGB, XYZ_to_RGB_matrix, chromatic_adaptation_transform='CAT02', cctf_encoding=None, **kwargs): """ Converts from *CIE XYZ* tristimulus values to *RGB* colourspace array. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. illuminant_XYZ : array_like *CIE XYZ* tristimulus values *illuminant* *CIE xy* chromaticity coordinates or *CIE xyY* colourspace array. illuminant_RGB : array_like *RGB* colourspace *illuminant* *CIE xy* chromaticity coordinates or *CIE xyY* colourspace array. XYZ_to_RGB_matrix : array_like *Normalised primary matrix*. chromatic_adaptation_transform : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC', None}**, *Chromatic adaptation* transform, if *None* no chromatic adaptation is performed. cctf_encoding : object, optional Encoding colour component transfer function (Encoding CCTF) or opto-electronic transfer function (OETF / OECF). Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- ndarray *RGB* colourspace array. Notes ----- +--------------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +====================+=======================+===============+ | ``XYZ`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ | ``illuminant_XYZ`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ | ``illuminant_RGB`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ +--------------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +====================+=======================+===============+ | ``RGB`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ Examples -------- >>> XYZ = np.array([0.21638819, 0.12570000, 0.03847493]) >>> illuminant_XYZ = np.array([0.34570, 0.35850]) >>> illuminant_RGB = np.array([0.31270, 0.32900]) >>> chromatic_adaptation_transform = 'Bradford' >>> XYZ_to_RGB_matrix = np.array( ... [[3.24062548, -1.53720797, -0.49862860], ... [-0.96893071, 1.87575606, 0.04151752], ... [0.05571012, -0.20402105, 1.05699594]] ... ) >>> XYZ_to_RGB(XYZ, illuminant_XYZ, illuminant_RGB, XYZ_to_RGB_matrix, ... chromatic_adaptation_transform) # doctest: +ELLIPSIS array([ 0.4559557..., 0.0303970..., 0.0408724...]) """ cctf_encoding = handle_arguments_deprecation( { 'ArgumentRenamed': [['encoding_cctf', 'cctf_encoding']], }, **kwargs).get('cctf_encoding', cctf_encoding) XYZ = to_domain_1(XYZ) if chromatic_adaptation_transform is not None: M_CAT = chromatic_adaptation_matrix_VonKries( xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)), xyY_to_XYZ(xy_to_xyY(illuminant_RGB)), transform=chromatic_adaptation_transform) XYZ = dot_vector(M_CAT, XYZ) RGB = dot_vector(XYZ_to_RGB_matrix, XYZ) if cctf_encoding is not None: with domain_range_scale('ignore'): RGB = cctf_encoding(RGB) return from_range_1(RGB)
def RGB_to_XYZ(RGB, illuminant_RGB, illuminant_XYZ, RGB_to_XYZ_matrix, chromatic_adaptation_transform='CAT02', cctf_decoding=None, **kwargs): """ Converts given *RGB* colourspace array to *CIE XYZ* tristimulus values. Parameters ---------- RGB : array_like *RGB* colourspace array. illuminant_RGB : array_like *RGB* colourspace *illuminant* chromaticity coordinates or *CIE xyY* colourspace array. illuminant_XYZ : array_like *CIE XYZ* tristimulus values *illuminant* chromaticity coordinates or *CIE xyY* colourspace array. RGB_to_XYZ_matrix : array_like *Normalised primary matrix*. chromatic_adaptation_transform : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC', None}**, *Chromatic adaptation* transform, if *None* no chromatic adaptation is performed. cctf_decoding : object, optional Decoding colour component transfer function (Decoding CCTF) or electro-optical transfer function (EOTF / EOCF). Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- ndarray *CIE XYZ* tristimulus values. Notes ----- +--------------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +====================+=======================+===============+ | ``RGB`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ | ``illuminant_XYZ`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ | ``illuminant_RGB`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ +--------------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +====================+=======================+===============+ | ``XYZ`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ Examples -------- >>> RGB = np.array([0.45595571, 0.03039702, 0.04087245]) >>> illuminant_RGB = np.array([0.31270, 0.32900]) >>> illuminant_XYZ = np.array([0.34570, 0.35850]) >>> chromatic_adaptation_transform = 'Bradford' >>> RGB_to_XYZ_matrix = np.array( ... [[0.41240000, 0.35760000, 0.18050000], ... [0.21260000, 0.71520000, 0.07220000], ... [0.01930000, 0.11920000, 0.95050000]] ... ) >>> RGB_to_XYZ(RGB, illuminant_RGB, illuminant_XYZ, RGB_to_XYZ_matrix, ... chromatic_adaptation_transform) # doctest: +ELLIPSIS array([ 0.2163881..., 0.1257 , 0.0384749...]) """ cctf_decoding = handle_arguments_deprecation( { 'ArgumentRenamed': [['decoding_cctf', 'cctf_decoding']], }, **kwargs).get('cctf_decoding', cctf_decoding) RGB = to_domain_1(RGB) if cctf_decoding is not None: with domain_range_scale('ignore'): RGB = cctf_decoding(RGB) XYZ = dot_vector(RGB_to_XYZ_matrix, RGB) if chromatic_adaptation_transform is not None: M_CAT = chromatic_adaptation_matrix_VonKries( xyY_to_XYZ(xy_to_xyY(illuminant_RGB)), xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)), transform=chromatic_adaptation_transform) XYZ = dot_vector(M_CAT, XYZ) return from_range_1(XYZ)
def log_encoding_CanonLog2(x, bit_depth=10, out_normalised_code_value=True, in_reflection=True, **kwargs): """ Defines the *Canon Log 2* log encoding curve / opto-electronic transfer function. Parameters ---------- x : numeric or array_like Linear data :math:`x`. bit_depth : int, optional Bit depth used for conversion. out_normalised_code_value : bool, optional Whether the *Canon Log 2* non-linear data is encoded as normalised code values. in_reflection : bool, optional Whether the light level :math:`x` to a camera is reflection. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- numeric or ndarray *Canon Log 2* non-linear data. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``x`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``clog2`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`Canona` Examples -------- >>> log_encoding_CanonLog2(0.18) * 100 # doctest: +ELLIPSIS 39.8254694... """ out_normalised_code_value = handle_arguments_deprecation( { 'ArgumentRenamed': [['out_legal', 'out_normalised_code_value']], }, **kwargs).get('out_normalised_code_value', out_normalised_code_value) x = to_domain_1(x) if in_reflection: x = x / 0.9 with domain_range_scale('ignore'): clog2 = np.where( x < log_decoding_CanonLog2(0.035388128, bit_depth, False), -(0.281863093 * (np.log10(-x * 87.09937546 + 1)) - 0.035388128), 0.281863093 * np.log10(x * 87.09937546 + 1) + 0.035388128, ) clog2 = (full_to_legal(clog2, bit_depth) if out_normalised_code_value else clog2) return as_float(from_range_1(clog2))