Exemple #1
0
    def test_get_domain_range_scale(self):
        """
        Test :func:`colour.utilities.common.get_domain_range_scale`
        definition.
        """

        with domain_range_scale("Reference"):
            self.assertEqual(get_domain_range_scale(), "reference")

        with domain_range_scale("1"):
            self.assertEqual(get_domain_range_scale(), "1")

        with domain_range_scale("100"):
            self.assertEqual(get_domain_range_scale(), "100")
Exemple #2
0
    def test_get_domain_range_scale(self):
        """
        Tests :func:`colour.utilities.common.get_domain_range_scale`
        definition.
        """

        with domain_range_scale('Reference'):
            self.assertEqual(get_domain_range_scale(), 'reference')

        with domain_range_scale('1'):
            self.assertEqual(get_domain_range_scale(), '1')

        with domain_range_scale('100'):
            self.assertEqual(get_domain_range_scale(), '100')
Exemple #3
0
    def test_get_domain_range_scale(self):
        """
        Tests :func:`colour.utilities.common.get_domain_range_scale`
        definition.
        """

        with domain_range_scale('Reference'):
            self.assertEqual(get_domain_range_scale(), 'reference')

        with domain_range_scale('1'):
            self.assertEqual(get_domain_range_scale(), '1')

        with domain_range_scale('100'):
            self.assertEqual(get_domain_range_scale(), '100')
Exemple #4
0
def delta_E_DIN99(Lab_1, Lab_2, textiles=False):
    """
    Returns the difference :math:`\\Delta E_{DIN99}` between two given
    *CIE L\\*a\\*b\\** colourspace arrays using *DIN99* formula.

    Parameters
    ----------
    Lab_1 : array_like
        *CIE L\\*a\\*b\\** colourspace array 1.
    Lab_2 : array_like
        *CIE L\\*a\\*b\\** colourspace array 2.

    Returns
    -------
    numeric or ndarray
        Colour difference :math:`\\Delta E_{DIN99}`.

    Notes
    -----

    +------------+-----------------------+-------------------+
    | **Domain** | **Scale - Reference** | **Scale - 1**     |
    +============+=======================+===================+
    | ``Lab_1``  | ``L_1`` : [0, 100]    | ``L_1`` : [0, 1]  |
    |            |                       |                   |
    |            | ``a_1`` : [-100, 100] | ``a_1`` : [-1, 1] |
    |            |                       |                   |
    |            | ``b_1`` : [-100, 100] | ``b_1`` : [-1, 1] |
    +------------+-----------------------+-------------------+
    | ``Lab_2``  | ``L_2`` : [0, 100]    | ``L_2`` : [0, 1]  |
    |            |                       |                   |
    |            | ``a_2`` : [-100, 100] | ``a_2`` : [-1, 1] |
    |            |                       |                   |
    |            | ``b_2`` : [-100, 100] | ``b_2`` : [-1, 1] |
    +------------+-----------------------+-------------------+

    References
    ----------
    :cite:`ASTMInternational2007`

    Examples
    --------
    >>> import numpy as np
    >>> Lab_1 = np.array([60.2574, -34.0099, 36.2677])
    >>> Lab_2 = np.array([60.4626, -34.1751, 39.4387])
    >>> delta_E_DIN99(Lab_1, Lab_2)  # doctest: +ELLIPSIS
    1.1772166...
    """

    k_E = 2 if textiles else 1
    k_CH = 0.5 if textiles else 1

    factor = 100 if get_domain_range_scale() == '1' else 1

    d_E = euclidean_distance(
        Lab_to_DIN99(Lab_1, k_E, k_CH) * factor,
        Lab_to_DIN99(Lab_2, k_E, k_CH) * factor)

    return d_E
Exemple #5
0
def delta_E_DIN99(Lab_1, Lab_2, textiles=False):
    """
    Returns the difference :math:`\\Delta E_{DIN99}` between two given
    *CIE L\\*a\\*b\\** colourspace arrays using *DIN99* formula.

    Parameters
    ----------
    Lab_1 : array_like
        *CIE L\\*a\\*b\\** colourspace array 1.
    Lab_2 : array_like
        *CIE L\\*a\\*b\\** colourspace array 2.

    Returns
    -------
    numeric or ndarray
        Colour difference :math:`\\Delta E_{DIN99}`.

    Notes
    -----

    +------------+-----------------------+-------------------+
    | **Domain** | **Scale - Reference** | **Scale - 1**     |
    +============+=======================+===================+
    | ``Lab_1``  | ``L_1`` : [0, 100]    | ``L_1`` : [0, 1]  |
    |            |                       |                   |
    |            | ``a_1`` : [-100, 100] | ``a_1`` : [-1, 1] |
    |            |                       |                   |
    |            | ``b_1`` : [-100, 100] | ``b_1`` : [-1, 1] |
    +------------+-----------------------+-------------------+
    | ``Lab_2``  | ``L_2`` : [0, 100]    | ``L_2`` : [0, 1]  |
    |            |                       |                   |
    |            | ``a_2`` : [-100, 100] | ``a_2`` : [-1, 1] |
    |            |                       |                   |
    |            | ``b_2`` : [-100, 100] | ``b_2`` : [-1, 1] |
    +------------+-----------------------+-------------------+

    References
    ----------
    :cite:`ASTMInternational2007`

    Examples
    --------
    >>> import numpy as np
    >>> Lab_1 = np.array([60.2574, -34.0099, 36.2677])
    >>> Lab_2 = np.array([60.4626, -34.1751, 39.4387])
    >>> delta_E_DIN99(Lab_1, Lab_2)  # doctest: +ELLIPSIS
    1.1772166...
    """

    k_E = 2 if textiles else 1
    k_CH = 0.5 if textiles else 1

    factor = 100 if get_domain_range_scale() == '1' else 1

    d_E = euclidean_distance(
        Lab_to_DIN99(Lab_1, k_E, k_CH) * factor,
        Lab_to_DIN99(Lab_2, k_E, k_CH) * factor)

    return d_E
Exemple #6
0
    def test_set_domain_range_scale(self):
        """
        Test :func:`colour.utilities.common.set_domain_range_scale`
        definition.
        """

        with domain_range_scale("Reference"):
            set_domain_range_scale("1")
            self.assertEqual(get_domain_range_scale(), "1")

        with domain_range_scale("Reference"):
            set_domain_range_scale("100")
            self.assertEqual(get_domain_range_scale(), "100")

        with domain_range_scale("1"):
            set_domain_range_scale("Reference")
            self.assertEqual(get_domain_range_scale(), "reference")

        self.assertRaises(ValueError,
                          lambda: set_domain_range_scale("Invalid"))
Exemple #7
0
    def test_set_domain_range_scale(self):
        """
        Tests :func:`colour.utilities.common.set_domain_range_scale`
        definition.
        """

        with domain_range_scale('Reference'):
            set_domain_range_scale('1')
            self.assertEqual(get_domain_range_scale(), '1')

        with domain_range_scale('Reference'):
            set_domain_range_scale('100')
            self.assertEqual(get_domain_range_scale(), '100')

        with domain_range_scale('1'):
            set_domain_range_scale('Reference')
            self.assertEqual(get_domain_range_scale(), 'reference')

        self.assertRaises(AssertionError,
                          lambda: set_domain_range_scale('Invalid'))
Exemple #8
0
    def test_set_domain_range_scale(self):
        """
        Tests :func:`colour.utilities.common.set_domain_range_scale`
        definition.
        """

        with domain_range_scale('Reference'):
            set_domain_range_scale('1')
            self.assertEqual(get_domain_range_scale(), '1')

        with domain_range_scale('Reference'):
            set_domain_range_scale('100')
            self.assertEqual(get_domain_range_scale(), '100')

        with domain_range_scale('1'):
            set_domain_range_scale('Reference')
            self.assertEqual(get_domain_range_scale(), 'reference')

        self.assertRaises(AssertionError,
                          lambda: set_domain_range_scale('Invalid'))
