Source code for colour.difference.cam02_ucs

"""
:math:`\\Delta E'` - Delta E Colour Difference - Luo, Cui and Li (2006)
=======================================================================

Define the :math:`\\Delta E'` colour difference computation objects based on
*Luo et al. (2006)* *CAM02-LCD*, *CAM02-SCD*, and *CAM02-UCS* colourspaces:

-   :func:`colour.difference.delta_E_CAM02LCD`
-   :func:`colour.difference.delta_E_CAM02SCD`
-   :func:`colour.difference.delta_E_CAM02UCS`

References
----------
-   :cite:`Luo2006b` : Luo, M. Ronnier, Cui, G., & Li, C. (2006). Uniform
    colour spaces based on CIECAM02 colour appearance model. Color Research &
    Application, 31(4), 320-330. doi:10.1002/col.20227
"""

from __future__ import annotations

import typing

import numpy as np

if typing.TYPE_CHECKING:
    from colour.hints import NDArrayFloat, Literal

from dataclasses import dataclass, field

from colour.hints import Domain100  # noqa: TC001
from colour.models.cam02_ucs import COEFFICIENTS_UCS_LUO2006, Coefficients_UCS_Luo2006
from colour.utilities import MixinDataclassArithmetic, as_float, tsplit

__author__ = "Colour Developers"
__copyright__ = "Copyright 2013 Colour Developers"
__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
__maintainer__ = "Colour Developers"
__email__ = "colour-developers@colour-science.org"
__status__ = "Production"

__all__ = [
    "DeltaE_Specification_Luo2006",
    "delta_E_Luo2006",
    "delta_E_CAM02LCD",
    "delta_E_CAM02SCD",
    "delta_E_CAM02UCS",
]


@dataclass
class DeltaE_Specification_Luo2006(MixinDataclassArithmetic):
    """
    Define the *Luo et al. (2006)* colour difference specification.

    This data structure is returned by
    :func:`colour.difference.delta_E_Luo2006` (and by extension
    :func:`colour.difference.delta_E_CAM02LCD`,
    :func:`colour.difference.delta_E_CAM02SCD`, and
    :func:`colour.difference.delta_E_CAM02UCS`) when
    ``additional_data=True``.

    Parameters
    ----------
    dE
        Colour difference :math:`\\Delta E'`.
    dJ
        Weighted *lightness* difference :math:`\\Delta J' / K_L`.
    da
        Raw :math:`\\Delta a'` difference.
    db
        Raw :math:`\\Delta b'` difference.
    """

    dE: NDArrayFloat | None = field(default_factory=lambda: None)
    dJ: NDArrayFloat | None = field(default_factory=lambda: None)
    da: NDArrayFloat | None = field(default_factory=lambda: None)
    db: NDArrayFloat | None = field(default_factory=lambda: None)


@typing.overload
def delta_E_Luo2006(
    Jpapbp_1: Domain100,
    Jpapbp_2: Domain100,
    coefficients: Coefficients_UCS_Luo2006,
    *,
    additional_data: Literal[False] = False,
) -> NDArrayFloat: ...


@typing.overload
def delta_E_Luo2006(
    Jpapbp_1: Domain100,
    Jpapbp_2: Domain100,
    coefficients: Coefficients_UCS_Luo2006,
    *,
    additional_data: Literal[True],
) -> DeltaE_Specification_Luo2006: ...


