Exemple #1
0
def excitation_purity(xy,
                      xy_n,
                      cmfs=CMFS['CIE 1931 2 Degree Standard Observer']):
    """
    Returns the *excitation purity* :math:`P_e` for given colour stimulus
    :math:`xy`.

    Parameters
    ----------
    xy : array_like
        Colour stimulus *xy* chromaticity coordinates.
    xy_n : array_like
        Achromatic stimulus *xy* chromaticity coordinates.
    cmfs : XYZ_ColourMatchingFunctions, optional
        Standard observer colour matching functions.

    Returns
    -------
    numeric or array_like
        *Excitation purity* :math:`P_e`.

    Examples
    --------
    >>> xy = np.array([0.28350, 0.68700])
    >>> xy_n = np.array([0.31270, 0.32900])
    >>> cmfs = CMFS['CIE 1931 2 Degree Standard Observer']
    >>> excitation_purity(xy, xy_n, cmfs)  # doctest: +ELLIPSIS
    0.9386035...
    """

    wl, xy_wl, xy_cwl = dominant_wavelength(xy, xy_n, cmfs)

    P_e = euclidean_distance(xy_n, xy) / euclidean_distance(xy_n, xy_wl)

    return P_e
Exemple #2
0
    def test_euclidean_distance(self):
        """
        Tests :func:`colour.algebra.geometry.euclidean_distance` definition.
        """

        self.assertAlmostEqual(
            euclidean_distance(
                np.array([100.00000000, 21.57210357, 272.22819350]),
                np.array([100.00000000, 426.67945353, 72.39590835])),
            451.71330197,
            places=7)

        self.assertAlmostEqual(
            euclidean_distance(
                np.array([100.00000000, 21.57210357, 272.22819350]),
                np.array([100.00000000, 74.05216981, 276.45318193])),
            52.64986116,
            places=7)

        self.assertAlmostEqual(
            euclidean_distance(
                np.array([100.00000000, 21.57210357, 272.22819350]),
                np.array([100.00000000, 8.32281957, -73.58297716])),
            346.06489172,
            places=7)
Exemple #3
0
    def test_euclidean_distance(self):
        """
        Tests :func:`colour.algebra.geometry.euclidean_distance` definition.
        """

        self.assertAlmostEqual(
            euclidean_distance(
                np.array([100.00000000, 21.57210357, 272.22819350]),
                np.array([100.00000000, 426.67945353, 72.39590835])),
            451.71330197,
            places=7)

        self.assertAlmostEqual(
            euclidean_distance(
                np.array([100.00000000, 21.57210357, 272.22819350]),
                np.array([100.00000000, 74.05216981, 276.45318193])),
            52.64986116,
            places=7)

        self.assertAlmostEqual(
            euclidean_distance(
                np.array([100.00000000, 21.57210357, 272.22819350]),
                np.array([100.00000000, 8.32281957, -73.58297716])),
            346.06489172,
            places=7)
Exemple #4
0
    def test_n_dimensional_euclidean_distance(self):
        """
        Tests :func:`colour.algebra.geometry.euclidean_distance` definition
        n-dimensional arrays support.
        """

        a = np.array([100.00000000, 21.57210357, 272.22819350])
        b = np.array([100.00000000, 426.67945353, 72.39590835])
        distance = 451.71330197
        np.testing.assert_almost_equal(
            euclidean_distance(a, b),
            distance,
            decimal=7)

        a = np.tile(a, (6, 1))
        b = np.tile(b, (6, 1))
        distance = np.tile(distance, 6)
        np.testing.assert_almost_equal(
            euclidean_distance(a, b),
            distance,
            decimal=7)

        a = np.reshape(a, (2, 3, 3))
        b = np.reshape(b, (2, 3, 3))
        distance = np.reshape(distance, (2, 3))
        np.testing.assert_almost_equal(
            euclidean_distance(a, b),
            distance,
            decimal=7)