Exemple #9
0
def whiteness(XYZ, XYZ_0, method='CIE 2004', **kwargs):
    """
    Returns the *whiteness* :math:`W` using given method.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of sample.
    XYZ_0 : array_like
        *CIE XYZ* tristimulus values of reference white.
    method : unicode, optional
        **{'CIE 2004', 'Berger 1959', 'Taube 1960', 'Stensby 1968',
        'ASTM E313', 'Ganz 1979'}**,
        Computation method.

    Other Parameters
    ----------------
    observer : unicode, optional
        {:func:`colour.colorimetry.whiteness_CIE2004`},
        **{'CIE 1931 2 Degree Standard Observer',
        'CIE 1964 10 Degree Standard Observer'}**,
        *CIE Standard Observer* used for computations, *tint* :math:`T` or
        :math:`T_{10}` value is dependent on viewing field angular subtense.

    Returns
    -------
    numeric or ndarray
        *whiteness* :math:`W`.

    Notes
    -----

    +------------+-----------------------+-----------------+
    | **Domain** | **Scale - Reference** |   **Scale - 1** |
    +============+=======================+=================+
    +------------+-----------------------+-----------------+
    | ``XYZ``    | [0, 100]              |   [0, 1]        |
    +------------+-----------------------+-----------------+
    | ``XYZ_0``  | [0, 100]              |   [0, 1]        |
    +------------+-----------------------+-----------------+

    +------------+-----------------------+-----------------+
    | **Range**  | **Scale - Reference** |   **Scale - 1** |
    +============+=======================+=================+
    | ``W``      | [0, 100]              |   [0, 1]        |
    +------------+-----------------------+-----------------+

    References
    ----------
    :cite:`CIETC1-482004k`, :cite:`Wyszecki2000ba`, :cite:`X-Rite2012a`,
    :cite:`Wikipedia2004b`

    Examples
    --------
    >>> import numpy as np
    >>> from colour.models import xyY_to_XYZ
    >>> XYZ = xyY_to_XYZ(np.array([0.3167, 0.3334, 100]))
    >>> XYZ_0 = xyY_to_XYZ(np.array([0.3139, 0.3311, 100]))
    >>> whiteness(XYZ, XYZ_0)  # doctest: +ELLIPSIS
    array([ 93.85...,  -1.305...])
    >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000])
    >>> XYZ_0 = np.array([94.80966767, 100.00000000, 107.30513595])
    >>> whiteness(XYZ, XYZ_0, method='Taube 1960')  # doctest: +ELLIPSIS
    91.4071738...
    """

    kwargs.update({'XYZ': XYZ, 'XYZ_0': XYZ_0})

    function = WHITENESS_METHODS.get(method)

    if function is whiteness_Stensby1968:
        from colour.models import XYZ_to_Lab, XYZ_to_xy

        if get_domain_range_scale() == 'reference':
            XYZ = XYZ / 100
            XYZ_0 = XYZ_0 / 100

        kwargs.update({'Lab': XYZ_to_Lab(XYZ, XYZ_to_xy(XYZ_0))})
    elif function in (whiteness_Ganz1979, whiteness_CIE2004):
        from colour.models import XYZ_to_xy

        _X_0, Y_0, _Z_0 = tsplit(XYZ_0)
        kwargs.update({
            'xy': XYZ_to_xy(XYZ),
            'Y': Y_0,
            'xy_n': XYZ_to_xy(XYZ_0)
        })

    return function(**filter_kwargs(function, **kwargs))
Exemple #10
0
def lightness(Y, method='CIE 1976', **kwargs):
    """
    Returns the *Lightness* :math:`L` of given *luminance* :math:`Y` using
    given method.

    Parameters
    ----------
    Y : numeric or array_like
        *luminance* :math:`Y`.
    method : unicode, optional
        **{'CIE 1976', 'Glasser 1958', 'Wyszecki 1963', 'Fairchild 2010',
        'Fairchild 2011'}**,
        Computation method.

    Other Parameters
    ----------------
    Y_n : numeric or array_like, optional
        {:func:`colour.colorimetry.lightness_CIE1976`},
        White reference *luminance* :math:`Y_n`.
    epsilon : numeric or array_like, optional
        {:func:`colour.colorimetry.lightness_Fairchild2010`,
        :func:`colour.colorimetry.lightness_Fairchild2011`},
        :math:`\\epsilon` exponent.

    Returns
    -------
    numeric or array_like
        *Lightness* :math:`L`.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``Y``      | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L``      | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`CIETC1-482004m`, :cite:`Fairchild2010`, :cite:`Fairchild2011`,
    :cite:`Glasser1958a`, :cite:`Wikipedia2007c`, :cite:`Wyszecki1963b`,
    :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> lightness(12.19722535)  # doctest: +ELLIPSIS
    41.5278758...
    >>> lightness(12.19722535, Y_n=100)  # doctest: +ELLIPSIS
    41.5278758...
    >>> lightness(12.19722535, Y_n=95)  # doctest: +ELLIPSIS
    42.5199307...
    >>> lightness(12.19722535, method='Glasser 1958')  # doctest: +ELLIPSIS
    39.8351264...
    >>> lightness(12.19722535, method='Wyszecki 1963')  # doctest: +ELLIPSIS
    40.5475745...
    >>> lightness(12.19722535, epsilon=0.710, method='Fairchild 2011')
    ... # doctest: +ELLIPSIS
    29.8295108...
    """

    Y = as_float_array(Y)

    function = LIGHTNESS_METHODS[method]

    domain_range_reference = get_domain_range_scale() == 'reference'
    domain_1 = (lightness_Fairchild2010, lightness_Fairchild2011)

    if function in domain_1 and domain_range_reference:
        Y = Y / 100

    return function(Y, **filter_kwargs(function, **kwargs))
Exemple #11
0
def UCS_Li2017_to_XYZ(Jpapbp: ArrayLike, coefficients: ArrayLike,
                      **kwargs: Any) -> NDArray:
    """
    Convert from one of the *Li et al. (2017)* *CAM16-LCD*, *CAM16-SCD*, or
    *CAM16-UCS* colourspaces :math:`J'a'b'` array to *CIE XYZ* tristimulus
    values.

    Parameters
    ----------
    Jpapbp
        *Li et al. (2017)* *CAM16-LCD*, *CAM16-SCD*, or *CAM16-UCS*
        colourspaces :math:`J'a'b'` array.
    coefficients
        Coefficients of one of the *Li et al. (2017)* *CAM16-LCD*, *CAM16-SCD*,
        or *CAM16-UCS* colourspaces.

    Other Parameters
    ----------------
    kwargs
        {:func:`colour.CAM16_to_XYZ`},
        See the documentation of the previously listed definition. The default
        viewing conditions are that of *IEC 61966-2-1:1999*, i.e. *sRGB* 64 Lux
        ambient illumination, 80 :math:`cd/m^2`, adapting field luminance about
        20% of a white object in the scene.

    Returns
    -------
    :class:`numpy.ndarray`
        *CIE XYZ* tristimulus values.

    Warnings
    --------
    The ``XYZ_w`` parameter for :func:`colour.XYZ_to_CAM16` definition must be
    given in the same domain-range scale than the ``XYZ`` parameter.

    Notes
    -----
    +------------+------------------------+------------------+
    | **Domain** |  **Scale - Reference** | **Scale - 1**    |
    +============+========================+==================+
    | ``Jpapbp`` | ``Jp`` : [0, 100]      | ``Jp`` : [0, 1]  |
    |            |                        |                  |
    |            | ``ap`` : [-100, 100]   | ``ap`` : [-1, 1] |
    |            |                        |                  |
    |            | ``bp`` : [-100, 100]   | ``bp`` : [-1, 1] |
    +------------+------------------------+------------------+

    +------------+------------------------+------------------+
    | **Range**  |  **Scale - Reference** | **Scale - 1**    |
    +============+========================+==================+
    | ``XYZ``    | [0, 1]                 | [0, 1]           |
    +------------+------------------------+------------------+

    Examples
    --------
    >>> import numpy as np
    >>> Jpapbp = np.array([46.06586037, 41.07586491, 14.51025828])
    >>> UCS_Li2017_to_XYZ(
    ...     Jpapbp, COEFFICIENTS_UCS_LUO2006['CAM02-LCD'])
    ... # doctest: +ELLIPSIS
    array([ 0.2065400...,  0.1219722...,  0.0513695...])

    >>> from colour.appearance import CAM_KWARGS_CIECAM02_sRGB
    >>> XYZ_w = CAM_KWARGS_CIECAM02_sRGB['XYZ_w']
    >>> UCS_Li2017_to_XYZ(
    ...     Jpapbp, COEFFICIENTS_UCS_LUO2006['CAM02-LCD'], XYZ_w=XYZ_w / 100)
    ... # doctest: +ELLIPSIS
    array([ 0.2065400...,  0.1219722...,  0.0513695...])
    """

    from colour.appearance import (
        CAM_KWARGS_CIECAM02_sRGB,
        CAM_Specification_CAM16,
        CAM16_to_XYZ,
    )

    domain_range_reference = get_domain_range_scale() == "reference"

    settings = CAM_KWARGS_CIECAM02_sRGB.copy()
    settings.update(**kwargs)
    XYZ_w = kwargs.get("XYZ_w")

    if XYZ_w is not None and domain_range_reference:
        settings["XYZ_w"] = XYZ_w * 100

    J, M, h = tsplit(UCS_Li2017_to_JMh_CAM16(Jpapbp, coefficients))

    specification = CAM_Specification_CAM16(J=J, M=M, h=h)

    XYZ = CAM16_to_XYZ(specification, **settings)

    if domain_range_reference:
        XYZ /= 100

    return XYZ
