Source code for colour.adaptation.fairchild2020

"""
Von Kries 2020 (vK20) Chromatic Adaptation Model
================================================

Define the *Von Kries 2020* (*vK20*) chromatic adaptation model objects:

-   :attr:`colour.adaptation.CONDITIONS_DEGREE_OF_ADAPTATION_VK20`
-   :func:`colour.adaptation.matrix_chromatic_adaptation_vk20`
-   :func:`colour.adaptation.chromatic_adaptation_vK20`

References
----------
-   :cite:`Fairchild2020` : Fairchild, M. D. (2020). Von Kries 2020: Evolution
    of degree of chromatic adaptation. Color and Imaging Conference, 28(1),
    252-257. doi:10.2352/issn.2169-2629.2020.28.40
"""

from __future__ import annotations

import typing
from dataclasses import dataclass

import numpy as np

from colour.adaptation import CHROMATIC_ADAPTATION_TRANSFORMS
from colour.algebra import sdiv, sdiv_mode, vecmul

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

from colour.utilities import (
    CanonicalMapping,
    MixinDataclassIterable,
    as_float_array,
    from_range_1,
    row_as_diagonal,
    to_domain_1,
    validate_method,
)

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

__all__ = [
    "Coefficients_DegreeOfAdaptation_vK20",
    "CONDITIONS_DEGREE_OF_ADAPTATION_VK20",
    "TVS_XYZ_R_VK20",
    "matrix_chromatic_adaptation_vk20",
    "chromatic_adaptation_vK20",
]


@dataclass(frozen=True)
class Coefficients_DegreeOfAdaptation_vK20(MixinDataclassIterable):
    """
    *Von Kries 2020* (*vK20*) degree of adaptation coefficients.

    Parameters
    ----------
    D_n
        Degree of adaptation for the adapting illuminant.
    D_r
        Degree of adaptation for the reference illuminant.
    D_p
        Degree of adaptation for the previous illuminant.

    References
    ----------
    :cite:`Fairchild2020`
    """

    D_n: float
    D_r: float
    D_p: float


CONDITIONS_DEGREE_OF_ADAPTATION_VK20: CanonicalMapping = CanonicalMapping(
    {
        "Fairchild": Coefficients_DegreeOfAdaptation_vK20(0.7, 0.3, 0),
        "Hands": Coefficients_DegreeOfAdaptation_vK20(0.95, 0.05, 0),
        "No Hands": Coefficients_DegreeOfAdaptation_vK20(0.85, 0.15, 0),
        "Ordinal 1st": Coefficients_DegreeOfAdaptation_vK20(0.9, 0.1, 0),
        "Ordinal 2nd": Coefficients_DegreeOfAdaptation_vK20(0.8, 0.1, 0.1),
        "Reversibility Trial 1st": Coefficients_DegreeOfAdaptation_vK20(0.7, 0.3, 0.1),
        "Reversibility Trial 2nd": Coefficients_DegreeOfAdaptation_vK20(0.6, 0.3, 0.1),
        "Ma et al.": Coefficients_DegreeOfAdaptation_vK20(1 / 3, 1 / 3, 1 / 3),
        "Hunt & Winter": Coefficients_DegreeOfAdaptation_vK20(0.6, 0.2, 0.2),
        "Hurvich & Jameson": Coefficients_DegreeOfAdaptation_vK20(0.7, 0.3, 0),
        "Simple von Kries": Coefficients_DegreeOfAdaptation_vK20(1, 0, 0),
    }
)
CONDITIONS_DEGREE_OF_ADAPTATION_VK20.__doc__ = """
Conditions for the *Von Kries 2020* (*vK20*) degree of adaptation coefficients.

References
----------
:cite:`Fairchild2020`
"""

TVS_XYZ_R_VK20 = np.array([0.97941176, 1.00000000, 1.73235294])
"""
*Von Kries 2020* (*vK20*) reference illuminant (taken to be
u' = 0.185, v' = 0.425, approximately 15000K, sky blue).

References
----------
:cite:`Fairchild2020`
"""