Exemple #5
0
    def test_n_dimensional_euclidean_distance(self):
        """
        Tests :func:`colour.algebra.geometry.euclidean_distance` definition
        n-dimensional arrays support.
        """

        a = np.array([100.00000000, 21.57210357, 272.22819350])
        b = np.array([100.00000000, 426.67945353, 72.39590835])
        distance = 451.71330197
        np.testing.assert_almost_equal(euclidean_distance(a, b),
                                       distance,
                                       decimal=7)

        a = np.tile(a, (6, 1))
        b = np.tile(b, (6, 1))
        distance = np.tile(distance, 6)
        np.testing.assert_almost_equal(euclidean_distance(a, b),
                                       distance,
                                       decimal=7)

        a = np.reshape(a, (2, 3, 3))
        b = np.reshape(b, (2, 3, 3))
        distance = np.reshape(distance, (2, 3))
        np.testing.assert_almost_equal(euclidean_distance(a, b),
                                       distance,
                                       decimal=7)
Exemple #6
0
    def test_nan_euclidean_distance(self):
        """
        Tests :func:`colour.algebra.geometry.euclidean_distance` definition nan
        support.
        """

        cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]
        cases = set(permutations(cases * 3, r=3))
        for case in cases:
            a = np.array(case)
            b = np.array(case)
            euclidean_distance(a, b)
Exemple #7
0
    def test_nan_euclidean_distance(self):
        """
        Tests :func:`colour.algebra.geometry.euclidean_distance` definition nan
        support.
        """

        cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]
        cases = set(permutations(cases * 3, r=3))
        for case in cases:
            a = np.array(case)
            b = np.array(case)
            euclidean_distance(a, b)
Exemple #8
0
def colour_quality_scales(test_data, reference_data, CCT_f):
    """
    Returns the *VS test colour samples* rendering scales.

    Parameters
    ----------
    test_data : list
        Test data.
    reference_data : list
        Reference data.
    CCT_f : numeric
        Factor penalizing lamps with extremely low correlated colour
        temperatures.

    Returns
    -------
    dict
        *VS Test colour samples* colour rendering scales.
    """

    Q_as = {}
    for i, _ in enumerate(test_data):
        D_C_ab = test_data[i].C - reference_data[i].C
        D_E_ab = euclidean_distance(test_data[i].Lab, reference_data[i].Lab)

        if D_C_ab > 0:
            D_Ep_ab = np.sqrt(D_E_ab**2 - D_C_ab**2)
        else:
            D_Ep_ab = D_E_ab

        Q_a = scale_conversion(D_Ep_ab, CCT_f)

        Q_as[i + 1] = VS_ColourQualityScaleData(test_data[i].name, Q_a, D_C_ab,
                                                D_E_ab, D_Ep_ab)
    return Q_as
Exemple #9
0
def delta_E_CIE1976(Lab_1, Lab_2):
    """
    Returns the difference :math:`\Delta E_{ab}` between two given
    *CIE L\*a\*b\** colourspace arrays using *CIE 1976* recommendation.

    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_{ab}`.

    References
    ----------
    -   :cite:`Lindbloom2003c`

    Examples
    --------
    >>> Lab_1 = np.array([100.00000000, 21.57210357, 272.22819350])
    >>> Lab_2 = np.array([100.00000000, 426.67945353, 72.39590835])
    >>> delta_E_CIE1976(Lab_1, Lab_2)  # doctest: +ELLIPSIS
    451.7133019...
    """

    d_E = euclidean_distance(Lab_1, Lab_2)

    return d_E
Exemple #10
0
def colour_rendering_indexes(
    test_data: Tuple[TCS_ColorimetryData, ...],
    reference_data: Tuple[TCS_ColorimetryData, ...],
) -> Dict[Integer, TCS_ColourQualityScaleData]:
    """
    Return the *test colour samples* rendering indexes :math:`Q_a`.

    Parameters
    ----------
    test_data
        Test data.
    reference_data
        Reference data.

    Returns
    -------
    :class:`dict`
        *Test colour samples* *Colour Rendering Index* (CRI).
    """

    Q_as = {}
    for i in range(len(test_data)):
        Q_as[i + 1] = TCS_ColourQualityScaleData(
            test_data[i].name,
            100
            - 4.6
            * as_float_scalar(
                euclidean_distance(reference_data[i].UVW, test_data[i].UVW)
            ),
        )

    return Q_as