Exemple #12
0
def XYZ_to_UCS_Luo2006(XYZ: ArrayLike, coefficients: ArrayLike,
                       **kwargs: Any) -> NDArray:
    """
    Convert from *CIE XYZ* tristimulus values to one of the
    *Luo et al. (2006)* *CAM02-LCD*, *CAM02-SCD*, or *CAM02-UCS* colourspaces
    :math:`J'a'b'` array.

    Parameters
    ----------
    XYZ
        *CIE XYZ* tristimulus values.
    coefficients
        Coefficients of one of the *Luo et al. (2006)* *CAM02-LCD*,
        *CAM02-SCD*, or *CAM02-UCS* colourspaces.

    Other Parameters
    ----------------
    kwargs
        {:func:`colour.XYZ_to_CIECAM02`},
        See the documentation of the previously listed definition. The default
        viewing conditions are that of *IEC 61966-2-1:1999*, i.e. *sRGB* 64 Lux
        ambient illumination, 80 :math:`cd/m^2`, adapting field luminance about
        20% of a white object in the scene.

    Returns
    -------
    :class:`numpy.ndarray`
        *Luo et al. (2006)* *CAM02-LCD*, *CAM02-SCD*, or *CAM02-UCS*
        colourspaces :math:`J'a'b'` array.

    Warnings
    --------
    The ``XYZ_w`` parameter for :func:`colour.XYZ_to_CAM16` definition must be
    given in the same domain-range scale than the ``XYZ`` parameter.

    Notes
    -----
    +------------+------------------------+------------------+
    | **Domain** |  **Scale - Reference** | **Scale - 1**    |
    +============+========================+==================+
    | ``XYZ``    | [0, 1]                 | [0, 1]           |
    +------------+------------------------+------------------+

    +------------+------------------------+------------------+
    | **Range**  |  **Scale - Reference** | **Scale - 1**    |
    +============+========================+==================+
    | ``Jpapbp`` | ``Jp`` : [0, 100]      | ``Jp`` : [0, 1]  |
    |            |                        |                  |
    |            | ``ap`` : [-100, 100]   | ``ap`` : [-1, 1] |
    |            |                        |                  |
    |            | ``bp`` : [-100, 100]   | ``bp`` : [-1, 1] |
    +------------+------------------------+------------------+

    Examples
    --------
    >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952])
    >>> XYZ_to_UCS_Luo2006(XYZ, COEFFICIENTS_UCS_LUO2006['CAM02-LCD'])
    ... # doctest: +ELLIPSIS
    array([ 46.6138615...,  39.3576023...,  15.9673043...])
    """

    from colour.appearance import CAM_KWARGS_CIECAM02_sRGB, XYZ_to_CIECAM02

    domain_range_reference = get_domain_range_scale() == "reference"

    settings = CAM_KWARGS_CIECAM02_sRGB.copy()
    settings.update(**kwargs)
    XYZ_w = kwargs.get("XYZ_w")
    if XYZ_w is not None and domain_range_reference:
        settings["XYZ_w"] = XYZ_w * 100

    if domain_range_reference:
        XYZ = as_float_array(XYZ) * 100

    specification = XYZ_to_CIECAM02(XYZ, **settings)
    JMh = tstack([specification.J, specification.M, specification.h])

    return JMh_CIECAM02_to_UCS_Luo2006(JMh, coefficients)
Exemple #13
0
def lightness(Y, method='CIE 1976', **kwargs):
    """
    Returns the *Lightness* :math:`L` of given *luminance* :math:`Y` using
    given method.

    Parameters
    ----------
    Y : numeric or array_like
        *luminance* :math:`Y`.
    method : unicode, optional
        **{'CIE 1976', 'Glasser 1958', 'Wyszecki 1963', 'Fairchild 2010',
        'Fairchild 2011'}**,
        Computation method.

    Other Parameters
    ----------------
    Y_n : numeric or array_like, optional
        {:func:`colour.colorimetry.lightness_CIE1976`},
        White reference *luminance* :math:`Y_n`.
    epsilon : numeric or array_like, optional
        {:func:`colour.colorimetry.lightness_Fairchild2010`,
        :func:`colour.colorimetry.lightness_Fairchild2011`},
        :math:`\\epsilon` exponent.

    Returns
    -------
    numeric or array_like
        *Lightness* :math:`L`.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``Y``      | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L``      | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`CIETC1-482004m`, :cite:`Fairchild2010`, :cite:`Fairchild2011`,
    :cite:`Glasser1958a`, :cite:`Wikipedia2007c`, :cite:`Wyszecki1963b`,
    :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> lightness(12.19722535)  # doctest: +ELLIPSIS
    41.5278758...
    >>> lightness(12.19722535, Y_n=100)  # doctest: +ELLIPSIS
    41.5278758...
    >>> lightness(12.19722535, Y_n=95)  # doctest: +ELLIPSIS
    42.5199307...
    >>> lightness(12.19722535, method='Glasser 1958')  # doctest: +ELLIPSIS
    39.8351264...
    >>> lightness(12.19722535, method='Wyszecki 1963')  # doctest: +ELLIPSIS
    40.5475745...
    >>> lightness(12.19722535, epsilon=0.710, method='Fairchild 2011')
    ... # doctest: +ELLIPSIS
    29.8295108...
    """

    Y = as_float_array(Y)

    function = LIGHTNESS_METHODS[method]

    domain_range_reference = get_domain_range_scale() == 'reference'
    domain_1 = (lightness_Fairchild2010, lightness_Fairchild2011)

    if function in domain_1 and domain_range_reference:
        Y = Y / 100

    return function(Y, **filter_kwargs(function, **kwargs))
Exemple #14
0
def chromatic_adaptation(XYZ, XYZ_w, XYZ_wr, method='Von Kries', **kwargs):
    """
    Adapts given stimulus from test viewing conditions to reference viewing
    conditions.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of stimulus to adapt.
    XYZ_w : array_like
        Test viewing condition *CIE XYZ* tristimulus values of the whitepoint.
    XYZ_wr : array_like
        Reference viewing condition *CIE XYZ* tristimulus values of the
        whitepoint.
    method : unicode, optional
        **{'Von Kries', 'CIE 1994', 'CMCCAT2000', 'Fairchild 1990'}**,
        Computation method.

    Other Parameters
    ----------------
    E_o1 : numeric
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Test illuminance :math:`E_{o1}` in :math:`cd/m^2`.
    E_o2 : numeric
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Reference illuminance :math:`E_{o2}` in :math:`cd/m^2`.
    L_A1 : numeric or array_like
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        Luminance of test adapting field :math:`L_{A1}` in :math:`cd/m^2`.
    L_A2 : numeric or array_like
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        Luminance of reference adapting field :math:`L_{A2}` in :math:`cd/m^2`.
    Y_n : numeric or array_like
        {:func:`colour.adaptation.chromatic_adaptation_Fairchild1990`},
        Luminance :math:`Y_n` of test adapting stimulus in :math:`cd/m^2`.
    Y_o : numeric
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Luminance factor :math:`Y_o` of achromatic background normalised to
        domain [0.18, 1] in **'Reference'** domain-range scale.
    direction : unicode, optional
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        **{'Forward', 'Reverse'}**,
        Chromatic adaptation direction.
    discount_illuminant : bool, optional
        {:func:`colour.adaptation.chromatic_adaptation_Fairchild1990`},
        Truth value indicating if the illuminant should be discounted.
    n : numeric, optional
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Noise component in fundamental primary system.
    surround : CMCCAT2000_InductionFactors, optional
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        Surround viewing conditions induction factors.
    transform : unicode, optional
        {:func:`colour.adaptation.chromatic_adaptation_VonKries`},
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC'}**,
        Chromatic adaptation transform.

    Returns
    -------
    ndarray
        *CIE XYZ_c* tristimulus values of the stimulus corresponding colour.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``XYZ``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_w``  | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_wr`` | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``Y_o``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``XYZ_c``  | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`CIETC1-321994b`, :cite:`Fairchild1991a`, :cite:`Fairchild2013s`,
    :cite:`Fairchild2013t`, :cite:`Li2002a`, :cite:`Westland2012k`

    Examples
    --------

    *Von Kries* chromatic adaptation:

    >>> import numpy as np
    >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952])
    >>> XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775])
    >>> XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460])
    >>> chromatic_adaptation(XYZ, XYZ_w, XYZ_wr)
    ... # doctest: +ELLIPSIS
    array([ 0.2163881...,  0.1257    ,  0.0384749...])

    *CIE 1994* chromatic adaptation, requires extra *kwargs*:

    >>> XYZ = np.array([0.2800, 0.2126, 0.0527])
    >>> XYZ_w = np.array([1.09867452, 1.00000000, 0.35591556])
    >>> XYZ_wr = np.array([0.95045593, 1.00000000, 1.08905775])
    >>> Y_o = 0.20
    >>> E_o = 1000
    >>> chromatic_adaptation(
    ...     XYZ, XYZ_w, XYZ_wr, method='CIE 1994', Y_o=Y_o, E_o1=E_o, E_o2=E_o)
    ... # doctest: +ELLIPSIS
    array([ 0.2403379...,  0.2115621...,  0.1764301...])

    *CMCCAT2000* chromatic adaptation, requires extra *kwargs*:

    >>> XYZ = np.array([0.2248, 0.2274, 0.0854])
    >>> XYZ_w = np.array([1.1115, 1.0000, 0.3520])
    >>> XYZ_wr = np.array([0.9481, 1.0000, 1.0730])
    >>> L_A = 200
    >>> chromatic_adaptation(
    ...     XYZ, XYZ_w, XYZ_wr, method='CMCCAT2000', L_A1=L_A, L_A2=L_A)
    ... # doctest: +ELLIPSIS
    array([ 0.1952698...,  0.2306834...,  0.2497175...])

    *Fairchild (1990)* chromatic adaptation, requires extra *kwargs*:

    >>> XYZ = np.array([0.1953, 0.2307, 0.2497])
    >>> Y_n = 200
    >>> chromatic_adaptation(
    ...     XYZ, XYZ_w, XYZ_wr, method='Fairchild 1990', Y_n=Y_n)
    ... # doctest: +ELLIPSIS
    array([ 0.2332526...,  0.2332455...,  0.7611593...])
    """

    function = CHROMATIC_ADAPTATION_METHODS[method]

    domain_range_reference = get_domain_range_scale() == 'reference'
    domain_100 = (chromatic_adaptation_CIE1994,
                  chromatic_adaptation_CMCCAT2000,
                  chromatic_adaptation_Fairchild1990)

    if function in domain_100 and domain_range_reference:
        XYZ = as_float_array(XYZ) * 100
        XYZ_w = as_float_array(XYZ_w) * 100
        XYZ_wr = as_float_array(XYZ_wr) * 100
        if kwargs.get('Y_o'):
            kwargs['Y_o'] = kwargs['Y_o'] * 100

    kwargs.update({'XYZ_w': XYZ_w, 'XYZ_wr': XYZ_wr})

    if function is chromatic_adaptation_CIE1994:
        from colour import XYZ_to_xy

        kwargs.update({'xy_o1': XYZ_to_xy(XYZ_w), 'xy_o2': XYZ_to_xy(XYZ_wr)})

    elif function is chromatic_adaptation_Fairchild1990:
        kwargs.update({'XYZ_n': XYZ_w, 'XYZ_r': XYZ_wr})

    XYZ_c = function(XYZ, **filter_kwargs(function, **kwargs))

    if function in domain_100 and domain_range_reference:
        XYZ_c /= 100

    return XYZ_c