[docs] def matrix_chromatic_adaptation_vk20( XYZ_p: ArrayLike, XYZ_n: ArrayLike, XYZ_r: ArrayLike = TVS_XYZ_R_VK20, transform: Literal[ "Bianco 2010", "Bianco PC 2010", "Bradford", "CAT02 Brill 2008", "CAT02", "CAT16", "CMCCAT2000", "CMCCAT97", "Fairchild", "Sharp", "Von Kries", "XYZ Scaling", ] | str = "CAT02", coefficients: Coefficients_DegreeOfAdaptation_vK20 = ( CONDITIONS_DEGREE_OF_ADAPTATION_VK20["Fairchild"] ), ) -> NDArrayFloat: """ Compute the *chromatic adaptation* matrix from previous viewing conditions to adapting viewing conditions using *Von Kries 2020* (*vK20*) method. Parameters ---------- XYZ_p Previous viewing conditions *CIE XYZ* tristimulus values of whitepoint. XYZ_n Adapting viewing conditions *CIE XYZ* tristimulus values of whitepoint. XYZ_r Reference viewing conditions *CIE XYZ* tristimulus values of whitepoint. transform Chromatic adaptation transform. coefficients *vK20* degree of adaptation coefficients. Returns ------- :class:`numpy.ndarray` Chromatic adaptation matrix :math:`M_{cat}`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ_p`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ | ``XYZ_n`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ | ``XYZ_r`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`Fairchild2020` Examples -------- >>> XYZ_p = np.array([0.95045593, 1.00000000, 1.08905775]) >>> XYZ_n = np.array([0.96429568, 1.00000000, 0.82510460]) >>> matrix_chromatic_adaptation_vk20(XYZ_p, XYZ_n) ... # doctest: +ELLIPSIS array([[ 1.0279139...e+00, 2.9137117...e-02, -2.2794068...e-02], [ 2.0702840...e-02, 9.9005316...e-01, -9.2143464...e-03], [ -6.3758553...e-04, -1.1577319...e-03, 9.1296320...e-01]]) Using *Bradford* transform: >>> XYZ_p = np.array([0.95045593, 1.00000000, 1.08905775]) >>> XYZ_n = np.array([0.96429568, 1.00000000, 0.82510460]) >>> transform = "Bradford" >>> matrix_chromatic_adaptation_vk20(XYZ_p, XYZ_n, transform=transform) ... # doctest: +ELLIPSIS array([[ 1.0367230..., 0.0195580..., -0.0219321...], [ 0.0276321..., 0.9822296..., -0.0082419...], [-0.0029508..., 0.0040690..., 0.9102430...]]) """ XYZ_n = as_float_array(XYZ_n) XYZ_r = as_float_array(XYZ_r) XYZ_p = as_float_array(XYZ_p) transform = validate_method( transform, tuple(CHROMATIC_ADAPTATION_TRANSFORMS), '"{0}" chromatic adaptation transform is invalid, it must be one of {1}!', ) M = CHROMATIC_ADAPTATION_TRANSFORMS[transform] D_n, D_r, D_p = coefficients.values LMS_n = vecmul(M, XYZ_n) LMS_r = vecmul(M, XYZ_r) LMS_p = vecmul(M, XYZ_p) with sdiv_mode(): D = row_as_diagonal(sdiv(1, (D_n * LMS_n + D_r * LMS_r + D_p * LMS_p))) M_CAT = np.matmul(np.linalg.inv(M), D) return np.matmul(M_CAT, M)
[docs] def chromatic_adaptation_vK20( XYZ: ArrayLike, XYZ_p: ArrayLike, XYZ_n: ArrayLike, XYZ_r: ArrayLike = TVS_XYZ_R_VK20, transform: Literal[ "Bianco 2010", "Bianco PC 2010", "Bradford", "CAT02 Brill 2008", "CAT02", "CAT16", "CMCCAT2000", "CMCCAT97", "Fairchild", "Sharp", "Von Kries", "XYZ Scaling", ] | str = "CAT02", coefficients: Coefficients_DegreeOfAdaptation_vK20 = ( CONDITIONS_DEGREE_OF_ADAPTATION_VK20["Fairchild"] ), ) -> NDArrayFloat: """ Adapt given stimulus from previous viewing conditions to adapting viewing conditions using *Von Kries 2020* (*vK20*) method. Parameters ---------- XYZ *CIE XYZ* tristimulus values of stimulus to adapt. XYZ_p Previous viewing conditions *CIE XYZ* tristimulus values of whitepoint. XYZ_n Adapting viewing conditions *CIE XYZ* tristimulus values of whitepoint. XYZ_r Reference viewing conditions *CIE XYZ* tristimulus values of whitepoint. transform Chromatic adaptation transform. coefficients *vK20* degree of adaptation coefficients. 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_p`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ | ``XYZ_n`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ | ``XYZ_r`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ_a`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`Fairchild2020` Examples -------- >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) >>> XYZ_p = np.array([0.95045593, 1.00000000, 1.08905775]) >>> XYZ_n = np.array([0.96429568, 1.00000000, 0.82510460]) >>> chromatic_adaptation_vK20(XYZ, XYZ_p, XYZ_n) ... # doctest: +ELLIPSIS array([ 0.2146884..., 0.1245616..., 0.0466255...]) Using *Bradford* transform: >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) >>> XYZ_p = np.array([0.95045593, 1.00000000, 1.08905775]) >>> XYZ_n = np.array([0.96429568, 1.00000000, 0.82510460]) >>> transform = "Bradford" >>> chromatic_adaptation_vK20(XYZ, XYZ_p, XYZ_n, transform=transform) ... # doctest: +ELLIPSIS array([ 0.2153837..., 0.1250885..., 0.0466455...]) """ XYZ = to_domain_1(XYZ) XYZ_p = to_domain_1(XYZ_p) XYZ_n = to_domain_1(XYZ_n) XYZ_r = to_domain_1(XYZ_r) M_CAT = matrix_chromatic_adaptation_vk20( XYZ_p, XYZ_n, XYZ_r, transform, coefficients ) XYZ_a = vecmul(M_CAT, XYZ) return from_range_1(XYZ_a)