Exemple #11
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 #12
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 #13
0
def excitation_purity(
    xy: ArrayLike,
    xy_n: ArrayLike,
    cmfs: Optional[MultiSpectralDistributions] = None,
) -> FloatingOrNDArray:
    """
    Return the *excitation purity* :math:`P_e` for given colour stimulus
    :math:`xy`.

    Parameters
    ----------
    xy
        Colour stimulus *CIE xy* chromaticity coordinates.
    xy_n
        Achromatic stimulus *CIE xy* chromaticity coordinates.
    cmfs
        Standard observer colour matching functions, default to the
        *CIE 1931 2 Degree Standard Observer*.

    Returns
    -------
    :class:`np.floating` or :class:`numpy.ndarray`
        *Excitation purity* :math:`P_e`.

    References
    ----------
    :cite:`CIETC1-482004o`, :cite:`Erdogana`

    Examples
    --------
    >>> from colour.colorimetry import MSDS_CMFS
    >>> cmfs = MSDS_CMFS['CIE 1931 2 Degree Standard Observer']
    >>> xy = np.array([0.54369557, 0.32107944])
    >>> xy_n = np.array([0.31270000, 0.32900000])
    >>> excitation_purity(xy, xy_n, cmfs)  # doctest: +ELLIPSIS
    0.6228856...
    """

    _wl, xy_wl, _xy_cwl = dominant_wavelength(xy, xy_n, cmfs)

    P_e = euclidean_distance(xy_n, xy) / euclidean_distance(xy_n, xy_wl)

    return P_e
Exemple #14
0
    def objective_function(M: ArrayLike, RGB: ArrayLike,
                           Jab: ArrayLike) -> FloatingOrNDArray:
        """:math:`J_za_zb_z` colourspace based objective function."""

        M = np.reshape(M, [3, 3])

        XYZ_t = vector_dot(RGB_COLOURSPACE_ACES2065_1.matrix_RGB_to_XYZ,
                           vector_dot(M, RGB))
        Jab_t = XYZ_to_Jzazbz(XYZ_t)

        return np.sum(euclidean_distance(Jab, Jab_t))
Exemple #15
0
    def objective_function(M, RGB, Jab):
        """
        :math:`J_zA_zB_z` colourspace based objective function.
        """

        M = np.reshape(M, [3, 3])

        XYZ_t = vector_dot(RGB_COLOURSPACE_ACES2065_1.matrix_RGB_to_XYZ,
                           vector_dot(M, RGB))
        Jab_t = XYZ_to_JzAzBz(XYZ_t)

        return np.sum(euclidean_distance(Jab, Jab_t))
Exemple #16
0
    def test_delta_E_CIE1976(self):
        """
        Tests :func:`colour.difference.delta_e.delta_E_CIE1976` definition.
        """

        Lab_1 = np.array([100.00000000, 21.57210357, 272.22819350])
        Lab_2 = np.array([100.00000000, 426.67945353, 72.39590835])
        Lab_1 = np.tile(Lab_1, (6, 1)).reshape((2, 3, 3))
        Lab_2 = np.tile(Lab_2, (6, 1)).reshape((2, 3, 3))

        np.testing.assert_almost_equal(delta_E_CIE1976(Lab_1, Lab_2),
                                       euclidean_distance(Lab_1, Lab_2),
                                       decimal=7)
Exemple #17
0
def excitation_purity(xy,
                      xy_n,
                      cmfs=CMFS['CIE 1931 2 Degree Standard Observer']):
    """
    Returns the *excitation purity* :math:`P_e` for given colour stimulus
    :math:`xy`.

    Parameters
    ----------
    xy : array_like
        Colour stimulus *CIE xy* chromaticity coordinates.
    xy_n : array_like
        Achromatic stimulus *CIE xy* chromaticity coordinates.
    cmfs : XYZ_ColourMatchingFunctions, optional
        Standard observer colour matching functions.

    Returns
    -------
    numeric or array_like
        *Excitation purity* :math:`P_e`.

    References
    ----------
    :cite:`CIETC1-482004o`, :cite:`Erdogana`

    Examples
    --------
    >>> xy = np.array([0.54369557, 0.32107944])
    >>> xy_n = np.array([0.31270000, 0.32900000])
    >>> cmfs = CMFS['CIE 1931 2 Degree Standard Observer']
    >>> excitation_purity(xy, xy_n, cmfs)  # doctest: +ELLIPSIS
    0.6228856...
    """

    _wl, xy_wl, _xy_cwl = dominant_wavelength(xy, xy_n, cmfs)

    P_e = euclidean_distance(xy_n, xy) / euclidean_distance(xy_n, xy_wl)

    return P_e