Exemple #15
0
def whiteness(
    XYZ: ArrayLike,
    XYZ_0: ArrayLike,
    method: Union[Literal["ASTM E313", "CIE 2004", "Berger 1959", "Ganz 1979",
                          "Stensby 1968", "Taube 1960", ], str, ] = "CIE 2004",
    **kwargs: Any,
) -> FloatingOrNDArray:
    """
    Return the *whiteness* :math:`W` using given method.

    Parameters
    ----------
    XYZ
        *CIE XYZ* tristimulus values of the sample.
    XYZ_0
        *CIE XYZ* tristimulus values of the reference white.
    method
        Computation method.

    Other Parameters
    ----------------
    observer
        {:func:`colour.colorimetry.whiteness_CIE2004`},
        *CIE Standard Observer* used for computations, *tint* :math:`T` or
        :math:`T_{10}` value is dependent on viewing field angular subtense.

    Returns
    -------
    :class:`np.floating` or :class:`numpy.ndarray`
        *Whiteness* :math:`W`.

    Notes
    -----
    +------------+-----------------------+-----------------+
    | **Domain** | **Scale - Reference** |   **Scale - 1** |
    +============+=======================+=================+
    +------------+-----------------------+-----------------+
    | ``XYZ``    | [0, 100]              |   [0, 1]        |
    +------------+-----------------------+-----------------+
    | ``XYZ_0``  | [0, 100]              |   [0, 1]        |
    +------------+-----------------------+-----------------+

    +------------+-----------------------+-----------------+
    | **Range**  | **Scale - Reference** |   **Scale - 1** |
    +============+=======================+=================+
    | ``W``      | [0, 100]              |   [0, 1]        |
    +------------+-----------------------+-----------------+

    References
    ----------
    :cite:`CIETC1-482004k`, :cite:`Wyszecki2000ba`, :cite:`X-Rite2012a`,
    :cite:`Wikipedia2004b`

    Examples
    --------
    >>> import numpy as np
    >>> from colour.models import xyY_to_XYZ
    >>> XYZ = xyY_to_XYZ(np.array([0.3167, 0.3334, 100]))
    >>> XYZ_0 = xyY_to_XYZ(np.array([0.3139, 0.3311, 100]))
    >>> whiteness(XYZ, XYZ_0)  # doctest: +ELLIPSIS
    array([ 93.85...,  -1.305...])
    >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000])
    >>> XYZ_0 = np.array([94.80966767, 100.00000000, 107.30513595])
    >>> whiteness(XYZ, XYZ_0, method='Taube 1960')  # doctest: +ELLIPSIS
    91.4071738...
    """

    XYZ = as_float_array(XYZ)
    XYZ_0 = as_float_array(XYZ_0)

    method = validate_method(method, WHITENESS_METHODS)

    kwargs.update({"XYZ": XYZ, "XYZ_0": XYZ_0})

    function = WHITENESS_METHODS[method]

    if function is whiteness_Stensby1968:
        from colour.models import XYZ_to_Lab, XYZ_to_xy

        if get_domain_range_scale() == "reference":
            XYZ = XYZ / 100
            XYZ_0 = XYZ_0 / 100

        kwargs.update({"Lab": XYZ_to_Lab(XYZ, XYZ_to_xy(XYZ_0))})
    elif function in (whiteness_Ganz1979, whiteness_CIE2004):
        from colour.models import XYZ_to_xy

        _X_0, Y_0, _Z_0 = tsplit(XYZ_0)
        kwargs.update({
            "xy": XYZ_to_xy(XYZ),
            "Y": Y_0,
            "xy_n": XYZ_to_xy(XYZ_0)
        })

    return function(**filter_kwargs(function, **kwargs))
