Source code for colour.colorimetry.whiteness

"""
Whiteness Index :math:`W`
=========================

Defines the *whiteness* index :math:`W` computation objects:

-   :func:`colour.colorimetry.whiteness_Berger1959`: *Whiteness* index
    :math:`WI` computation of given sample *CIE XYZ* tristimulus values using
    *Berger (1959)* method.
-   :func:`colour.colorimetry.whiteness_Taube1960`: *Whiteness* index
    :math:`WI` computation of given sample *CIE XYZ* tristimulus values using
    *Taube (1960)* method.
-   :func:`colour.colorimetry.whiteness_Stensby1968`: *Whiteness* index
    :math:`WI` computation of given sample *CIE L\\*a\\*b\\** colourspace array
    using *Stensby (1968)* method.
-   :func:`colour.colorimetry.whiteness_ASTME313`: *Whiteness* index :math:`WI`
    of given sample *CIE XYZ* tristimulus values using *ASTM E313* method.
-   :func:`colour.colorimetry.whiteness_Ganz1979`: *Whiteness* index :math:`W`
    and *tint* :math:`T` computation of given sample *CIE xy* chromaticity
    coordinates using *Ganz and Griesser (1979)* method.
-   :func:`colour.colorimetry.whiteness_CIE2004`: *Whiteness* :math:`W` or
    :math:`W_{10}` and *tint* :math:`T` or :math:`T_{10}` computation of given
    sample *CIE xy* chromaticity coordinates using *CIE 2004* method.
-   :attr:`colour.WHITENESS_METHODS`: Supported *whiteness* computations
    methods.
-   :func:`colour.whiteness`: *Whiteness* :math:`W` computation using given
    method.

References
----------
-   :cite:`CIETC1-482004k` : CIE TC 1-48. (2004). The evaluation of whiteness.
    In CIE 015:2004 Colorimetry, 3rd Edition (p. 24). ISBN:978-3-901906-33-6
-   :cite:`Wikipedia2004b` : Wikipedia. (2004). Whiteness. Retrieved September
    17, 2014, from http://en.wikipedia.org/wiki/Whiteness
-   :cite:`Wyszecki2000ba` : Wyszecki, Günther, & Stiles, W. S. (2000). Table
    I(6.5.3) Whiteness Formulae (Whiteness Measure Denoted by W). In Color
    Science: Concepts and Methods, Quantitative Data and Formulae (pp.
    837-839). Wiley. ISBN:978-0-471-39918-6
-   :cite:`X-Rite2012a` : X-Rite, & Pantone. (2012). Color iQC and Color iMatch
    Color Calculations Guide.
    https://www.xrite.com/-/media/xrite/files/apps_engineering_techdocuments/\
c/09_color_calculations_en.pdf
"""

from __future__ import annotations

from colour.hints import Any, ArrayLike, Literal, NDArrayFloat
from colour.utilities import (
    CanonicalMapping,
    as_float,
    as_float_array,
    filter_kwargs,
    from_range_100,
    get_domain_range_scale,
    to_domain_100,
    tsplit,
    tstack,
    validate_method,
)

__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__ = [
    "whiteness_Berger1959",
    "whiteness_Taube1960",
    "whiteness_Stensby1968",
    "whiteness_ASTME313",
    "whiteness_Ganz1979",
    "whiteness_CIE2004",
    "WHITENESS_METHODS",
    "whiteness",
]