Exemple #18
0
def delta_E_CIE1976(Lab_1, Lab_2):
    """
    Returns the difference :math:`\\Delta E_{76}` between two given
    *CIE L\\*a\\*b\\** colourspace arrays using *CIE 1976* recommendation.

    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_{76}`.

    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:`Lindbloom2003c`

    Examples
    --------
    >>> Lab_1 = np.array([100.00000000, 21.57210357, 272.22819350])
    >>> Lab_2 = np.array([100.00000000, 426.67945353, 72.39590835])
    >>> delta_E_CIE1976(Lab_1, Lab_2)  # doctest: +ELLIPSIS
    451.7133019...
    """

    d_E = euclidean_distance(to_domain_100(Lab_1), to_domain_100(Lab_2))

    return d_E
Exemple #19
0
def delta_E_CIE1976(Lab_1, Lab_2):
    """
    Returns the difference :math:`\\Delta E_{76}` between two given
    *CIE L\\*a\\*b\\** colourspace arrays using *CIE 1976* recommendation.

    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_{76}`.

    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:`Lindbloom2003c`

    Examples
    --------
    >>> Lab_1 = np.array([100.00000000, 21.57210357, 272.22819350])
    >>> Lab_2 = np.array([100.00000000, 426.67945353, 72.39590835])
    >>> delta_E_CIE1976(Lab_1, Lab_2)  # doctest: +ELLIPSIS
    451.7133019...
    """

    d_E = euclidean_distance(to_domain_100(Lab_1), to_domain_100(Lab_2))

    return d_E
Exemple #20
0
    def test_delta_E_CIE1976(self):
        """
        Tests :func:`colour.difference.delta_e.delta_E_CIE1976` definition.
        """

        Lab_1 = np.array([100.00000000, 21.57210357, 272.22819350])
        Lab_2 = np.array([100.00000000, 426.67945353, 72.39590835])
        Lab_1 = np.tile(Lab_1, (6, 1)).reshape([2, 3, 3])
        Lab_2 = np.tile(Lab_2, (6, 1)).reshape([2, 3, 3])

        np.testing.assert_almost_equal(
            delta_E_CIE1976(Lab_1, Lab_2),
            euclidean_distance(Lab_1, Lab_2),
            decimal=7)
Exemple #21
0
    def test_domain_range_scale_delta_E_CIE1976(self):
        """
        Tests :func:`colour.difference.delta_e.delta_E_CIE1976` definition
        domain and range scale support.
        """

        Lab_1 = np.array([100.00000000, 21.57210357, 272.22819350])
        Lab_2 = np.array([100.00000000, 426.67945353, 72.39590835])

        d_r = (('reference', 1), (1, 0.01), (100, 1))
        for scale, factor in d_r:
            with domain_range_scale(scale):
                np.testing.assert_almost_equal(
                    delta_E_CIE1976(Lab_1 * factor, Lab_2 * factor),
                    euclidean_distance(Lab_1, Lab_2),
                    decimal=7)
Exemple #22
0
    def test_domain_range_scale_delta_E_CIE1976(self):
        """
        Tests :func:`colour.difference.delta_e.delta_E_CIE1976` definition
        domain and range scale support.
        """

        Lab_1 = np.array([100.00000000, 21.57210357, 272.22819350])
        Lab_2 = np.array([100.00000000, 426.67945353, 72.39590835])

        d_r = (('reference', 1), (1, 0.01), (100, 1))
        for scale, factor in d_r:
            with domain_range_scale(scale):
                np.testing.assert_almost_equal(
                    delta_E_CIE1976(Lab_1 * factor, Lab_2 * factor),
                    euclidean_distance(Lab_1, Lab_2),
                    decimal=7)
def colour_quality_scales(test_data, reference_data, CCT_f):

    Q_as = {}
    from colour.algebra import euclidean_distance
    for i, _ in enumerate(test_data):
        D_C_ab = test_data[i].C - reference_data[i].C
        D_E_ab = euclidean_distance(test_data[i].Lab, reference_data[i].Lab)

        if D_C_ab > 0:
            D_Ep_ab = np.sqrt(D_E_ab**2 - D_C_ab**2)
        else:
            D_Ep_ab = D_E_ab

        Q_a = scale_conversion(D_Ep_ab, CCT_f)

        Q_as[i + 1] = VS_ColourQualityScaleData(test_data[i].name, Q_a, D_C_ab,
                                                D_E_ab, D_Ep_ab)
    return Q_as