Exemple #16
0
def chromatic_adaptation(
    XYZ: ArrayLike,
    XYZ_w: ArrayLike,
    XYZ_wr: ArrayLike,
    method: Union[Literal["CIE 1994", "CMCCAT2000", "Fairchild 1990",
                          "Zhai 2018", "Von Kries", ], str, ] = "Von Kries",
    **kwargs: Any,
) -> NDArray:
    """
    Adapt given stimulus from test viewing conditions to reference viewing
    conditions.

    Parameters
    ----------
    XYZ
        *CIE XYZ* tristimulus values of stimulus to adapt.
    XYZ_w
        Test viewing condition *CIE XYZ* tristimulus values of the whitepoint.
    XYZ_wr
        Reference viewing condition *CIE XYZ* tristimulus values of the
        whitepoint.
    method
        Computation method.

    Other Parameters
    ----------------
    E_o1
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Test illuminance :math:`E_{o1}` in :math:`cd/m^2`.
    E_o2
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Reference illuminance :math:`E_{o2}` in :math:`cd/m^2`.
    n
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Noise component in fundamental primary system.
    Y_o
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Luminance factor :math:`Y_o` of achromatic background normalised to
        domain [0.18, 1] in **'Reference'** domain-range scale.
    direction
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        Chromatic adaptation direction.
    L_A1
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        Luminance of test adapting field :math:`L_{A1}` in :math:`cd/m^2`.
    L_A2
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        Luminance of reference adapting field :math:`L_{A2}` in :math:`cd/m^2`.
    surround
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        Surround viewing conditions induction factors.
    discount_illuminant
        {:func:`colour.adaptation.chromatic_adaptation_Fairchild1990`},
        Truth value indicating if the illuminant should be discounted.
    Y_n
        {:func:`colour.adaptation.chromatic_adaptation_Fairchild1990`},
        Luminance :math:`Y_n` of test adapting stimulus in :math:`cd/m^2`.
    D_b
        {:func:`colour.adaptation.chromatic_adaptation_Zhai2018`},
        Degree of adaptation :math:`D_\\beta` of input illuminant
        :math:`\\beta`.
    D_d
        {:func:`colour.adaptation.chromatic_adaptation_Zhai2018`},
        Degree of adaptation :math:`D_\\Delta` of output illuminant
        :math:`\\Delta`.
    transform
        {:func:`colour.adaptation.chromatic_adaptation_VonKries`,
        :func:`colour.adaptation.chromatic_adaptation_Zhai2018`},
        Chromatic adaptation transform.
    XYZ_wo
        {:func:`colour.adaptation.chromatic_adaptation_Zhai2018`},
        Baseline illuminant (:math:`BI`) :math:`o`.

    Returns
    -------
    :class:`numpy.ndarray`
        *CIE XYZ_c* tristimulus values of the stimulus corresponding colour.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``XYZ``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_w``  | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_wr`` | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_wo`` | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``Y_o``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``XYZ_c``  | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`CIETC1-321994b`, :cite:`Fairchild1991a`, :cite:`Fairchild2013s`,
    :cite:`Fairchild2013t`, :cite:`Li2002a`, :cite:`Westland2012k`

    Examples
    --------
    *Von Kries* chromatic adaptation:

    >>> import numpy as np
    >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952])
    >>> XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775])
    >>> XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460])
    >>> chromatic_adaptation(XYZ, XYZ_w, XYZ_wr)
    ... # doctest: +ELLIPSIS
    array([ 0.2163881...,  0.1257    ,  0.0384749...])

    *CIE 1994* chromatic adaptation, requires extra *kwargs*:

    >>> XYZ = np.array([0.2800, 0.2126, 0.0527])
    >>> XYZ_w = np.array([1.09867452, 1.00000000, 0.35591556])
    >>> XYZ_wr = np.array([0.95045593, 1.00000000, 1.08905775])
    >>> Y_o = 0.20
    >>> E_o = 1000
    >>> chromatic_adaptation(
    ...     XYZ, XYZ_w, XYZ_wr, method='CIE 1994', Y_o=Y_o, E_o1=E_o, E_o2=E_o)
    ... # doctest: +ELLIPSIS
    array([ 0.2403379...,  0.2115621...,  0.1764301...])

    *CMCCAT2000* chromatic adaptation, requires extra *kwargs*:

    >>> XYZ = np.array([0.2248, 0.2274, 0.0854])
    >>> XYZ_w = np.array([1.1115, 1.0000, 0.3520])
    >>> XYZ_wr = np.array([0.9481, 1.0000, 1.0730])
    >>> L_A = 200
    >>> chromatic_adaptation(
    ...     XYZ, XYZ_w, XYZ_wr, method='CMCCAT2000', L_A1=L_A, L_A2=L_A)
    ... # doctest: +ELLIPSIS
    array([ 0.1952698...,  0.2306834...,  0.2497175...])

    *Fairchild (1990)* chromatic adaptation, requires extra *kwargs*:

    >>> XYZ = np.array([0.1953, 0.2307, 0.2497])
    >>> Y_n = 200
    >>> chromatic_adaptation(
    ...     XYZ, XYZ_w, XYZ_wr, method='Fairchild 1990', Y_n=Y_n)
    ... # doctest: +ELLIPSIS
    array([ 0.2332526...,  0.2332455...,  0.7611593...])

    *Zhai and Luo (2018)* chromatic adaptation:

    >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952])
    >>> XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775])
    >>> XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460])
    >>> chromatic_adaptation(XYZ, XYZ_w, XYZ_wr, method='Zhai 2018')
    ... # doctest: +ELLIPSIS
    array([ 0.2163881...,  0.1257    ,  0.0384749...])
    >>> chromatic_adaptation(
    ...     XYZ, XYZ_w, XYZ_wr, method='Zhai 2018', D_b=0.9,
    ...     XYZ_wo=np.array([100, 100, 100]))
    ... # doctest: +ELLIPSIS
    array([ 0.2152436...,  0.1253522...,  0.0388406...])
    """

    method = validate_method(method, CHROMATIC_ADAPTATION_METHODS)

    function = CHROMATIC_ADAPTATION_METHODS[method]

    domain_range_reference = get_domain_range_scale() == "reference"
    domain_100 = (
        chromatic_adaptation_CIE1994,
        chromatic_adaptation_CMCCAT2000,
        chromatic_adaptation_Fairchild1990,
        chromatic_adaptation_Zhai2018,
    )

    if function in domain_100 and domain_range_reference:
        XYZ = as_float_array(XYZ) * 100
        XYZ_w = as_float_array(XYZ_w) * 100
        XYZ_wr = as_float_array(XYZ_wr) * 100

        if "Y_o" in kwargs:
            kwargs["Y_o"] = kwargs["Y_o"] * 100

        if "XYZ_wo" in kwargs:
            kwargs["XYZ_wo"] = kwargs["XYZ_wo"] * 100

    kwargs.update({"XYZ_w": XYZ_w, "XYZ_wr": XYZ_wr})

    if function is chromatic_adaptation_CIE1994:
        from colour import XYZ_to_xy

        kwargs.update({"xy_o1": XYZ_to_xy(XYZ_w), "xy_o2": XYZ_to_xy(XYZ_wr)})
    elif function is chromatic_adaptation_Fairchild1990:
        kwargs.update({"XYZ_n": XYZ_w, "XYZ_r": XYZ_wr})
    elif function is chromatic_adaptation_Zhai2018:
        kwargs.update({"XYZ_wb": XYZ_w, "XYZ_wd": XYZ_wr})

    XYZ_c = function(XYZ, **filter_kwargs(function, **kwargs))

    if function in domain_100 and domain_range_reference:
        XYZ_c /= 100

    return XYZ_c
Exemple #17
0
def luminance(LV, method='CIE 1976', **kwargs):
    """
    Returns the *luminance* :math:`Y` of given *Lightness* :math:`L^*` or given
    *Munsell* value :math:`V`.

    Parameters
    ----------
    LV : numeric or array_like
        *Lightness* :math:`L^*` or *Munsell* value :math:`V`.
    method : unicode, optional
        **{'CIE 1976', 'Newhall 1943', 'ASTM D1535-08', 'Fairchild 2010',
        'Fairchild 2011'}**,
        Computation method.

    Other Parameters
    ----------------
    Y_n : numeric or array_like, optional
        {:func:`colour.colorimetry.luminance_CIE1976`},
        White reference *luminance* :math:`Y_n`.
    epsilon : numeric or array_like, optional
        {:func:`colour.colorimetry.lightness_Fairchild2010`,
        :func:`colour.colorimetry.lightness_Fairchild2011`},
        :math:`\\epsilon` exponent.

    Returns
    -------
    numeric or array_like
        *luminance* :math:`Y`.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``LV``     | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``Y``      | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`ASTMInternational2008a`, :cite:`CIETC1-482004m`,
    :cite:`Fairchild2010`, :cite:`Fairchild2011`, :cite:`Newhall1943a`,
    :cite:`Wikipedia2001b`, :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> luminance(41.527875844653451)  # doctest: +ELLIPSIS
    12.1972253...
    >>> luminance(41.527875844653451, Y_n=100)  # doctest: +ELLIPSIS
    12.1972253...
    >>> luminance(42.51993072812094, Y_n=95)  # doctest: +ELLIPSIS
    12.1972253...
    >>> luminance(4.08244375 * 10, method='Newhall 1943')
    ... # doctest: +ELLIPSIS
    12.5500788...
    >>> luminance(4.08244375 * 10, method='ASTM D1535-08')
    ... # doctest: +ELLIPSIS
    12.2363426...
    >>> luminance(29.829510892279330, epsilon=0.710, method='Fairchild 2011')
    ... # doctest: +ELLIPSIS
    12.1972253...
    """

    function = LUMINANCE_METHODS[method]

    domain_range_reference = get_domain_range_scale() == 'reference'
    domain_1 = (luminance_Fairchild2010, luminance_Fairchild2011)
    domain_10 = (luminance_Newhall1943, luminance_ASTMD153508)

    if function in domain_10 and domain_range_reference:
        LV /= 10

    Y_V = function(LV, **filter_kwargs(function, **kwargs))

    if function in domain_1 and domain_range_reference:
        Y_V *= 100

    return Y_V