def delta_E_Luo2006(
    Jpapbp_1: Domain100,
    Jpapbp_2: Domain100,
    coefficients: Coefficients_UCS_Luo2006,
    additional_data: bool = False,
) -> NDArrayFloat | DeltaE_Specification_Luo2006:
    """
    Compute the colour difference :math:`\\Delta E'` between two specified
    *Luo et al. (2006)* *CAM02-LCD*, *CAM02-SCD*, or *CAM02-UCS*
    colourspaces :math:`J'a'b'` arrays.

    Parameters
    ----------
    Jpapbp_1
        Standard / reference *Luo et al. (2006)* *CAM02-LCD*, *CAM02-SCD*,
        or *CAM02-UCS* colourspaces :math:`J'a'b'` array.
    Jpapbp_2
        Sample / test *Luo et al. (2006)* *CAM02-LCD*, *CAM02-SCD*, or
        *CAM02-UCS* colourspaces :math:`J'a'b'` array.
    coefficients
        Coefficients of one of the *Luo et al. (2006)* *CAM02-LCD*,
        *CAM02-SCD*, or *CAM02-UCS* colourspaces.
    additional_data
        Whether to output additional data.

    Returns
    -------
    :class:`numpy.ndarray` or :class:`DeltaE_Specification_Luo2006`
        Colour difference :math:`\\Delta E'`.

    Warnings
    --------
    The :math:`J'a'b'` array should have been computed with a
    *Luo et al. (2006)* *CAM02-LCD*, *CAM02-SCD*, or *CAM02-UCS*
    colourspace and not with the *CIE L\\*a\\*b\\** colourspace.

    Notes
    -----
    +--------------+------------------------+--------------------+
    | **Domain**   |  **Scale - Reference** | **Scale - 1**      |
    +==============+========================+====================+
    | ``Jpapbp_1`` | 100                    | 1                  |
    +--------------+------------------------+--------------------+
    | ``Jpapbp_2`` | 100                    | 1                  |
    +--------------+------------------------+--------------------+

    Examples
    --------
    >>> Jpapbp_1 = np.array([54.90433134, -0.08450395, -0.06854831])
    >>> Jpapbp_2 = np.array([54.80352754, -3.96940084, -13.57591013])
    >>> delta_E_Luo2006(Jpapbp_1, Jpapbp_2, COEFFICIENTS_UCS_LUO2006["CAM02-LCD"])
    ... # doctest: +ELLIPSIS
    np.float64(14.0555464...)
    >>> delta_E_Luo2006(
    ...     Jpapbp_1,
    ...     Jpapbp_2,
    ...     COEFFICIENTS_UCS_LUO2006["CAM02-LCD"],
    ...     additional_data=True,
    ... )  # doctest: +ELLIPSIS
    DeltaE_Specification_Luo2006(dE=np.float64(14.0555464...), \
dJ=np.float64(0.1309140...), da=np.float64(3.8848968...), \
db=np.float64(13.5073618...))
    """

    J_p_1, a_p_1, b_p_1 = tsplit(Jpapbp_1)
    J_p_2, a_p_2, b_p_2 = tsplit(Jpapbp_2)
    K_L, _c_1, _c_2 = coefficients.values

    J = (J_p_1 - J_p_2) / K_L
    a = a_p_1 - a_p_2
    b = b_p_1 - b_p_2

    d_E = as_float(np.sqrt(J**2 + a**2 + b**2))

    if not additional_data:
        return d_E

    return DeltaE_Specification_Luo2006(
        d_E,
        J,
        a,
        b,
    )


@typing.overload
def delta_E_CAM02LCD(
    Jpapbp_1: Domain100,
    Jpapbp_2: Domain100,
    *,
    additional_data: Literal[False] = False,
) -> NDArrayFloat: ...


@typing.overload
def delta_E_CAM02LCD(
    Jpapbp_1: Domain100,
    Jpapbp_2: Domain100,
    *,
    additional_data: Literal[True],
) -> DeltaE_Specification_Luo2006: ...