Exemple #24
0
def colour_quality_scales(
    test_data: Tuple[VS_ColorimetryData, ...],
    reference_data: Tuple[VS_ColorimetryData, ...],
    scaling_f: Floating,
    CCT_f: Floating,
) -> Dict[Integer, VS_ColourQualityScaleData]:
    """
    Return the *VS test colour samples* rendering scales.

    Parameters
    ----------
    test_data
        Test data.
    reference_data
        Reference data.
    scaling_f
        Scaling factor constant.
    CCT_f
        Factor penalizing lamps with extremely low correlated colour
        temperatures.

    Returns
    -------
    :class:`dict`
        *VS Test colour samples* colour rendering scales.
    """

    Q_as = {}
    for i in range(len(test_data)):
        D_C_ab = test_data[i].C - reference_data[i].C
        D_E_ab = as_float_scalar(
            euclidean_distance(test_data[i].Lab, reference_data[i].Lab))

        if D_C_ab > 0:
            D_Ep_ab = np.sqrt(D_E_ab**2 - D_C_ab**2)
        else:
            D_Ep_ab = D_E_ab

        Q_a = scale_conversion(D_Ep_ab, CCT_f, scaling_f)

        Q_as[i + 1] = VS_ColourQualityScaleData(test_data[i].name, Q_a, D_C_ab,
                                                D_E_ab, D_Ep_ab)
    return Q_as
Exemple #25
0
def colour_rendering_indexes(test_data, reference_data):
    """
    Returns the *test colour samples* rendering indexes :math:`Q_a`.

    Parameters
    ----------
    test_data : list
        Test data.
    reference_data : list
        Reference data.

    Returns
    -------
    dict
        *Test colour samples* *Colour Rendering Index* (CRI).
    """

    Q_as = {}
    for i, _ in enumerate(test_data):
        Q_as[i + 1] = TCS_ColourQualityScaleData(
            test_data[i].name, 100 -
            4.6 * euclidean_distance(reference_data[i].UVW, test_data[i].UVW))
    return Q_as
Exemple #26
0
def colour_rendering_indexes(test_data, reference_data):
    """
    Returns the *test colour samples* rendering indexes :math:`Q_a`.

    Parameters
    ----------
    test_data : list
        Test data.
    reference_data : list
        Reference data.

    Returns
    -------
    dict
        *Test colour samples* *Colour Rendering Index* (CRI).
    """

    Q_as = {}
    for i, _ in enumerate(test_data):
        Q_as[i + 1] = TCS_ColourQualityScaleData(
            test_data[i].name, 100 -
            4.6 * euclidean_distance(reference_data[i].UVW, test_data[i].UVW))
    return Q_as
Exemple #27
0
def delta_E_CIE1976(Lab_1, Lab_2):
    """
    Returns the difference :math:`\Delta E_{ab}` between two given
    *CIE Lab* colourspace arrays using CIE 1976 recommendation.

    Parameters
    ----------
    Lab_1 : array_like
        *CIE Lab* colourspace array 1.
    Lab_2 : array_like
        *CIE Lab* colourspace array 2.

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

    See Also
    --------
    colour.euclidean_distance

    References
    ----------
    .. [2]  Lindbloom, B. (2003). Delta E (CIE 1976). Retrieved February 24,
            2014, from http://brucelindbloom.com/Eqn_DeltaE_CIE76.html

    Examples
    --------
    >>> Lab_1 = np.array([100.00000000, 21.57210357, 272.22819350])
    >>> Lab_2 = np.array([100.00000000, 426.67945353, 72.39590835])
    >>> delta_E_CIE1976(Lab_1, Lab_2)  # doctest: +ELLIPSIS
    451.7133019...
    """

    d_E = euclidean_distance(Lab_1, Lab_2)

    return d_E