Exemple #18
0
def whiteness(XYZ, XYZ_0, method='CIE 2004', **kwargs):
    """
    Returns the *whiteness* :math:`W` using given method.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of sample.
    XYZ_0 : array_like
        *CIE XYZ* tristimulus values of reference white.
    method : unicode, optional
        **{'CIE 2004', 'Berger 1959', 'Taube 1960', 'Stensby 1968',
        'ASTM E313', 'Ganz 1979'}**,
        Computation method.

    Other Parameters
    ----------------
    observer : unicode, optional
        {:func:`colour.colorimetry.whiteness_CIE2004`},
        **{'CIE 1931 2 Degree Standard Observer',
        'CIE 1964 10 Degree Standard Observer'}**,
        *CIE Standard Observer* used for computations, *tint* :math:`T` or
        :math:`T_{10}` value is dependent on viewing field angular subtense.

    Returns
    -------
    numeric or ndarray
        *whiteness* :math:`W`.

    Notes
    -----

    +------------+-----------------------+-----------------+
    | **Domain** | **Scale - Reference** |   **Scale - 1** |
    +============+=======================+=================+
    +------------+-----------------------+-----------------+
    | ``XYZ``    | [0, 100]              |   [0, 1]        |
    +------------+-----------------------+-----------------+
    | ``XYZ_0``  | [0, 100]              |   [0, 1]        |
    +------------+-----------------------+-----------------+

    +------------+-----------------------+-----------------+
    | **Range**  | **Scale - Reference** |   **Scale - 1** |
    +============+=======================+=================+
    | ``W``      | [0, 100]              |   [0, 1]        |
    +------------+-----------------------+-----------------+

    References
    ----------
    :cite:`CIETC1-482004k`, :cite:`Wyszecki2000ba`, :cite:`X-Rite2012a`,
    :cite:`Wikipedia2004b`

    Examples
    --------
    >>> import numpy as np
    >>> from colour.models import xyY_to_XYZ
    >>> XYZ = xyY_to_XYZ(np.array([0.3167, 0.3334, 100]))
    >>> XYZ_0 = xyY_to_XYZ(np.array([0.3139, 0.3311, 100]))
    >>> whiteness(XYZ, XYZ_0)  # doctest: +ELLIPSIS
    array([ 93.85...,  -1.305...])
    >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000])
    >>> XYZ_0 = np.array([94.80966767, 100.00000000, 107.30513595])
    >>> whiteness(XYZ, XYZ_0, method='Taube 1960')  # doctest: +ELLIPSIS
    91.4071738...
    """

    kwargs.update({'XYZ': XYZ, 'XYZ_0': XYZ_0})

    function = WHITENESS_METHODS.get(method)

    if function is whiteness_Stensby1968:
        from colour.models import XYZ_to_Lab, XYZ_to_xy

        if get_domain_range_scale() == 'reference':
            XYZ = XYZ / 100
            XYZ_0 = XYZ_0 / 100

        kwargs.update({'Lab': XYZ_to_Lab(XYZ, XYZ_to_xy(XYZ_0))})
    elif function in (whiteness_Ganz1979, whiteness_CIE2004):
        from colour.models import XYZ_to_xy

        _X_0, Y_0, _Z_0 = tsplit(XYZ_0)
        kwargs.update({
            'xy': XYZ_to_xy(XYZ),
            'Y': Y_0,
            'xy_n': XYZ_to_xy(XYZ_0)
        })

    return function(**filter_kwargs(function, **kwargs))
Exemple #19
0
def chromatic_adaptation(XYZ, XYZ_w, XYZ_wr, method='Von Kries', **kwargs):
    """
    Adapts given stimulus from test viewing conditions to reference viewing
    conditions.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of stimulus to adapt.
    XYZ_w : array_like
        Test viewing condition *CIE XYZ* tristimulus values of the whitepoint.
    XYZ_wr : array_like
        Reference viewing condition *CIE XYZ* tristimulus values of the
        whitepoint.
    method : unicode, optional
        **{'Von Kries', 'CIE 1994', 'CMCCAT2000', 'Fairchild 1990'}**,
        Computation method.

    Other Parameters
    ----------------
    E_o1 : numeric
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Test illuminance :math:`E_{o1}` in :math:`cd/m^2`.
    E_o2 : numeric
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Reference illuminance :math:`E_{o2}` in :math:`cd/m^2`.
    L_A1 : numeric or array_like
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        Luminance of test adapting field :math:`L_{A1}` in :math:`cd/m^2`.
    L_A2 : numeric or array_like
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        Luminance of reference adapting field :math:`L_{A2}` in :math:`cd/m^2`.
    Y_n : numeric or array_like
        {:func:`colour.adaptation.chromatic_adaptation_Fairchild1990`},
        Luminance :math:`Y_n` of test adapting stimulus in :math:`cd/m^2`.
    Y_o : numeric
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Luminance factor :math:`Y_o` of achromatic background normalised to
        domain [0.18, 1] in **'Reference'** domain-range scale.
    direction : unicode, optional
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        **{'Forward', 'Reverse'}**,
        Chromatic adaptation direction.
    discount_illuminant : bool, optional
        {:func:`colour.adaptation.chromatic_adaptation_Fairchild1990`},
        Truth value indicating if the illuminant should be discounted.
    n : numeric, optional
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Noise component in fundamental primary system.
    surround : CMCCAT2000_InductionFactors, optional
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        Surround viewing conditions induction factors.
    transform : unicode, optional
        {:func:`colour.adaptation.chromatic_adaptation_VonKries`},
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC'}**,
        Chromatic adaptation transform.

    Returns
    -------
    ndarray
        *CIE XYZ_c* tristimulus values of the stimulus corresponding colour.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``XYZ``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_w``  | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_wr`` | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``Y_o``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``XYZ_c``  | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`CIETC1-321994b`, :cite:`Fairchild1991a`, :cite:`Fairchild2013s`,
    :cite:`Fairchild2013t`, :cite:`Li2002a`, :cite:`Westland2012k`

    Examples
    --------

    *Von Kries* chromatic adaptation:

    >>> import numpy as np
    >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952])
    >>> XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775])
    >>> XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460])
    >>> chromatic_adaptation(XYZ, XYZ_w, XYZ_wr)
    ... # doctest: +ELLIPSIS
    array([ 0.2163881...,  0.1257    ,  0.0384749...])

    *CIE 1994* chromatic adaptation, requires extra *kwargs*:

    >>> XYZ = np.array([0.2800, 0.2126, 0.0527])
    >>> XYZ_w = np.array([1.09867452, 1.00000000, 0.35591556])
    >>> XYZ_wr = np.array([0.95045593, 1.00000000, 1.08905775])
    >>> Y_o = 0.20
    >>> E_o = 1000
    >>> chromatic_adaptation(
    ...     XYZ, XYZ_w, XYZ_wr, method='CIE 1994', Y_o=Y_o, E_o1=E_o, E_o2=E_o)
    ... # doctest: +ELLIPSIS
    array([ 0.2403379...,  0.2115621...,  0.1764301...])

    *CMCCAT2000* chromatic adaptation, requires extra *kwargs*:

    >>> XYZ = np.array([0.2248, 0.2274, 0.0854])
    >>> XYZ_w = np.array([1.1115, 1.0000, 0.3520])
    >>> XYZ_wr = np.array([0.9481, 1.0000, 1.0730])
    >>> L_A = 200
    >>> chromatic_adaptation(
    ...     XYZ, XYZ_w, XYZ_wr, method='CMCCAT2000', L_A1=L_A, L_A2=L_A)
    ... # doctest: +ELLIPSIS
    array([ 0.1952698...,  0.2306834...,  0.2497175...])

    *Fairchild (1990)* chromatic adaptation, requires extra *kwargs*:

    >>> XYZ = np.array([0.1953, 0.2307, 0.2497])
    >>> Y_n = 200
    >>> chromatic_adaptation(
    ...     XYZ, XYZ_w, XYZ_wr, method='Fairchild 1990', Y_n=Y_n)
    ... # doctest: +ELLIPSIS
    array([ 0.2332526...,  0.2332455...,  0.7611593...])
    """

    function = CHROMATIC_ADAPTATION_METHODS[method]

    domain_range_reference = get_domain_range_scale() == 'reference'
    domain_100 = (chromatic_adaptation_CIE1994,
                  chromatic_adaptation_CMCCAT2000,
                  chromatic_adaptation_Fairchild1990)

    if function in domain_100 and domain_range_reference:
        XYZ = as_float_array(XYZ) * 100
        XYZ_w = as_float_array(XYZ_w) * 100
        XYZ_wr = as_float_array(XYZ_wr) * 100
        if kwargs.get('Y_o'):
            kwargs['Y_o'] = kwargs['Y_o'] * 100

    kwargs.update({'XYZ_w': XYZ_w, 'XYZ_wr': XYZ_wr})

    if function is chromatic_adaptation_CIE1994:
        from colour import XYZ_to_xy

        kwargs.update({'xy_o1': XYZ_to_xy(XYZ_w), 'xy_o2': XYZ_to_xy(XYZ_wr)})

    elif function is chromatic_adaptation_Fairchild1990:
        kwargs.update({'XYZ_n': XYZ_w, 'XYZ_r': XYZ_wr})

    XYZ_c = function(XYZ, **filter_kwargs(function, **kwargs))

    if function in domain_100 and domain_range_reference:
        XYZ_c /= 100

    return XYZ_c