[docs] def whiteness_Berger1959(XYZ: ArrayLike, XYZ_0: ArrayLike) -> NDArrayFloat: """ Return the *whiteness* index :math:`WI` of given sample *CIE XYZ* tristimulus values using *Berger (1959)* method. Parameters ---------- XYZ *CIE XYZ* tristimulus values of the sample. XYZ_0 *CIE XYZ* tristimulus values of the reference white. Returns ------- :class:`np.float` or :class:`numpy.ndarray` *Whiteness* :math:`WI`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ | ``XYZ_0`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``WI`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ - *Whiteness* :math:`WI` values larger than 33.33 indicate a bluish white and values smaller than 33.33 indicate a yellowish white. References ---------- :cite:`X-Rite2012a` Examples -------- >>> import numpy as np >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000]) >>> XYZ_0 = np.array([94.80966767, 100.00000000, 107.30513595]) >>> whiteness_Berger1959(XYZ, XYZ_0) # doctest: +ELLIPSIS 30.3638017... """ X, Y, Z = tsplit(to_domain_100(XYZ)) X_0, _Y_0, Z_0 = tsplit(to_domain_100(XYZ_0)) WI = 0.333 * Y + 125 * (Z / Z_0) - 125 * (X / X_0) return as_float(from_range_100(WI))
[docs] def whiteness_Taube1960(XYZ: ArrayLike, XYZ_0: ArrayLike) -> NDArrayFloat: """ Return the *whiteness* index :math:`WI` of given sample *CIE XYZ* tristimulus values using *Taube (1960)* method. Parameters ---------- XYZ *CIE XYZ* tristimulus values of the sample. XYZ_0 *CIE XYZ* tristimulus values of the reference white. Returns ------- :class:`np.float` or :class:`numpy.ndarray` *Whiteness* :math:`WI`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ | ``XYZ_0`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``WI`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ - *Whiteness* :math:`WI` values larger than 100 indicate a bluish white and values smaller than 100 indicate a yellowish white. References ---------- :cite:`X-Rite2012a` Examples -------- >>> import numpy as np >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000]) >>> XYZ_0 = np.array([94.80966767, 100.00000000, 107.30513595]) >>> whiteness_Taube1960(XYZ, XYZ_0) # doctest: +ELLIPSIS 91.4071738... """ _X, Y, Z = tsplit(to_domain_100(XYZ)) _X_0, _Y_0, Z_0 = tsplit(to_domain_100(XYZ_0)) WI = 400 * (Z / Z_0) - 3 * Y return as_float(from_range_100(WI))
[docs] def whiteness_Stensby1968(Lab: ArrayLike) -> NDArrayFloat: """ Return the *whiteness* index :math:`WI` of given sample *CIE L\\*a\\*b\\** colourspace array using *Stensby (1968)* method. Parameters ---------- Lab *CIE L\\*a\\*b\\** colourspace array of the sample. Returns ------- :class:`np.float` or :class:`numpy.ndarray` *Whiteness* :math:`WI`. Notes ----- +------------+-----------------------+-----------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+=================+ | ``Lab`` | ``L`` : [0, 100] | ``L`` : [0, 1] | | | | | | | ``a`` : [-100, 100] | ``a`` : [-1, 1] | | | | | | | ``b`` : [-100, 100] | ``b`` : [-1, 1] | +------------+-----------------------+-----------------+ +------------+-----------------------+-----------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+=================+ | ``WI`` | [0, 100] | [0, 1] | +------------+-----------------------+-----------------+ - *Whiteness* :math:`WI` values larger than 100 indicate a bluish white and values smaller than 100 indicate a yellowish white. References ---------- :cite:`X-Rite2012a` Examples -------- >>> import numpy as np >>> Lab = np.array([100.00000000, -2.46875131, -16.72486654]) >>> whiteness_Stensby1968(Lab) # doctest: +ELLIPSIS 142.7683456... """ L, a, b = tsplit(to_domain_100(Lab)) WI = L - 3 * b + 3 * a return as_float(from_range_100(WI))
[docs] def whiteness_ASTME313(XYZ: ArrayLike) -> NDArrayFloat: """ Return the *whiteness* index :math:`WI` of given sample *CIE XYZ* tristimulus values using *ASTM E313* method. Parameters ---------- XYZ *CIE XYZ* tristimulus values of the sample. Returns ------- :class:`np.float` or :class:`numpy.ndarray` *Whiteness* :math:`WI`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``WI`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`X-Rite2012a` Examples -------- >>> import numpy as np >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000]) >>> whiteness_ASTME313(XYZ) # doctest: +ELLIPSIS 55.7400000... """ _X, Y, Z = tsplit(to_domain_100(XYZ)) WI = 3.388 * Z - 3 * Y return as_float(from_range_100(WI))
[docs] def whiteness_Ganz1979(xy: ArrayLike, Y: ArrayLike) -> NDArrayFloat: """ Return the *whiteness* index :math:`W` and *tint* :math:`T` of given sample *CIE xy* chromaticity coordinates using *Ganz and Griesser (1979)* method. Parameters ---------- xy Chromaticity coordinates *CIE xy* of the sample. Y Tristimulus :math:`Y` value of the sample. Returns ------- :class:`numpy.ndarray` *Whiteness* :math:`W` and *tint* :math:`T`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``Y`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``WT`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ - The formula coefficients are valid for *CIE Standard Illuminant D Series* *D65* and *CIE 1964 10 Degree Standard Observer*. - Positive output *tint* :math:`T` values indicate a greener tint while negative values indicate a redder tint. - Whiteness differences of less than 5 Ganz units appear to be indistinguishable to the human eye. - Tint differences of less than 0.5 Ganz units appear to be indistinguishable to the human eye. References ---------- :cite:`X-Rite2012a` Examples -------- >>> import numpy as np >>> xy = np.array([0.3167, 0.3334]) >>> whiteness_Ganz1979(xy, 100) # doctest: +ELLIPSIS array([ 85.6003766..., 0.6789003...]) """ x, y = tsplit(xy) Y = to_domain_100(Y) W = Y - 1868.322 * x - 3695.690 * y + 1809.441 T = -1001.223 * x + 748.366 * y + 68.261 WT = tstack([W, T]) return from_range_100(WT)
[docs] def whiteness_CIE2004( xy: ArrayLike, Y: ArrayLike, xy_n: ArrayLike, observer: Literal[ "CIE 1931 2 Degree Standard Observer", "CIE 1964 10 Degree Standard Observer", ] = ("CIE 1931 2 Degree Standard Observer"), ) -> NDArrayFloat: """ Return the *whiteness* :math:`W` or :math:`W_{10}` and *tint* :math:`T` or :math:`T_{10}` of given sample *CIE xy* chromaticity coordinates using *CIE 2004* method. Parameters ---------- xy Chromaticity coordinates *CIE xy* of the sample. Y Tristimulus :math:`Y` value of the sample. xy_n Chromaticity coordinates *xy_n* of a perfect diffuser. observer *CIE Standard Observer* used for computations, *tint* :math:`T` or :math:`T_{10}` value is dependent on viewing field angular subtense. Returns ------- :class:`numpy.ndarray` *Whiteness* :math:`W` or :math:`W_{10}` and *tint* :math:`T` or :math:`T_{10}` of given sample. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``Y`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``WT`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ - This method may be used only for samples whose values of :math:`W` or :math:`W_{10}` lie within the following limits: greater than 40 and less than 5Y - 280, or 5Y10 - 280. - This method may be used only for samples whose values of :math:`T` or :math:`T_{10}` lie within the following limits: greater than -4 and less than +2. - Output *whiteness* :math:`W` or :math:`W_{10}` values larger than 100 indicate a bluish white while values smaller than 100 indicate a yellowish white. - Positive output *tint* :math:`T` or :math:`T_{10}` values indicate a greener tint while negative values indicate a redder tint. References ---------- :cite:`CIETC1-482004k` Examples -------- >>> import numpy as np >>> xy = np.array([0.3167, 0.3334]) >>> xy_n = np.array([0.3139, 0.3311]) >>> whiteness_CIE2004(xy, 100, xy_n) # doctest: +ELLIPSIS array([ 93.85..., -1.305...]) """ x, y = tsplit(xy) Y = to_domain_100(Y) x_n, y_n = tsplit(xy_n) W = Y + 800 * (x_n - x) + 1700 * (y_n - y) T = (1000 if "1931" in observer else 900) * (x_n - x) - 650 * (y_n - y) WT = tstack([W, T]) return from_range_100(WT)
WHITENESS_METHODS: CanonicalMapping = CanonicalMapping( { "Berger 1959": whiteness_Berger1959, "Taube 1960": whiteness_Taube1960, "Stensby 1968": whiteness_Stensby1968, "ASTM E313": whiteness_ASTME313, "Ganz 1979": whiteness_Ganz1979, "CIE 2004": whiteness_CIE2004, } ) WHITENESS_METHODS.__doc__ = """ Supported *whiteness* computation methods. References ---------- :cite:`CIETC1-482004k`, :cite:`X-Rite2012a` Aliases: - 'cie2004': 'CIE 2004' """ WHITENESS_METHODS["cie2004"] = WHITENESS_METHODS["CIE 2004"]
[docs] def whiteness( XYZ: ArrayLike, XYZ_0: ArrayLike, method: Literal[ "ASTM E313", "CIE 2004", "Berger 1959", "Ganz 1979", "Stensby 1968", "Taube 1960", ] | str = "CIE 2004", **kwargs: Any, ) -> NDArrayFloat: """ 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.float` 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, tuple(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))