Exemple #28
0
def delta_E_CIE1976(Lab_1, Lab_2):
    """
    Returns the difference :math:`\Delta E_{ab}` between two given
    *CIE Lab* colourspace arrays using CIE 1976 recommendation.

    Parameters
    ----------
    Lab_1 : array_like
        *CIE Lab* colourspace array 1.
    Lab_2 : array_like
        *CIE Lab* colourspace array 2.

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

    See Also
    --------
    colour.euclidean_distance

    References
    ----------
    .. [2]  Lindbloom, B. (2003). Delta E (CIE 1976). Retrieved February 24,
            2014, from http://brucelindbloom.com/Eqn_DeltaE_CIE76.html

    Examples
    --------
    >>> Lab_1 = np.array([100.00000000, 21.57210357, 272.22819350])
    >>> Lab_2 = np.array([100.00000000, 426.67945353, 72.39590835])
    >>> delta_E_CIE1976(Lab_1, Lab_2)  # doctest: +ELLIPSIS
    451.7133019...
    """

    d_E = euclidean_distance(Lab_1, Lab_2)

    return d_E
Exemple #29
0
def colour_quality_scales(test_data, reference_data, scaling_f, CCT_f):
    """
    Returns the *VS test colour samples* rendering scales.

    Parameters
    ----------
    test_data : list
        Test data.
    reference_data : list
        Reference data.
    scaling_f : numeric, optional
        Scaling factor constant.
    CCT_f : numeric
        Factor penalizing lamps with extremely low correlated colour
        temperatures.

    Returns
    -------
    dict
        *VS Test colour samples* colour rendering scales.
    """

    Q_as = {}
    for i, _ in enumerate(test_data):
        D_C_ab = test_data[i].C - reference_data[i].C
        D_E_ab = euclidean_distance(test_data[i].Lab, reference_data[i].Lab)

        if D_C_ab > 0:
            D_Ep_ab = np.sqrt(D_E_ab ** 2 - D_C_ab ** 2)
        else:
            D_Ep_ab = D_E_ab

        Q_a = scale_conversion(D_Ep_ab, scaling_f, CCT_f)

        Q_as[i + 1] = VS_ColourQualityScaleData(test_data[i].name, Q_a, D_C_ab,
                                                D_E_ab, D_Ep_ab)
    return Q_as
Exemple #30
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
Exemple #31
0
def colour_fidelity_index_CIE2017(sd_test, additional_data=False):
    """
    Returns the *CIE 2017 Colour Fidelity Index* (CFI) :math:`R_f` of given
    spectral distribution.

    Parameters
    ----------
    sd_test : SpectralDistribution
        Test spectral distribution.
    additional_data : bool, optional
        Whether to output additional data.

    Returns
    -------
    numeric or ColourRendering_Specification_CIE2017
        *CIE 2017 Colour Fidelity Index* (CFI) :math:`R_f`.

    References
    ----------
    :cite:`CIETC1-902017`

    Examples
    --------
    >>> from colour.colorimetry import SDS_ILLUMINANTS
    >>> sd = SDS_ILLUMINANTS['FL2']
    >>> colour_fidelity_index_CIE2017(sd)  # doctest: +ELLIPSIS
    70.1208254...
    """

    if sd_test.shape.start > 380 or sd_test.shape.end < 780:
        usage_warning('Test spectral distribution shape does not span the'
                      'recommended 380-780nm range, missing values will be'
                      'filled with zeros!')

        # NOTE: "CIE 2017 Colour Fidelity Index" standard recommends filling
        # missing values with zeros.
        sd_test = sd_test.copy()
        sd_test.extrapolator = Extrapolator
        sd_test.extrapolator_kwargs = {
            'method': 'constant',
            'left': 0,
            'right': 0
        }

    if sd_test.shape.interval > 5:
        raise ValueError('Test spectral distribution interval is greater than'
                         '5nm which is the maximum recommended value '
                         'for computing the "CIE 2017 Colour Fidelity Index"!')

    shape = SpectralShape(SPECTRAL_SHAPE_CIE2017.start,
                          SPECTRAL_SHAPE_CIE2017.end, sd_test.shape.interval)

    CCT, D_uv = CCT_reference_illuminant(sd_test)
    sd_reference = sd_reference_illuminant(CCT, shape)

    # NOTE: All computations except CCT calculation use the
    # "CIE 1964 10 Degree Standard Observer".
    cmfs_10 = MSDS_CMFS['CIE 1964 10 Degree Standard Observer'].copy().align(
        shape)

    sds_tcs = load_TCS_CIE2017(shape).align(shape)

    test_tcs_colorimetry_data = tcs_colorimetry_data(sd_test, sds_tcs, cmfs_10)
    reference_tcs_colorimetry_data = tcs_colorimetry_data(
        sd_reference, sds_tcs, cmfs_10)

    delta_E_s = np.empty(len(sds_tcs.labels))
    for i, _delta_E in enumerate(delta_E_s):
        delta_E_s[i] = euclidean_distance(
            test_tcs_colorimetry_data[i].Jpapbp,
            reference_tcs_colorimetry_data[i].Jpapbp)

    R_s = delta_E_to_R_f(delta_E_s)
    R_f = delta_E_to_R_f(np.average(delta_E_s))

    if additional_data:
        return ColourRendering_Specification_CIE2017(
            sd_test.name, sd_reference, R_f, R_s, CCT, D_uv,
            (test_tcs_colorimetry_data, reference_tcs_colorimetry_data),
            delta_E_s)
    else:
        return R_f