Exemple #20
0
def lightness(
    Y: FloatingOrArrayLike,
    method: Union[
        Literal[
            "Abebe 2017",
            "CIE 1976",
            "Glasser 1958",
            "Fairchild 2010",
            "Fairchild 2011",
            "Wyszecki 1963",
        ],
        str,
    ] = "CIE 1976",
    **kwargs: Any,
) -> FloatingOrNDArray:
    """
    Return the *Lightness* :math:`L` of given *luminance* :math:`Y` using
    given method.

    Parameters
    ----------
    Y
        *Luminance* :math:`Y`.
    method
        Computation method.

    Other Parameters
    ----------------
    Y_n
        {:func:`colour.colorimetry.lightness_Abebe2017`,
        :func:`colour.colorimetry.lightness_CIE1976`},
        White reference *luminance* :math:`Y_n`.
    epsilon
        {:func:`colour.colorimetry.lightness_Fairchild2010`,
        :func:`colour.colorimetry.lightness_Fairchild2011`},
        :math:`\\epsilon` exponent.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        *Lightness* :math:`L`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``Y``      | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L``      | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Abebe2017a`, :cite:`CIETC1-482004m`, :cite:`Fairchild2010`,
    :cite:`Fairchild2011`, :cite:`Glasser1958a`, :cite:`Wikipedia2007c`,
    :cite:`Wyszecki1963b`, :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> lightness(12.19722535)  # doctest: +ELLIPSIS
    41.5278758...
    >>> lightness(12.19722535, Y_n=100)  # doctest: +ELLIPSIS
    41.5278758...
    >>> lightness(12.19722535, Y_n=95)  # doctest: +ELLIPSIS
    42.5199307...
    >>> lightness(12.19722535, method='Glasser 1958')  # doctest: +ELLIPSIS
    39.8351264...
    >>> lightness(12.19722535, method='Wyszecki 1963')  # doctest: +ELLIPSIS
    40.5475745...
    >>> lightness(12.19722535, epsilon=0.710, method='Fairchild 2011')
    ... # doctest: +ELLIPSIS
    29.8295108...
    >>> lightness(12.19722535, epsilon=0.710, method='Fairchild 2011')
    ... # doctest: +ELLIPSIS
    29.8295108...
    >>> lightness(12.19722535, method='Abebe 2017')
    ... # doctest: +ELLIPSIS
    48.6955571...
    """

    Y = as_float_array(Y)
    method = validate_method(method, LIGHTNESS_METHODS)

    function = LIGHTNESS_METHODS[method]

    # NOTE: "Abebe et al. (2017)" uses absolute luminance levels and has
    # undefined domain-range scale, yet we modify its behaviour consistency
    # with the other methods.
    domain_range_reference = get_domain_range_scale() == "reference"
    domain_range_1 = get_domain_range_scale() == "1"
    domain_range_100 = get_domain_range_scale() == "100"

    domain_1 = (lightness_Fairchild2010, lightness_Fairchild2011)
    domain_undefined = (lightness_Abebe2017,)

    if function in domain_1 and domain_range_reference:
        Y = Y / 100

    if function in domain_undefined and domain_range_1:
        Y = Y * 100

    L = function(Y, **filter_kwargs(function, **kwargs))

    if function in domain_undefined and (
        domain_range_reference or domain_range_100
    ):
        L *= 100

    return L
Exemple #21
0
def luminance(
    LV: FloatingOrArrayLike,
    method: Union[Literal["Abebe 2017", "CIE 1976", "Glasser 1958",
                          "Fairchild 2010", "Fairchild 2011",
                          "Wyszecki 1963", ], str, ] = "CIE 1976",
    **kwargs: Any,
) -> FloatingOrNDArray:
    """
    Return the *luminance* :math:`Y` of given *Lightness* :math:`L^*` or given
    *Munsell* value :math:`V`.

    Parameters
    ----------
    LV
        *Lightness* :math:`L^*` or *Munsell* value :math:`V`.
    method
        Computation method.

    Other Parameters
    ----------------
    Y_n
        {:func:`colour.colorimetry.luminance_Abebe2017`,
        :func:`colour.colorimetry.luminance_CIE1976`},
        White reference *luminance* :math:`Y_n`.
    epsilon
        {:func:`colour.colorimetry.lightness_Fairchild2010`,
        :func:`colour.colorimetry.lightness_Fairchild2011`},
        :math:`\\epsilon` exponent.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        *Luminance* :math:`Y`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``LV``     | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``Y``      | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Abebe2017a`, :cite:`ASTMInternational2008a`, :cite:`CIETC1-482004m`,
    :cite:`Fairchild2010`, :cite:`Fairchild2011`, :cite:`Newhall1943a`,
    :cite:`Wikipedia2001b`, :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> luminance(41.527875844653451)  # doctest: +ELLIPSIS
    12.1972253...
    >>> luminance(41.527875844653451, Y_n=100)  # doctest: +ELLIPSIS
    12.1972253...
    >>> luminance(42.51993072812094, Y_n=95)  # doctest: +ELLIPSIS
    12.1972253...
    >>> luminance(4.08244375 * 10, method='Newhall 1943')
    ... # doctest: +ELLIPSIS
    12.5500788...
    >>> luminance(4.08244375 * 10, method='ASTM D1535')
    ... # doctest: +ELLIPSIS
    12.2363426...
    >>> luminance(29.829510892279330, epsilon=0.710, method='Fairchild 2011')
    ... # doctest: +ELLIPSIS
    12.1972253...
    """

    LV = as_float_array(LV)
    method = validate_method(method, LUMINANCE_METHODS)

    function = LUMINANCE_METHODS[method]

    # NOTE: "Abebe et al. (2017)" uses absolute luminance levels and has
    # undefined domain-range scale, yet we modify its behaviour consistency
    # with the other methods.
    domain_range_reference = get_domain_range_scale() == "reference"
    domain_range_1 = get_domain_range_scale() == "1"

    domain_1 = (luminance_Fairchild2010, luminance_Fairchild2011)
    domain_10 = (luminance_Newhall1943, luminance_ASTMD1535)
    domain_undefined = (luminance_Abebe2017, )

    if function in domain_10 and domain_range_reference:
        LV = LV / 10

    if function in domain_undefined and domain_range_1:
        LV = LV * 100

    Y_V = function(LV, **filter_kwargs(function, **kwargs))

    if function in domain_1 and domain_range_reference:
        Y_V *= 100

    if function in domain_undefined and domain_range_1:
        Y_V /= 100

    return Y_V
Exemple #22
0
def luminance(LV, method='CIE 1976', **kwargs):
    """
    Returns the *luminance* :math:`Y` of given *Lightness* :math:`L^*` or given
    *Munsell* value :math:`V`.

    Parameters
    ----------
    LV : numeric or array_like
        *Lightness* :math:`L^*` or *Munsell* value :math:`V`.
    method : unicode, optional
        **{'CIE 1976', 'Newhall 1943', 'ASTM D1535-08', 'Fairchild 2010',
        'Fairchild 2011'}**,
        Computation method.

    Other Parameters
    ----------------
    Y_n : numeric or array_like, optional
        {:func:`colour.colorimetry.luminance_CIE1976`},
        White reference *luminance* :math:`Y_n`.
    epsilon : numeric or array_like, optional
        {:func:`colour.colorimetry.lightness_Fairchild2010`,
        :func:`colour.colorimetry.lightness_Fairchild2011`},
        :math:`\\epsilon` exponent.

    Returns
    -------
    numeric or array_like
        *luminance* :math:`Y`.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``LV``     | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``Y``      | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`ASTMInternational2008a`, :cite:`Fairchild2010`,
    :cite:`Fairchild2011`, :cite:`Lindbloom2003d`, :cite:`Newhall1943a`,
    :cite:`Wikipedia2001b`, :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> luminance(41.527875844653451)  # doctest: +ELLIPSIS
    12.1972253...
    >>> luminance(41.527875844653451, Y_n=100)  # doctest: +ELLIPSIS
    12.1972253...
    >>> luminance(42.51993072812094, Y_n=95)  # doctest: +ELLIPSIS
    12.1972253...
    >>> luminance(4.08244375 * 10, method='Newhall 1943')
    ... # doctest: +ELLIPSIS
    12.5500788...
    >>> luminance(4.08244375 * 10, method='ASTM D1535-08')
    ... # doctest: +ELLIPSIS
    12.2363426...
    >>> luminance(29.829510892279330, epsilon=0.710, method='Fairchild 2011')
    ... # doctest: +ELLIPSIS
    12.1972253...
    """

    function = LUMINANCE_METHODS[method]

    domain_range_reference = get_domain_range_scale() == 'reference'
    domain_1 = (luminance_Fairchild2010, luminance_Fairchild2011)
    domain_10 = (luminance_Newhall1943, luminance_ASTMD153508)

    if function in domain_10 and domain_range_reference:
        LV /= 10

    Y_V = function(LV, **filter_kwargs(function, **kwargs))

    if function in domain_1 and domain_range_reference:
        Y_V *= 100

    return Y_V