[docs] def delta_E_CAM02LCD( Jpapbp_1: Domain100, Jpapbp_2: Domain100, additional_data: bool = False, ) -> NDArrayFloat | DeltaE_Specification_Luo2006: """ Compute the colour difference :math:`\\Delta E'` between two specified *CAM02-LCD* colourspace :math:`J'a'b'` arrays using the *Luo et al. (2006)* formula. Parameters ---------- Jpapbp_1 Standard / reference *CAM02-LCD* colourspace :math:`J'a'b'` array as computed by the *Luo et al. (2006)* uniform colour space model. Jpapbp_2 Sample / test *CAM02-LCD* colourspace :math:`J'a'b'` array as computed by the *Luo et al. (2006)* uniform colour space model. additional_data Whether to output additional data. Returns ------- :class:`numpy.ndarray` or :class:`DeltaE_Specification_Luo2006` Colour difference :math:`\\Delta E'`. Warnings -------- The :math:`J'a'b'` arrays should have been computed with the *Luo et al. (2006)* *CAM02-LCD* colourspace and not with the *CIE L\\*a\\*b\\** colourspace. Notes ----- +--------------+------------------------+--------------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +==============+========================+====================+ | ``Jpapbp_1`` | 100 | 1 | +--------------+------------------------+--------------------+ | ``Jpapbp_2`` | 100 | 1 | +--------------+------------------------+--------------------+ References ---------- :cite:`Luo2006b` Examples -------- >>> Jpapbp_1 = np.array([54.90433134, -0.08450395, -0.06854831]) >>> Jpapbp_2 = np.array([54.80352754, -3.96940084, -13.57591013]) >>> delta_E_CAM02LCD(Jpapbp_1, Jpapbp_2) # doctest: +ELLIPSIS np.float64(14.0555464...) >>> delta_E_CAM02LCD( ... Jpapbp_1, ... Jpapbp_2, ... additional_data=True, ... ) # doctest: +ELLIPSIS DeltaE_Specification_Luo2006(dE=np.float64(14.0555464...), \ dJ=np.float64(0.1309140...), da=np.float64(3.8848968...), \ db=np.float64(13.5073618...)) """ return delta_E_Luo2006( Jpapbp_1, Jpapbp_2, COEFFICIENTS_UCS_LUO2006["CAM02-LCD"], additional_data=additional_data, )
@typing.overload def delta_E_CAM02SCD( Jpapbp_1: Domain100, Jpapbp_2: Domain100, *, additional_data: Literal[False] = False, ) -> NDArrayFloat: ... @typing.overload def delta_E_CAM02SCD( Jpapbp_1: Domain100, Jpapbp_2: Domain100, *, additional_data: Literal[True], ) -> DeltaE_Specification_Luo2006: ...
[docs] def delta_E_CAM02SCD( Jpapbp_1: Domain100, Jpapbp_2: Domain100, additional_data: bool = False, ) -> NDArrayFloat | DeltaE_Specification_Luo2006: """ Compute the colour difference :math:`\\Delta E'` between two specified *CAM02-SCD* colourspace :math:`J'a'b'` arrays using the *Luo et al. (2006)* formula. Parameters ---------- Jpapbp_1 Standard / reference *CAM02-SCD* colourspace :math:`J'a'b'` array as computed by the *Luo et al. (2006)* uniform colour space model. Jpapbp_2 Sample / test *CAM02-SCD* colourspace :math:`J'a'b'` array as computed by the *Luo et al. (2006)* uniform colour space model. additional_data Whether to output additional data. Returns ------- :class:`numpy.ndarray` or :class:`DeltaE_Specification_Luo2006` Colour difference :math:`\\Delta E'`. Warnings -------- The :math:`J'a'b'` arrays should have been computed with the *Luo et al. (2006)* *CAM02-SCD* colourspace and not with the *CIE L\\*a\\*b\\** colourspace. Notes ----- +--------------+------------------------+--------------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +==============+========================+====================+ | ``Jpapbp_1`` | 100 | 1 | +--------------+------------------------+--------------------+ | ``Jpapbp_2`` | 100 | 1 | +--------------+------------------------+--------------------+ References ---------- :cite:`Luo2006b` Examples -------- >>> Jpapbp_1 = np.array([54.90433134, -0.08450395, -0.06854831]) >>> Jpapbp_2 = np.array([54.80352754, -3.96940084, -13.57591013]) >>> delta_E_CAM02SCD(Jpapbp_1, Jpapbp_2) # doctest: +ELLIPSIS np.float64(14.0551718...) >>> delta_E_CAM02SCD( ... Jpapbp_1, ... Jpapbp_2, ... additional_data=True, ... ) # doctest: +ELLIPSIS DeltaE_Specification_Luo2006(dE=np.float64(14.0551718...), \ dJ=np.float64(0.0812933...), da=np.float64(3.8848968...), \ db=np.float64(13.5073618...)) """ return delta_E_Luo2006( Jpapbp_1, Jpapbp_2, COEFFICIENTS_UCS_LUO2006["CAM02-SCD"], additional_data=additional_data, )
@typing.overload def delta_E_CAM02UCS( Jpapbp_1: Domain100, Jpapbp_2: Domain100, *, additional_data: Literal[False] = False, ) -> NDArrayFloat: ... @typing.overload def delta_E_CAM02UCS( Jpapbp_1: Domain100, Jpapbp_2: Domain100, *, additional_data: Literal[True], ) -> DeltaE_Specification_Luo2006: ...
[docs] def delta_E_CAM02UCS( Jpapbp_1: Domain100, Jpapbp_2: Domain100, additional_data: bool = False, ) -> NDArrayFloat | DeltaE_Specification_Luo2006: """ Compute the colour difference :math:`\\Delta E'` between two specified *CAM02-UCS* colourspace :math:`J'a'b'` arrays using the *Luo et al. (2006)* formula. Parameters ---------- Jpapbp_1 Standard / reference *CAM02-UCS* colourspace :math:`J'a'b'` array as computed by the *Luo et al. (2006)* uniform colour space model. Jpapbp_2 Sample / test *CAM02-UCS* colourspace :math:`J'a'b'` array as computed by the *Luo et al. (2006)* uniform colour space model. additional_data Whether to output additional data. Returns ------- :class:`numpy.ndarray` or :class:`DeltaE_Specification_Luo2006` Colour difference :math:`\\Delta E'`. Warnings -------- The :math:`J'a'b'` arrays should have been computed with the *Luo et al. (2006)* *CAM02-UCS* colourspace and not with the *CIE L\\*a\\*b\\** colourspace. Notes ----- +--------------+------------------------+--------------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +==============+========================+====================+ | ``Jpapbp_1`` | 100 | 1 | +--------------+------------------------+--------------------+ | ``Jpapbp_2`` | 100 | 1 | +--------------+------------------------+--------------------+ References ---------- :cite:`Luo2006b` Examples -------- >>> Jpapbp_1 = np.array([54.90433134, -0.08450395, -0.06854831]) >>> Jpapbp_2 = np.array([54.80352754, -3.96940084, -13.57591013]) >>> delta_E_CAM02UCS(Jpapbp_1, Jpapbp_2) # doctest: +ELLIPSIS np.float64(14.0552982...) >>> delta_E_CAM02UCS( ... Jpapbp_1, ... Jpapbp_2, ... additional_data=True, ... ) # doctest: +ELLIPSIS DeltaE_Specification_Luo2006(dE=np.float64(14.0552982...), \ dJ=np.float64(0.1008038...), da=np.float64(3.8848968...), \ db=np.float64(13.5073618...)) """ return delta_E_Luo2006( Jpapbp_1, Jpapbp_2, COEFFICIENTS_UCS_LUO2006["CAM02-UCS"], additional_data=additional_data, )