Exemple #32
0
def colour_fidelity_index_CIE2017(
    sd_test: SpectralDistribution,
    additional_data: Boolean = False
) -> Union[Floating, ColourRendering_Specification_CIE2017]:
    """
    Return the *CIE 2017 Colour Fidelity Index* (CFI) :math:`R_f` of given
    spectral distribution.

    Parameters
    ----------
    sd_test
        Test spectral distribution.
    additional_data
        Whether to output additional data.

    Returns
    -------
    :class:`numpy.floating` or \
:class:`colour.quality.ColourRendering_Specification_CIE2017`
        *CIE 2017 Colour Fidelity Index* (CFI) :math:`R_f`.

    References
    ----------
    :cite:`CIETC1-902017`

    Examples
    --------
    >>> from colour.colorimetry import SDS_ILLUMINANTS
    >>> sd = SDS_ILLUMINANTS['FL2']
    >>> colour_fidelity_index_CIE2017(sd)  # doctest: +ELLIPSIS
    70.1208254...
    """

    if sd_test.shape.start > 380 or sd_test.shape.end < 780:
        usage_warning("Test spectral distribution shape does not span the"
                      "recommended 380-780nm range, missing values will be"
                      "filled with zeros!")

        # NOTE: "CIE 2017 Colour Fidelity Index" standard recommends filling
        # missing values with zeros.
        sd_test = cast(SpectralDistribution, sd_test.copy())
        sd_test.extrapolator = Extrapolator
        sd_test.extrapolator_kwargs = {
            "method": "constant",
            "left": 0,
            "right": 0,
        }

    if sd_test.shape.interval > 5:
        raise ValueError("Test spectral distribution interval is greater than"
                         "5nm which is the maximum recommended value "
                         'for computing the "CIE 2017 Colour Fidelity Index"!')

    shape = SpectralShape(
        SPECTRAL_SHAPE_CIE2017.start,
        SPECTRAL_SHAPE_CIE2017.end,
        sd_test.shape.interval,
    )

    CCT, D_uv = tsplit(CCT_reference_illuminant(sd_test))
    sd_reference = sd_reference_illuminant(CCT, shape)

    # NOTE: All computations except CCT calculation use the
    # "CIE 1964 10 Degree Standard Observer".
    # pylint: disable=E1102
    cmfs_10 = reshape_msds(MSDS_CMFS["CIE 1964 10 Degree Standard Observer"],
                           shape)

    # pylint: disable=E1102
    sds_tcs = reshape_msds(load_TCS_CIE2017(shape), shape)

    test_tcs_colorimetry_data = tcs_colorimetry_data(sd_test, sds_tcs, cmfs_10)
    reference_tcs_colorimetry_data = tcs_colorimetry_data(
        sd_reference, sds_tcs, cmfs_10)

    delta_E_s = np.empty(len(sds_tcs.labels))
    for i, _delta_E in enumerate(delta_E_s):
        delta_E_s[i] = euclidean_distance(
            test_tcs_colorimetry_data[i].Jpapbp,
            reference_tcs_colorimetry_data[i].Jpapbp,
        )

    R_s = as_float_array(delta_E_to_R_f(delta_E_s))
    R_f = as_float_scalar(delta_E_to_R_f(np.average(delta_E_s)))

    if additional_data:
        return ColourRendering_Specification_CIE2017(
            sd_test.name,
            sd_reference,
            R_f,
            R_s,
            CCT,
            D_uv,
            (test_tcs_colorimetry_data, reference_tcs_colorimetry_data),
            delta_E_s,
        )
    else:
        return R_f