Exemple #23
0
def multiprocessing_pool(*args: Any, **kwargs: Any) -> Generator:
    """
    Define a context manager providing a multiprocessing pool.

    Other Parameters
    ----------------
    args
        Arguments.
    kwargs
        Keywords arguments.

    Yields
    ------
    Generator
        Multiprocessing pool.

    Examples
    --------
    >>> from functools import partial
    >>> def _add(a, b):
    ...     return a + b
    >>> with multiprocessing_pool() as pool:
    ...     pool.map(partial(_add, b=2), range(10))
    ... # doctest: +SKIP
    [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
    """

    from colour.utilities import get_domain_range_scale

    class _DummyPool:
        """
        A dummy multiprocessing pool that does not perform multiprocessing.

        Other Parameters
        ----------------
        args
            Arguments.
        kwargs
            Keywords arguments.
        """
        def __init__(self, *args: Any, **kwargs: Any):
            pass

        def map(self, func, iterable, chunksize=None):
            """Apply given function to each element of given iterable."""

            return [func(a) for a in iterable]

        def terminate(self):
            """Terminate the process."""

            pass

    kwargs["initializer"] = _initializer
    kwargs["initargs"] = ({"scale": get_domain_range_scale()}, )

    pool_factory: Callable
    if _MULTIPROCESSING_ENABLED:
        pool_factory = multiprocessing.Pool
    else:
        pool_factory = _DummyPool

    pool = pool_factory(*args, **kwargs)

    try:
        yield pool
    finally:
        pool.terminate()
Exemple #24
0
    def test_domain_range_scale(self):
        """
        Tests :func:`colour.utilities.common.domain_range_scale`
        definition.
        """

        self.assertEqual(get_domain_range_scale(), 'reference')

        with domain_range_scale('Reference'):
            self.assertEqual(get_domain_range_scale(), 'reference')

        self.assertEqual(get_domain_range_scale(), 'reference')

        with domain_range_scale('1'):
            self.assertEqual(get_domain_range_scale(), '1')

        self.assertEqual(get_domain_range_scale(), 'reference')

        with domain_range_scale('100'):
            self.assertEqual(get_domain_range_scale(), '100')

        self.assertEqual(get_domain_range_scale(), 'reference')

        def _domain_range_change(a):
            """
            Helper definition performing domain-range scale.
            """

            b = to_domain_10(a)

            b *= 2

            return from_range_100(b)

        with domain_range_scale('Reference'):
            with domain_range_scale('1'):
                with domain_range_scale('100'):
                    with domain_range_scale('Ignore'):
                        self.assertEqual(get_domain_range_scale(), 'ignore')
                        self.assertEqual(_domain_range_change(4), 8)

                    self.assertEqual(get_domain_range_scale(), '100')
                    self.assertEqual(_domain_range_change(40), 8)

                self.assertEqual(get_domain_range_scale(), '1')
                self.assertEqual(_domain_range_change(0.4), 0.08)

            self.assertEqual(get_domain_range_scale(), 'reference')
            self.assertEqual(_domain_range_change(4), 8)

        self.assertEqual(get_domain_range_scale(), 'reference')
Exemple #25
0
    def test_domain_range_scale(self):
        """
        Test :func:`colour.utilities.common.domain_range_scale`
        definition.
        """

        self.assertEqual(get_domain_range_scale(), "reference")

        with domain_range_scale("Reference"):
            self.assertEqual(get_domain_range_scale(), "reference")

        self.assertEqual(get_domain_range_scale(), "reference")

        with domain_range_scale("1"):
            self.assertEqual(get_domain_range_scale(), "1")

        self.assertEqual(get_domain_range_scale(), "reference")

        with domain_range_scale("100"):
            self.assertEqual(get_domain_range_scale(), "100")

        self.assertEqual(get_domain_range_scale(), "reference")

        def fn_a(a):
            """Change the domain-range scale for unit testing."""

            b = to_domain_10(a)

            b *= 2

            return from_range_100(b)

        with domain_range_scale("Reference"):
            with domain_range_scale("1"):
                with domain_range_scale("100"):
                    with domain_range_scale("Ignore"):
                        self.assertEqual(get_domain_range_scale(), "ignore")
                        self.assertEqual(fn_a(4), 8)

                    self.assertEqual(get_domain_range_scale(), "100")
                    self.assertEqual(fn_a(40), 8)

                self.assertEqual(get_domain_range_scale(), "1")
                self.assertEqual(fn_a(0.4), 0.08)

            self.assertEqual(get_domain_range_scale(), "reference")
            self.assertEqual(fn_a(4), 8)

        self.assertEqual(get_domain_range_scale(), "reference")

        @domain_range_scale("1")
        def fn_b(a):
            """Change the domain-range scale for unit testing."""

            b = to_domain_10(a)

            b *= 2

            return from_range_100(b)

        self.assertEqual(fn_b(10), 2.0)
Exemple #26
0
    def test_domain_range_scale(self):
        """
        Tests :func:`colour.utilities.common.domain_range_scale`
        definition.
        """

        self.assertEqual(get_domain_range_scale(), 'reference')

        with domain_range_scale('Reference'):
            self.assertEqual(get_domain_range_scale(), 'reference')

        self.assertEqual(get_domain_range_scale(), 'reference')

        with domain_range_scale('1'):
            self.assertEqual(get_domain_range_scale(), '1')

        self.assertEqual(get_domain_range_scale(), 'reference')

        with domain_range_scale('100'):
            self.assertEqual(get_domain_range_scale(), '100')

        self.assertEqual(get_domain_range_scale(), 'reference')

        def fn_a(a):
            """
            Helper definition performing domain-range scale.
            """

            b = to_domain_10(a)

            b *= 2

            return from_range_100(b)

        with domain_range_scale('Reference'):
            with domain_range_scale('1'):
                with domain_range_scale('100'):
                    with domain_range_scale('Ignore'):
                        self.assertEqual(get_domain_range_scale(), 'ignore')
                        self.assertEqual(fn_a(4), 8)

                    self.assertEqual(get_domain_range_scale(), '100')
                    self.assertEqual(fn_a(40), 8)

                self.assertEqual(get_domain_range_scale(), '1')
                self.assertEqual(fn_a(0.4), 0.08)

            self.assertEqual(get_domain_range_scale(), 'reference')
            self.assertEqual(fn_a(4), 8)

        self.assertEqual(get_domain_range_scale(), 'reference')

        @domain_range_scale(1)
        def fn_b(a):
            """
            Helper definition performing domain-range scale.
            """

            b = to_domain_10(a)

            b *= 2

            return from_range_100(b)

        self.assertEqual(fn_b(10), 2.0)
Exemple #27
0
def delta_E_DIN99(Lab_1: ArrayLike,
                  Lab_2: ArrayLike,
                  textiles: Boolean = False) -> FloatingOrNDArray:
    """
    Return the difference :math:`\\Delta E_{DIN99}` between two given
    *CIE L\\*a\\*b\\** colourspace arrays using *DIN99* formula.

    Parameters
    ----------
    Lab_1
        *CIE L\\*a\\*b\\** colourspace array 1.
    Lab_2
        *CIE L\\*a\\*b\\** colourspace array 2.
    textiles
        Textiles application specific parametric factors,
        :math:`k_E=2,\\ k_{CH}=0.5` weights are used instead of
        :math:`k_E=1,\\ k_{CH}=1`.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Colour difference :math:`\\Delta E_{DIN99}`.

    Notes
    -----
    +------------+-----------------------+-------------------+
    | **Domain** | **Scale - Reference** | **Scale - 1**     |
    +============+=======================+===================+
    | ``Lab_1``  | ``L_1`` : [0, 100]    | ``L_1`` : [0, 1]  |
    |            |                       |                   |
    |            | ``a_1`` : [-100, 100] | ``a_1`` : [-1, 1] |
    |            |                       |                   |
    |            | ``b_1`` : [-100, 100] | ``b_1`` : [-1, 1] |
    +------------+-----------------------+-------------------+
    | ``Lab_2``  | ``L_2`` : [0, 100]    | ``L_2`` : [0, 1]  |
    |            |                       |                   |
    |            | ``a_2`` : [-100, 100] | ``a_2`` : [-1, 1] |
    |            |                       |                   |
    |            | ``b_2`` : [-100, 100] | ``b_2`` : [-1, 1] |
    +------------+-----------------------+-------------------+

    References
    ----------
    :cite:`ASTMInternational2007`

    Examples
    --------
    >>> import numpy as np
    >>> Lab_1 = np.array([60.2574, -34.0099, 36.2677])
    >>> Lab_2 = np.array([60.4626, -34.1751, 39.4387])
    >>> delta_E_DIN99(Lab_1, Lab_2)  # doctest: +ELLIPSIS
    1.1772166...
    """

    k_E = 2 if textiles else 1
    k_CH = 0.5 if textiles else 1

    factor = 100 if get_domain_range_scale() == "1" else 1

    d_E = euclidean_distance(
        Lab_to_DIN99(Lab_1, k_E, k_CH) * factor,
        Lab_to_DIN99(Lab_2, k_E, k_CH) * factor,
    )

    return d_E