Exemplo n.º 1
0
def whiteness_Berger1959(XYZ, XYZ_0):
    """
    Returns the *whiteness* index :math:`WI` of given sample *CIE XYZ*
    tristimulus values using *Berger (1959)* method.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of sample.
    XYZ_0 : array_like
        *CIE XYZ* tristimulus values of reference white.

    Returns
    -------
    numeric or 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 from_range_100(WI)
Exemplo n.º 2
0
def whiteness_Berger1959(XYZ, XYZ_0):
    """
    Returns the *whiteness* index :math:`WI` of given sample *CIE XYZ*
    tristimulus values using *Berger (1959)* method.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of sample.
    XYZ_0 : array_like
        *CIE XYZ* tristimulus values of reference white.

    Returns
    -------
    numeric or 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 from_range_100(WI)
Exemplo n.º 3
0
def whiteness_Taube1960(XYZ: ArrayLike, XYZ_0: ArrayLike) -> FloatingOrNDArray:
    """
    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.floating` 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))
Exemplo n.º 4
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
Exemplo n.º 5
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
Exemplo n.º 6
0
def yellowness_ASTME313(
    XYZ: ArrayLike,
    C_XZ: ArrayLike = YELLOWNESS_COEFFICIENTS_ASTME313[
        "CIE 1931 2 Degree Standard Observer"]["D65"],
) -> FloatingOrNDArray:
    """
    Return the *yellowness* index :math:`YI` of given sample *CIE XYZ*
    tristimulus values using *ASTM E313* method.

    ASTM E313 has successfully been used for a variety of white or near white
    materials. This includes coatings, plastics, textiles.

    Parameters
    ----------
    XYZ
        *CIE XYZ* tristimulus values of the sample.
    C_XZ
        Coefficients :math:`C_X` and :math:`C_Z` for the
        *CIE 1931 2 Degree Standard Observer* and
        *CIE 1964 10 Degree Standard Observer* and *CIE Illuminant C* and
        *CIE Standard Illuminant D65*.

    Returns
    -------
    :class:`np.floating` or :class:`numpy.ndarray`
        *Yellowness* :math:`YI`.

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

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

    References
    ----------
    :cite:`ASTMInternational2015`

    Examples
    --------
    >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000])
    >>> yellowness_ASTME313(XYZ)  # doctest: +ELLIPSIS
    4.3400000...
    """

    X, Y, Z = tsplit(to_domain_100(XYZ))
    C_X, C_Z = tsplit(C_XZ)

    WI = 100 * (C_X * X - C_Z * Z) / Y

    return as_float(from_range_100(WI))
Exemplo n.º 7
0
    def test_to_domain_100(self):
        """Test :func:`colour.utilities.common.to_domain_100` definition."""

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

        with domain_range_scale("1"):
            self.assertEqual(to_domain_100(1), 100)

        with domain_range_scale("100"):
            self.assertEqual(to_domain_100(1), 1)

        with domain_range_scale("1"):
            self.assertEqual(to_domain_100(1, np.pi), np.pi)

        with domain_range_scale("100"):
            self.assertEqual(
                to_domain_100(1, dtype=np.float16).dtype, np.float16)
Exemplo n.º 8
0
def Luv_to_uv(
    Luv: ArrayLike,
    illuminant: ArrayLike = CCS_ILLUMINANTS[
        "CIE 1931 2 Degree Standard Observer"]["D65"],
) -> NDArray:
    """
    Return the :math:`uv^p` chromaticity coordinates from given
    *CIE L\\*u\\*v\\** colourspace array.

    Parameters
    ----------
    Luv
        *CIE L\\*u\\*v\\** colourspace array.
    illuminant
        Reference *illuminant* *CIE xy* chromaticity coordinates or *CIE xyY*
        colourspace array.

    Returns
    -------
    :class:`numpy.ndarray`
        :math:`uv^p` chromaticity coordinates.

    Notes
    -----
    +----------------+-----------------------+-----------------+
    | **Domain**     | **Scale - Reference** | **Scale - 1**   |
    +================+=======================+=================+
    | ``Luv``        | ``L`` : [0, 100]      | ``L`` : [0, 1]  |
    |                |                       |                 |
    |                | ``u`` : [-100, 100]   | ``u`` : [-1, 1] |
    |                |                       |                 |
    |                | ``v`` : [-100, 100]   | ``v`` : [-1, 1] |
    +----------------+-----------------------+-----------------+
    | ``illuminant`` | [0, 1]                | [0, 1]          |
    +----------------+-----------------------+-----------------+

    References
    ----------
    :cite:`CIETC1-482004j`

    Examples
    --------
    >>> import numpy as np
    >>> Luv = np.array([41.52787529, 96.83626054, 17.75210149])
    >>> Luv_to_uv(Luv)  # doctest: +ELLIPSIS
    array([ 0.3772021...,  0.5012026...])
    """

    Luv = to_domain_100(Luv)

    X, Y, Z = tsplit(Luv_to_XYZ(Luv, illuminant))

    X_Y_Z = X + 15 * Y + 3 * Z

    uv = tstack([4 * X / X_Y_Z, 9 * Y / X_Y_Z])

    return uv
Exemplo n.º 9
0
def luminance_Fairchild2010(L_hdr, epsilon=1.836):
    """
    Computes *luminance* :math:`Y` of given *Lightness* :math:`L_{hdr}` using
    *Fairchild and Wyble (2010)* method according to *Michealis-Menten*
    kinetics.

    Parameters
    ----------
    L_hdr : array_like
        *Lightness* :math:`L_{hdr}`.
    epsilon : numeric or array_like, optional
        :math:`\\epsilon` exponent.

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

    Warning
    -------
    The output range of that definition is non standard!

    Notes
    -----

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

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

    References
    ----------
    :cite:`Fairchild2010`

    Examples
    --------
    >>> luminance_Fairchild2010(31.996390226262736, 1.836)
    ... # doctest: +ELLIPSIS
    0.1219722...
    """

    L_hdr = to_domain_100(L_hdr)

    Y = np.exp(
        np.log(
            substrate_concentration_MichealisMenten(L_hdr - 0.02, 100, 0.184 **
                                                    epsilon)) / epsilon)

    return from_range_1(Y)
Exemplo n.º 10
0
def yellowness_ASTME313_alternative(XYZ: ArrayLike) -> FloatingOrNDArray:
    """
    Return the *yellowness* index :math:`YI` of given sample *CIE XYZ*
    tristimulus values using the alternative *ASTM E313* method.

    In the original form of *Test Method E313*, an alternative equation was
    recommended for a *yellowness* index. In terms of colorimeter readings,
    it was :math:`YI = 100(1 − B/G)` where :math:`B` and :math:`G` are,
    respectively, blue and green colorimeter readings. Its derivation assumed
    that, because of the limitation of the concept to yellow (or blue) colors,
    it was not necessary to take account of variations in the amber or red
    colorimeter reading :math:`A`. This equation is no longer recommended.

    Parameters
    ----------
    XYZ
        *CIE XYZ* tristimulus values of the sample.

    Returns
    -------
    :class:`np.floating` or :class:`numpy.ndarray`
        *Yellowness* :math:`YI`.

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

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

    -   Input *CIE XYZ* tristimulus values must be adapted to
        *CIE Illuminant C*.

    References
    ----------
    :cite:`ASTMInternational2015`, :cite:`X-Rite2012a`

    Examples
    --------
    >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000])
    >>> yellowness_ASTME313_alternative(XYZ)  # doctest: +ELLIPSIS
    11.0650000...
    """

    _X, Y, Z = tsplit(to_domain_100(XYZ))

    WI = 100 * (1 - (0.847 * Z) / Y)

    return as_float(from_range_100(WI))
Exemplo n.º 11
0
def luminance_Fairchild2010(L_hdr, epsilon=1.836):
    """
    Computes *luminance* :math:`Y` of given *Lightness* :math:`L_{hdr}` using
    *Fairchild and Wyble (2010)* method according to *Michealis-Menten*
    kinetics.

    Parameters
    ----------
    L_hdr : array_like
        *Lightness* :math:`L_{hdr}`.
    epsilon : numeric or array_like, optional
        :math:`\\epsilon` exponent.

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

    Warning
    -------
    The output range of that definition is non standard!

    Notes
    -----

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

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

    References
    ----------
    :cite:`Fairchild2010`

    Examples
    --------
    >>> luminance_Fairchild2010(31.996390226262736, 1.836)
    ... # doctest: +ELLIPSIS
    0.1219722...
    """

    L_hdr = to_domain_100(L_hdr)

    Y = np.exp(
        np.log(
            substrate_concentration_MichealisMenten(L_hdr - 0.02, 100, 0.184**
                                                    epsilon)) / epsilon)

    return from_range_1(Y)
Exemplo n.º 12
0
def lightness_CIE1976(Y, Y_n=100):
    """
    Returns the *Lightness* :math:`L^*` of given *luminance* :math:`Y` using
    given reference white *luminance* :math:`Y_n` as per *CIE 1976*
    recommendation.

    Parameters
    ----------
    Y : numeric or array_like
        *luminance* :math:`Y`.
    Y_n : numeric or array_like, optional
        White reference *luminance* :math:`Y_n`.

    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_star`` | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Lindbloom2003d`, :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> lightness_CIE1976(12.19722535)  # doctest: +ELLIPSIS
    41.5278758...
    """

    Y = to_domain_100(Y)
    Y_n = as_float_array(Y_n)

    L_star = Y / Y_n

    L_star = as_float(
        np.where(
            L_star <= CIE_E,
            CIE_K * L_star,
            116 * spow(L_star, 1 / 3) - 16,
        ))

    return from_range_100(L_star)
Exemplo n.º 13
0
def luminance_CIE1976(L_star, Y_n=100):
    """
    Returns the *luminance* :math:`Y` of given *Lightness* :math:`L^*` with
    given reference white *luminance* :math:`Y_n`.

    Parameters
    ----------
    L_star : numeric or array_like
        *Lightness* :math:`L^*`
    Y_n : numeric or array_like
        White reference *luminance* :math:`Y_n`.

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

    Notes
    -----

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

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

    References
    ----------
    :cite:`Lindbloom2003d`, :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> luminance_CIE1976(41.527875844653451)  # doctest: +ELLIPSIS
    12.1972253...
    >>> luminance_CIE1976(41.527875844653451, 95)  # doctest: +ELLIPSIS
    11.5873640...
    """

    L_star = to_domain_100(L_star)
    Y_n = as_float_array(Y_n)

    Y = as_float(
        np.where(
            L_star > CIE_K * CIE_E,
            Y_n * ((L_star + 16) / 116)**3,
            Y_n * (L_star / CIE_K),
        ))

    return from_range_100(Y)
Exemplo n.º 14
0
def whiteness_Stensby1968(Lab):
    """
    Returns the *whiteness* index :math:`WI` of given sample *CIE L\\*a\\*b\\**
    colourspace array using *Stensby (1968)* method.

    Parameters
    ----------
    Lab : array_like
        *CIE L\\*a\\*b\\** colourspace array of sample.

    Returns
    -------
    numeric or 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 from_range_100(WI)
Exemplo n.º 15
0
def yellowness_ASTMD1925(XYZ: ArrayLike) -> FloatingOrNDArray:
    """
    Return the *yellowness* index :math:`YI` of given sample *CIE XYZ*
    tristimulus values using *ASTM D1925* method.

    ASTM D1925 has been specifically developed for the definition of the
    yellowness of homogeneous, non-fluorescent, almost neutral-transparent,
    white-scattering or opaque plastics as they will be reviewed under daylight
    condition. It can be other materials as well, as long as they fit into this
    description.

    Parameters
    ----------
    XYZ
        *CIE XYZ* tristimulus values of the sample.

    Returns
    -------
    :class:`np.floating` or :class:`numpy.ndarray`
        *Yellowness* :math:`YI`.

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

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

    -   Input *CIE XYZ* tristimulus values must be adapted to
        *CIE Illuminant C*.

    References
    ----------
    :cite:`ASTMInternational2015`, :cite:`X-Rite2012a`

    Examples
    --------
    >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000])
    >>> yellowness_ASTMD1925(XYZ)  # doctest: +ELLIPSIS
    10.2999999...
    """

    X, Y, Z = tsplit(to_domain_100(XYZ))

    YI = (100 * (1.28 * X - 1.06 * Z)) / Y

    return as_float(from_range_100(YI))
Exemplo n.º 16
0
    def test_to_domain_100(self):
        """
        Tests :func:`colour.utilities.common.to_domain_100` definition.
        """

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

        with domain_range_scale('1'):
            self.assertEqual(to_domain_100(1), 100)

        with domain_range_scale('100'):
            self.assertEqual(to_domain_100(1), 1)

        with domain_range_scale('1'):
            self.assertEqual(to_domain_100(1, np.pi), np.pi)

        with domain_range_scale('100'):
            self.assertEqual(
                to_domain_100(1, dtype=np.float16).dtype, np.float16)
Exemplo n.º 17
0
def whiteness_Stensby1968(Lab):
    """
    Returns the *whiteness* index :math:`WI` of given sample *CIE L\\*a\\*b\\**
    colourspace array using *Stensby (1968)* method.

    Parameters
    ----------
    Lab : array_like
        *CIE L\\*a\\*b\\** colourspace array of sample.

    Returns
    -------
    numeric or 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 from_range_100(WI)
Exemplo n.º 18
0
def yellowness_ASTMD1925(XYZ):
    """
    Returns the *yellowness* index :math:`YI` of given sample *CIE XYZ*
    tristimulus values using *ASTM D1925* method.

    ASTM D1925 has been specifically developed for the definition of the
    Yellowness of homogeneous, non-fluorescent, almost neutral-transparent,
    white-scattering or opaque plastics as they will be reviewed under daylight
    condition. It can be other materials as well, as long as they fit into this
    description.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of sample.

    Returns
    -------
    numeric or ndarray
        *Whiteness* :math:`YI`.

    Notes
    -----

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

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

    References
    ----------
    :cite:`X-Rite2012a`

    Examples
    --------
    >>> import numpy as np
    >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000])
    >>> yellowness_ASTMD1925(XYZ)  # doctest: +ELLIPSIS
    10.2999999...
    """

    X, Y, Z = tsplit(to_domain_100(XYZ))

    YI = (100 * (1.28 * X - 1.06 * Z)) / Y

    return from_range_100(YI)
Exemplo n.º 19
0
def luminance_Fairchild2010(
        L_hdr: FloatingOrArrayLike,
        epsilon: FloatingOrArrayLike = 1.836) -> FloatingOrNDArray:
    """
    Compute *luminance* :math:`Y` of given *Lightness* :math:`L_{hdr}` using
    *Fairchild and Wyble (2010)* method according to *Michaelis-Menten*
    kinetics.

    Parameters
    ----------
    L_hdr
        *Lightness* :math:`L_{hdr}`.
    epsilon
        :math:`\\epsilon` exponent.

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

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

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

    References
    ----------
    :cite:`Fairchild2010`

    Examples
    --------
    >>> luminance_Fairchild2010(31.996390226262736, 1.836)
    ... # doctest: +ELLIPSIS
    0.1219722...
    """

    L_hdr = to_domain_100(L_hdr)

    Y = np.exp(
        np.log(
            substrate_concentration_MichaelisMenten_Michaelis1913(
                L_hdr - 0.02, 100, spow(0.184, epsilon))) / epsilon)

    return as_float(from_range_1(Y))
Exemplo n.º 20
0
def Luv_to_uv(
        Luv,
        illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65']):
    """
    Returns the :math:`uv^p` chromaticity coordinates from given
    *CIE L\\*u\\*v\\** colourspace array.

    Parameters
    ----------
    Luv : array_like
        *CIE L\\*u\\*v\\** colourspace array.
    illuminant : array_like, optional
        Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array.

    Returns
    -------
    ndarray
        :math:`uv^p` chromaticity coordinates.

    Notes
    -----

    +----------------+-----------------------+-----------------+
    | **Domain**     | **Scale - Reference** | **Scale - 1**   |
    +================+=======================+=================+
    | ``Luv``        | ``L`` : [0, 100]      | ``L`` : [0, 1]  |
    |                |                       |                 |
    |                | ``u`` : [-100, 100]   | ``u`` : [-1, 1] |
    |                |                       |                 |
    |                | ``v`` : [-100, 100]   | ``v`` : [-1, 1] |
    +----------------+-----------------------+-----------------+
    | ``illuminant`` | [0, 1]                | [0, 1]          |
    +----------------+-----------------------+-----------------+

    References
    ----------
    :cite:`CIETC1-482004j`

    Examples
    --------
    >>> Luv = np.array([41.52787529, 96.83626054, 17.75210149])
    >>> Luv_to_uv(Luv)  # doctest: +ELLIPSIS
    array([ 0.3772021...,  0.5012026...])
    """

    Luv = to_domain_100(Luv)

    X, Y, Z = tsplit(Luv_to_XYZ(Luv, illuminant))

    uv = tstack([4 * X / (X + 15 * Y + 3 * Z), 9 * Y / (X + 15 * Y + 3 * Z)])

    return uv
Exemplo n.º 21
0
def Luv_to_uv(
        Luv,
        illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65']):
    """
    Returns the :math:`uv^p` chromaticity coordinates from given
    *CIE L\\*u\\*v\\** colourspace array.

    Parameters
    ----------
    Luv : array_like
        *CIE L\\*u\\*v\\** colourspace array.
    illuminant : array_like, optional
        Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array.

    Returns
    -------
    ndarray
        :math:`uv^p` chromaticity coordinates.

    Notes
    -----

    +----------------+-----------------------+-----------------+
    | **Domain**     | **Scale - Reference** | **Scale - 1**   |
    +================+=======================+=================+
    | ``Luv``        | ``L`` : [0, 100]      | ``L`` : [0, 1]  |
    |                |                       |                 |
    |                | ``u`` : [-100, 100]   | ``u`` : [-1, 1] |
    |                |                       |                 |
    |                | ``v`` : [-100, 100]   | ``v`` : [-1, 1] |
    +----------------+-----------------------+-----------------+
    | ``illuminant`` | [0, 1]                | [0, 1]          |
    +----------------+-----------------------+-----------------+

    References
    ----------
    :cite:`CIETC1-482004j`

    Examples
    --------
    >>> Luv = np.array([41.52787529, 96.83626054, 17.75210149])
    >>> Luv_to_uv(Luv)  # doctest: +ELLIPSIS
    array([ 0.3772021...,  0.5012026...])
    """

    Luv = to_domain_100(Luv)

    X, Y, Z = tsplit(Luv_to_XYZ(Luv, illuminant))

    uv = tstack([4 * X / (X + 15 * Y + 3 * Z), 9 * Y / (X + 15 * Y + 3 * Z)])

    return uv
Exemplo n.º 22
0
def yellowness_ASTMD1925(XYZ):
    """
    Returns the *yellowness* index :math:`YI` of given sample *CIE XYZ*
    tristimulus values using *ASTM D1925* method.

    ASTM D1925 has been specifically developed for the definition of the
    Yellowness of homogeneous, non-fluorescent, almost neutral-transparent,
    white-scattering or opaque plastics as they will be reviewed under daylight
    condition. It can be other materials as well, as long as they fit into this
    description.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of sample.

    Returns
    -------
    numeric or ndarray
        *Whiteness* :math:`YI`.

    Notes
    -----

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

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

    References
    ----------
    :cite:`X-Rite2012a`

    Examples
    --------
    >>> import numpy as np
    >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000])
    >>> yellowness_ASTMD1925(XYZ)  # doctest: +ELLIPSIS
    10.2999999...
    """

    X, Y, Z = tsplit(to_domain_100(XYZ))

    YI = (100 * (1.28 * X - 1.06 * Z)) / Y

    return from_range_100(YI)
Exemplo n.º 23
0
def luminance_CIE1976(L_star, Y_n=100):
    """
    Returns the *luminance* :math:`Y` of given *Lightness* :math:`L^*` with
    given reference white *luminance* :math:`Y_n`.

    Parameters
    ----------
    L_star : numeric or array_like
        *Lightness* :math:`L^*`
    Y_n : numeric or array_like
        White reference *luminance* :math:`Y_n`.

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

    Notes
    -----

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

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

    References
    ----------
    :cite:`CIETC1-482004m`, :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> luminance_CIE1976(41.527875844653451)  # doctest: +ELLIPSIS
    12.1972253...
    >>> luminance_CIE1976(41.527875844653451, 95)  # doctest: +ELLIPSIS
    11.5873640...
    """

    L_star = to_domain_100(L_star)
    Y_n = as_float_array(Y_n)

    f_Y_Y_n = (L_star + 16) / 116

    Y = intermediate_luminance_function_CIE1976(f_Y_Y_n, Y_n)

    return from_range_100(Y)
Exemplo n.º 24
0
def luminance_CIE1976(L_star: FloatingOrArrayLike,
                      Y_n: FloatingOrArrayLike = 100) -> FloatingOrNDArray:
    """
    Return the *luminance* :math:`Y` of given *Lightness* :math:`L^*` with
    given reference white *luminance* :math:`Y_n`.

    Parameters
    ----------
    L_star
        *Lightness* :math:`L^*`
    Y_n
        White reference *luminance* :math:`Y_n`.

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

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

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

    References
    ----------
    :cite:`CIETC1-482004m`, :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> luminance_CIE1976(41.527875844653451)  # doctest: +ELLIPSIS
    12.1972253...
    >>> luminance_CIE1976(41.527875844653451, 95)  # doctest: +ELLIPSIS
    11.5873640...
    """

    L_star = to_domain_100(L_star)
    Y_n = as_float_array(Y_n)

    f_Y_Y_n = (L_star + 16) / 116

    Y = intermediate_luminance_function_CIE1976(f_Y_Y_n, Y_n)

    return as_float(from_range_100(Y))
Exemplo n.º 25
0
def lightness_Wyszecki1963(Y: FloatingOrArrayLike) -> FloatingOrNDArray:
    """
    Return the *Lightness* :math:`W` of given *luminance* :math:`Y` using
    *Wyszecki (1963)* method.


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

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

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

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

    References
    ----------
    :cite:`Wyszecki1963b`

    Examples
    --------
    >>> lightness_Wyszecki1963(12.19722535)  # doctest: +ELLIPSIS
    40.5475745...
    """

    Y = to_domain_100(Y)

    if np.any(Y < 1) or np.any(Y > 98):
        usage_warning(
            '"W*" Lightness computation is only applicable for '
            '1% < "Y" < 98%, unpredictable results may occur!'
        )

    W = 25 * spow(Y, 1 / 3) - 17

    return as_float(from_range_100(W))
Exemplo n.º 26
0
def yellowness_ASTME313(XYZ):
    """
    Returns the *yellowness* index :math:`YI` of given sample *CIE XYZ*
    tristimulus values using *ASTM E313* method.

    ASTM E313 has successfully been used for a variety of white or near white
    materials. This includes coatings, Plastics, Textiles.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of sample.

    Returns
    -------
    numeric or ndarray
        *Whiteness* :math:`YI`.

    Notes
    -----

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

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

    References
    ----------
    :cite:`X-Rite2012a`

    Examples
    --------
    >>> import numpy as np
    >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000])
    >>> yellowness_ASTME313(XYZ)  # doctest: +ELLIPSIS
    11.0650000...
    """

    _X, Y, Z = tsplit(to_domain_100(XYZ))

    WI = 100 * (1 - (0.847 * Z) / Y)

    return from_range_100(WI)
Exemplo n.º 27
0
def lightness_Wyszecki1963(Y):
    """
    Returns the *Lightness* :math:`W` of given *luminance* :math:`Y` using
    *Wyszecki (1963)* method.


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

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

    Notes
    -----

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

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

    References
    ----------
    :cite:`Wyszecki1963b`

    Examples
    --------
    >>> lightness_Wyszecki1963(12.19722535)  # doctest: +ELLIPSIS
    40.5475745...
    """

    Y = to_domain_100(Y)

    if np.any(Y < 1) or np.any(Y > 98):
        usage_warning('"W*" Lightness computation is only applicable for '
                      '1% < "Y" < 98%, unpredictable results may occur!')

    W = 25 * spow(Y, 1 / 3) - 17

    return from_range_100(W)
Exemplo n.º 28
0
def lightness_CIE1976(
    Y: FloatingOrArrayLike, Y_n: FloatingOrArrayLike = 100
) -> FloatingOrNDArray:
    """
    Return the *Lightness* :math:`L^*` of given *luminance* :math:`Y` using
    given reference white *luminance* :math:`Y_n` as per *CIE 1976*
    recommendation.

    Parameters
    ----------
    Y
        *Luminance* :math:`Y`.
    Y_n
        White reference *luminance* :math:`Y_n`.

    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_star`` | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`CIETC1-482004m`, :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> lightness_CIE1976(12.19722535)  # doctest: +ELLIPSIS
    41.5278758...
    """

    Y = to_domain_100(Y)
    Y_n = as_float_array(Y_n)

    L_star = 116 * intermediate_lightness_function_CIE1976(Y, Y_n) - 16

    return as_float(from_range_100(L_star))
Exemplo n.º 29
0
def yellowness_ASTME313(XYZ):
    """
    Returns the *yellowness* index :math:`YI` of given sample *CIE XYZ*
    tristimulus values using *ASTM E313* method.

    ASTM E313 has successfully been used for a variety of white or near white
    materials. This includes coatings, Plastics, Textiles.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of sample.

    Returns
    -------
    numeric or ndarray
        *Whiteness* :math:`YI`.

    Notes
    -----

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

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

    References
    ----------
    :cite:`X-Rite2012a`

    Examples
    --------
    >>> import numpy as np
    >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000])
    >>> yellowness_ASTME313(XYZ)  # doctest: +ELLIPSIS
    11.0650000...
    """

    _X, Y, Z = tsplit(to_domain_100(XYZ))

    WI = 100 * (1 - (0.847 * Z) / Y)

    return from_range_100(WI)
Exemplo n.º 30
0
def lightness_CIE1976(Y, Y_n=100):
    """
    Returns the *Lightness* :math:`L^*` of given *luminance* :math:`Y` using
    given reference white *luminance* :math:`Y_n` as per *CIE 1976*
    recommendation.

    Parameters
    ----------
    Y : numeric or array_like
        *luminance* :math:`Y`.
    Y_n : numeric or array_like, optional
        White reference *luminance* :math:`Y_n`.

    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_star`` | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`CIETC1-482004m`, :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> lightness_CIE1976(12.19722535)  # doctest: +ELLIPSIS
    41.5278758...
    """

    Y = to_domain_100(Y)
    Y_n = as_float_array(Y_n)

    L_star = 116 * intermediate_lightness_function_CIE1976(Y, Y_n) - 16

    return from_range_100(L_star)
Exemplo n.º 31
0
def whiteness_ASTME313(XYZ):
    """
    Returns the *whiteness* index :math:`WI` of given sample *CIE XYZ*
    tristimulus values using *ASTM E313* method.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of sample.

    Returns
    -------
    numeric or 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 from_range_100(WI)
Exemplo n.º 32
0
def whiteness_ASTME313(XYZ):
    """
    Returns the *whiteness* index :math:`WI` of given sample *CIE XYZ*
    tristimulus values using *ASTM E313* method.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of sample.

    Returns
    -------
    numeric or 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 from_range_100(WI)
Exemplo n.º 33
0
def lightness_Glasser1958(Y):
    """
    Returns the *Lightness* :math:`L` of given *luminance* :math:`Y` using
    *Glasser et al. (1958)* method.

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

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

    Examples
    --------
    >>> lightness_Glasser1958(12.19722535)  # doctest: +ELLIPSIS
    39.8351264...
    """

    Y = to_domain_100(Y)

    L = 25.29 * spow(Y, 1 / 3) - 18.38

    return from_range_100(L)
Exemplo n.º 34
0
def lightness_Glasser1958(Y):
    """
    Returns the *Lightness* :math:`L` of given *luminance* :math:`Y` using
    *Glasser et al. (1958)* method.

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

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

    Examples
    --------
    >>> lightness_Glasser1958(12.19722535)  # doctest: +ELLIPSIS
    39.8351264...
    """

    Y = to_domain_100(Y)

    L = 25.29 * spow(Y, 1 / 3) - 18.38

    return from_range_100(L)
Exemplo n.º 35
0
def lightness_Glasser1958(Y: FloatingOrArrayLike) -> FloatingOrNDArray:
    """
    Return the *Lightness* :math:`L` of given *luminance* :math:`Y` using
    *Glasser et al. (1958)* method.

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

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

    Examples
    --------
    >>> lightness_Glasser1958(12.19722535)  # doctest: +ELLIPSIS
    39.8351264...
    """

    Y = to_domain_100(Y)

    L = 25.29 * spow(Y, 1 / 3) - 18.38

    return as_float(from_range_100(L))
Exemplo n.º 36
0
def Lab_to_XYZ(
        Lab,
        illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65']):
    """
    Converts from *CIE L\\*a\\*b\\** colourspace to *CIE XYZ* tristimulus
    values.

    Parameters
    ----------
    Lab : array_like
        *CIE L\\*a\\*b\\** colourspace array.
    illuminant : array_like, optional
        Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array.

    Returns
    -------
    ndarray
        *CIE XYZ* tristimulus values.

    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] |
    +----------------+-----------------------+-----------------+
    | ``illuminant`` | [0, 1]                | [0, 1]          |
    +----------------+-----------------------+-----------------+

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

    References
    ----------
    :cite:`CIETC1-482004m`

    Examples
    --------
    >>> Lab = np.array([41.52787529, 52.63858304, 26.92317922])
    >>> Lab_to_XYZ(Lab)  # doctest: +ELLIPSIS
    array([ 0.2065400...,  0.1219722...,  0.0513695...])
    """

    L, a, b = tsplit(to_domain_100(Lab))

    X_n, Y_n, Z_n = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant)))

    f_Y_Y_n = (L + 16) / 116
    f_X_X_n = a / 500 + f_Y_Y_n
    f_Z_Z_n = f_Y_Y_n - b / 200

    X = intermediate_luminance_function_CIE1976(f_X_X_n, X_n)
    Y = intermediate_luminance_function_CIE1976(f_Y_Y_n, Y_n)
    Z = intermediate_luminance_function_CIE1976(f_Z_Z_n, Z_n)

    XYZ = tstack([X, Y, Z])

    return from_range_1(XYZ)
Exemplo n.º 37
0
def Lab_to_DIN99(Lab, k_E=1, k_CH=1):
    """
    Converts from *CIE L\\*a\\*b\\** colourspace to *DIN99* colourspace.

    Parameters
    ----------
    Lab : array_like
        *CIE L\\*a\\*b\\** colourspace array.
    k_E : numeric, optional
        Parametric factor :math:`K_E` used to compensate for texture and other
        specimen presentation effects.
    k_CH : numeric, optional
        Parametric factor :math:`K_{CH}` used to compensate for texture and
        other specimen presentation effects.

    Returns
    -------
    ndarray
        *DIN99* colourspace array.

    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**      |
    +============+========================+====================+
    | ``Lab_99`` | ``L_99`` : [0, 100]    | ``L_99`` : [0, 1]  |
    |            |                        |                    |
    |            | ``a_99`` : [-100, 100] | ``a_99`` : [-1, 1] |
    |            |                        |                    |
    |            | ``b_99`` : [-100, 100] | ``b_99`` : [-1, 1] |
    +------------+------------------------+--------------------+

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

    Examples
    --------
    >>> import numpy as np
    >>> Lab = np.array([41.52787529, 52.63858304, 26.92317922])
    >>> Lab_to_DIN99(Lab)  # doctest: +ELLIPSIS
    array([ 53.2282198...,  28.4163465...,   3.8983955...])
    """

    L, a, b = tsplit(to_domain_100(Lab))

    cos_16 = np.cos(np.radians(16))
    sin_16 = np.sin(np.radians(16))

    e = cos_16 * a + sin_16 * b
    f = 0.7 * (-sin_16 * a + cos_16 * b)
    G = spow(e ** 2 + f ** 2, 0.5)
    h_ef = np.arctan2(f, e)

    C_99 = (np.log(1 + 0.045 * G)) / (0.045 * k_CH * k_E)
    # Hue angle is unused currently.
    # h_99 = np.degrees(h_ef)
    a_99 = C_99 * np.cos(h_ef)
    b_99 = C_99 * np.sin(h_ef)
    L_99 = 105.509 * (np.log(1 + 0.0158 * L)) * k_E

    Lab_99 = tstack([L_99, a_99, b_99])

    return from_range_100(Lab_99)
Exemplo n.º 38
0
def UVW_to_XYZ(
        UVW,
        illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65']):
    """
    Converts *CIE 1964 U\\*V\\*W\\** colourspace to *CIE XYZ* tristimulus
    values.

    Parameters
    ----------
    UVW : array_like
        *CIE 1964 U\\*V\\*W\\** colourspace array.
    illuminant : array_like, optional
        Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array.

    Returns
    -------
    ndarray
        *CIE XYZ* tristimulus values.

    Warning
    -------
    The input domain and output range of that definition are non standard!

    Notes
    -----

    +----------------+-----------------------+-----------------+
    | **Domain**     | **Scale - Reference** | **Scale - 1**   |
    +================+=======================+=================+
    | ``UVW``        | ``U`` : [-100, 100]   | ``U`` : [-1, 1] |
    |                |                       |                 |
    |                | ``V`` : [-100, 100]   | ``V`` : [-1, 1] |
    |                |                       |                 |
    |                | ``W`` : [0, 100]      | ``W`` : [0, 1]  |
    +----------------+-----------------------+-----------------+
    | ``illuminant`` | [0, 1]                | [0, 1]          |
    +----------------+-----------------------+-----------------+

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

    References
    ----------
    :cite:`Wikipedia2008a`

    Examples
    --------
    >>> import numpy as np
    >>> UVW = np.array([94.55035725, 11.55536523, 40.54757405])
    >>> UVW_to_XYZ(UVW)
    array([ 20.654008,  12.197225,   5.136952])
    """

    U, V, W = tsplit(to_domain_100(UVW))

    u_0, v_0 = tsplit(xy_to_UCS_uv(xyY_to_xy(illuminant)))

    Y = ((W + 17) / 25) ** 3
    u = U / (13 * W) + u_0
    v = V / (13 * W) + v_0

    x, y = tsplit(UCS_uv_to_xy(tstack([u, v])))

    XYZ = xyY_to_XYZ(tstack([x, y, Y]))

    return from_range_100(XYZ)
Exemplo n.º 39
0
def Luv_to_XYZ(
        Luv,
        illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65']):
    """
    Converts from *CIE L\\*u\\*v\\** colourspace to *CIE XYZ* tristimulus
    values.

    Parameters
    ----------
    Luv : array_like
        *CIE L\\*u\\*v\\** colourspace array.
    illuminant : array_like, optional
        Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array.

    Returns
    -------
    ndarray
        *CIE XYZ* tristimulus values.

    Notes
    -----

    +----------------+-----------------------+-----------------+
    | **Domain**     | **Scale - Reference** | **Scale - 1**   |
    +================+=======================+=================+
    | ``Luv``        | ``L`` : [0, 100]      | ``L`` : [0, 1]  |
    |                |                       |                 |
    |                | ``u`` : [-100, 100]   | ``u`` : [-1, 1] |
    |                |                       |                 |
    |                | ``v`` : [-100, 100]   | ``v`` : [-1, 1] |
    +----------------+-----------------------+-----------------+
    | ``illuminant`` | [0, 1]                | [0, 1]          |
    +----------------+-----------------------+-----------------+

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

    References
    ----------
    :cite:`CIETC1-482004m`, :cite:`Wikipedia2007b`

    Examples
    --------
    >>> Luv = np.array([41.52787529, 96.83626054, 17.75210149])
    >>> Luv_to_XYZ(Luv)  # doctest: +ELLIPSIS
    array([ 0.2065400...,  0.1219722...,  0.0513695...])
    """

    L, u, v = tsplit(to_domain_100(Luv))

    X_r, Y_r, Z_r = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant)))

    with domain_range_scale('100'):
        Y = luminance_CIE1976(L, Y_r)

    a = 1 / 3 * (
        (52 * L / (u + 13 * L * (4 * X_r / (X_r + 15 * Y_r + 3 * Z_r)))) - 1)
    b = -5 * Y
    c = -1 / 3.0
    d = Y * (39 * L / (v + 13 * L * (9 * Y_r /
                                     (X_r + 15 * Y_r + 3 * Z_r))) - 5)

    X = (d - b) / (a - c)
    Z = X * a + b

    XYZ = tstack([X, Y, Z])

    return from_range_1(XYZ)
Exemplo n.º 40
0
def chromatic_adaptation_Fairchild1990(XYZ_1,
                                       XYZ_n,
                                       XYZ_r,
                                       Y_n,
                                       discount_illuminant=False):
    """
    Adapts given stimulus *CIE XYZ_1* tristimulus values from test viewing
    conditions to reference viewing conditions using *Fairchild (1990)*
    chromatic adaptation model.

    Parameters
    ----------
    XYZ_1 : array_like
        *CIE XYZ_1* tristimulus values of test sample / stimulus.
    XYZ_n : array_like
        Test viewing condition *CIE XYZ_n* tristimulus values of whitepoint.
    XYZ_r : array_like
        Reference viewing condition *CIE XYZ_r* tristimulus values of
        whitepoint.
    Y_n : numeric or array_like
        Luminance :math:`Y_n` of test adapting stimulus in :math:`cd/m^2`.
    discount_illuminant : bool, optional
        Truth value indicating if the illuminant should be discounted.

    Returns
    -------
    ndarray
        Adapted *CIE XYZ_2* tristimulus values of stimulus.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``XYZ_1``  | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_n``  | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_r``  | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

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

    References
    ----------
    :cite:`Fairchild1991a`, :cite:`Fairchild2013s`

    Examples
    --------
    >>> XYZ_1 = np.array([19.53, 23.07, 24.97])
    >>> XYZ_n = np.array([111.15, 100.00, 35.20])
    >>> XYZ_r = np.array([94.81, 100.00, 107.30])
    >>> Y_n = 200
    >>> chromatic_adaptation_Fairchild1990(XYZ_1, XYZ_n, XYZ_r, Y_n)
    ... # doctest: +ELLIPSIS
    array([ 23.3252634...,  23.3245581...,  76.1159375...])
    """

    XYZ_1 = to_domain_100(XYZ_1)
    XYZ_n = to_domain_100(XYZ_n)
    XYZ_r = to_domain_100(XYZ_r)
    Y_n = as_float_array(Y_n)

    LMS_1 = dot_vector(FAIRCHILD1990_XYZ_TO_RGB_MATRIX, XYZ_1)
    LMS_n = dot_vector(FAIRCHILD1990_XYZ_TO_RGB_MATRIX, XYZ_n)
    LMS_r = dot_vector(FAIRCHILD1990_XYZ_TO_RGB_MATRIX, XYZ_r)

    p_LMS = degrees_of_adaptation(
        LMS_1, Y_n, discount_illuminant=discount_illuminant)

    a_LMS_1 = p_LMS / LMS_n
    a_LMS_2 = p_LMS / LMS_r

    A_1 = row_as_diagonal(a_LMS_1)
    A_2 = row_as_diagonal(a_LMS_2)

    LMSp_1 = dot_vector(A_1, LMS_1)

    c = 0.219 - 0.0784 * np.log10(Y_n)
    C = row_as_diagonal(tstack([c, c, c]))

    LMS_a = dot_vector(C, LMSp_1)
    LMSp_2 = dot_vector(np.linalg.inv(C), LMS_a)

    LMS_c = dot_vector(np.linalg.inv(A_2), LMSp_2)
    XYZ_c = dot_vector(FAIRCHILD1990_RGB_TO_XYZ_MATRIX, LMS_c)

    return from_range_100(XYZ_c)
Exemplo n.º 41
0
def XYZ_to_UVW(
        XYZ,
        illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65']):
    """
    Converts from *CIE XYZ* tristimulus values to *CIE 1964 U\\*V\\*W\\**
    colourspace.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values.
    illuminant : array_like, optional
        Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array.

    Returns
    -------
    ndarray
        *CIE 1964 U\\*V\\*W\\** colourspace array.

    Warning
    -------
    The input domain and output range of that definition are non standard!

    Notes
    -----

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

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

    References
    ----------
    :cite:`Wikipedia2008a`

    Examples
    --------
    >>> import numpy as np
    >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) * 100
    >>> XYZ_to_UVW(XYZ)  # doctest: +ELLIPSIS
    array([ 94.5503572...,  11.5553652...,  40.5475740...])
    """

    XYZ = to_domain_100(XYZ)

    xy = xyY_to_xy(illuminant)
    xyY = XYZ_to_xyY(XYZ, xy)
    _x, _y, Y = tsplit(xyY)

    u, v = tsplit(UCS_to_uv(XYZ_to_UCS(XYZ)))
    u_0, v_0 = tsplit(xy_to_UCS_uv(xy))

    W = 25 * spow(Y, 1 / 3) - 17
    U = 13 * W * (u - u_0)
    V = 13 * W * (v - v_0)

    UVW = tstack([U, V, W])

    return from_range_100(UVW)
Exemplo n.º 42
0
def JMh_CIECAM02_to_UCS_Luo2006(JMh, coefficients):
    """
    Converts from *CIECAM02* :math:`JMh` correlates array to one of the
    *Luo et al. (2006)* *CAM02-LCD*, *CAM02-SCD*, or *CAM02-UCS* colourspaces
    :math:`J'a'b'` array.

    The :math:`JMh` correlates array is constructed using the CIECAM02
    correlate of *Lightness* :math:`J`, the *CIECAM02* correlate of
    *colourfulness* :math:`M` and the *CIECAM02* *Hue* angle :math:`h` in
    degrees.

    Parameters
    ----------
    JMh : array_like
        *CIECAM02* correlates array :math:`JMh`.
    coefficients : array_like
        Coefficients of one of the *Luo et al. (2006)* *CAM02-LCD*,
        *CAM02-SCD*, or *CAM02-UCS* colourspaces.

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

    Notes
    -----

    +------------+------------------------+--------------------+
    | **Domain** |  **Scale - Reference** | **Scale - 1**      |
    +============+========================+====================+
    | ``JMh``    | ``J`` : [0, 100]       | ``J`` : [0, 1]     |
    |            |                        |                    |
    |            | ``M`` : [0, 100]       | ``M`` : [0, 1]     |
    |            |                        |                    |
    |            | ``h`` : [0, 360]       | ``h`` : [0, 1]     |
    +------------+------------------------+--------------------+

    +------------+------------------------+--------------------+
    | **Range**  |  **Scale - Reference** | **Scale - 1**      |
    +============+========================+====================+
    | ``Jpapbp`` | ``Jp_1`` : [0, 100]    | ``Jp_1`` : [0, 1]  |
    |            |                        |                    |
    |            | ``ap_1`` : [-100, 100] | ``ap_1`` : [-1, 1] |
    |            |                        |                    |
    |            | ``bp_1`` : [-100, 100] | ``bp_1`` : [-1, 1] |
    +------------+------------------------+--------------------+

    Examples
    --------
    >>> from colour.appearance import (
    ...     CIECAM02_VIEWING_CONDITIONS,
    ...     XYZ_to_CIECAM02)
    >>> XYZ = np.array([19.01, 20.00, 21.78])
    >>> XYZ_w = np.array([95.05, 100.00, 108.88])
    >>> L_A = 318.31
    >>> Y_b = 20.0
    >>> surround = CIECAM02_VIEWING_CONDITIONS['Average']
    >>> specification = XYZ_to_CIECAM02(
    ...     XYZ, XYZ_w, L_A, Y_b, surround)
    >>> JMh = (specification.J, specification.M, specification.h)
    >>> JMh_CIECAM02_to_UCS_Luo2006(JMh, COEFFICIENTS_UCS_LUO2006['CAM02-LCD'])
    ... # doctest: +ELLIPSIS
    array([ 54.9043313...,  -0.0845039...,  -0.0685483...])
    """

    J, M, h = tsplit(JMh)
    J = to_domain_100(J)
    M = to_domain_100(M)
    h = to_domain_degrees(h)

    _K_L, c_1, c_2 = tsplit(coefficients)

    J_p = ((1 + 100 * c_1) * J) / (1 + c_1 * J)
    M_p = (1 / c_2) * np.log(1 + c_2 * M)

    a_p, b_p = tsplit(polar_to_cartesian(tstack([M_p, np.radians(h)])))

    Jpapbp = tstack([J_p, a_p, b_p])

    return from_range_100(Jpapbp)
Exemplo n.º 43
0
def UCS_Luo2006_to_JMh_CIECAM02(Jpapbp, coefficients):
    """
    Converts from one of the *Luo et al. (2006)* *CAM02-LCD*, *CAM02-SCD*, or
    *CAM02-UCS* colourspaces :math:`J'a'b'` array to *CIECAM02* :math:`JMh`
    correlates array.

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

    Returns
    -------
    ndarray
        *CIECAM02* correlates array :math:`JMh`.

    Notes
    -----

    +------------+------------------------+--------------------+
    | **Domain** |  **Scale - Reference** | **Scale - 1**      |
    +============+========================+====================+
    | ``Jpapbp`` | ``Jp_1`` : [0, 100]    | ``Jp_1`` : [0, 1]  |
    |            |                        |                    |
    |            | ``ap_1`` : [-100, 100] | ``ap_1`` : [-1, 1] |
    |            |                        |                    |
    |            | ``bp_1`` : [-100, 100] | ``bp_1`` : [-1, 1] |
    +------------+------------------------+--------------------+

    +------------+------------------------+--------------------+
    | **Range**  |  **Scale - Reference** | **Scale - 1**      |
    +============+========================+====================+
    | ``JMh``    | ``J`` : [0, 100]       | ``J`` : [0, 1]     |
    |            |                        |                    |
    |            | ``M`` : [0, 100]       | ``M`` : [0, 1]     |
    |            |                        |                    |
    |            | ``h`` : [0, 360]       | ``h`` : [0, 1]     |
    +------------+------------------------+--------------------+

    Examples
    --------
    >>> Jpapbp = np.array([54.90433134, -0.08450395, -0.06854831])
    >>> UCS_Luo2006_to_JMh_CIECAM02(
    ...     Jpapbp, COEFFICIENTS_UCS_LUO2006['CAM02-LCD'])
    ... # doctest: +ELLIPSIS
    array([  4.1731091...e+01,   1.0884217...e-01,   2.1904843...e+02])
    """

    J_p, a_p, b_p = tsplit(to_domain_100(Jpapbp))
    _K_L, c_1, c_2 = tsplit(coefficients)

    J = -J_p / (c_1 * J_p - 1 - 100 * c_1)

    M_p, h = tsplit(cartesian_to_polar(tstack([a_p, b_p])))

    M = (np.exp(M_p / (1 / c_2)) - 1) / c_2

    JMh = tstack([
        from_range_100(J),
        from_range_100(M),
        from_range_degrees(np.degrees(h) % 360)
    ])

    return JMh
Exemplo n.º 44
0
def delta_E_CMC(Lab_1, Lab_2, l=2, c=1):  # noqa
    """
    Returns the difference :math:`\\Delta E_{CMC}` between two given
    *CIE L\\*a\\*b\\** colourspace arrays using *Colour Measurement Committee*
    recommendation.

    The quasimetric has two parameters: *Lightness* (l) and *chroma* (c),
    allowing the users to weight the difference based on the ratio of l:c.
    Commonly used values are 2:1 for acceptability and 1:1 for the threshold of
    imperceptibility.

    Parameters
    ----------
    Lab_1 : array_like
        *CIE L\\*a\\*b\\** colourspace array 1.
    Lab_2 : array_like
        *CIE L\\*a\\*b\\** colourspace array 2.
    l : numeric, optional
        Lightness weighting factor.
    c : numeric, optional
        Chroma weighting factor.

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

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

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

    L_1, a_1, b_1 = tsplit(to_domain_100(Lab_1))
    L_2, a_2, b_2 = tsplit(to_domain_100(Lab_2))

    c_1 = np.hypot(a_1, b_1)
    c_2 = np.hypot(a_2, b_2)
    s_l = np.where(L_1 < 16, 0.511, (0.040975 * L_1) / (1 + 0.01765 * L_1))
    s_c = 0.0638 * c_1 / (1 + 0.0131 * c_1) + 0.638
    h_1 = np.degrees(np.arctan2(b_1, a_1)) % 360

    t = np.where(
        np.logical_and(h_1 >= 164, h_1 <= 345),
        0.56 + np.fabs(0.2 * np.cos(np.deg2rad(h_1 + 168))),
        0.36 + np.fabs(0.4 * np.cos(np.deg2rad(h_1 + 35))),
    )

    c_4 = c_1 * c_1 * c_1 * c_1
    f = np.sqrt(c_4 / (c_4 + 1900))
    s_h = s_c * (f * t + 1 - f)

    delta_L = L_1 - L_2
    delta_C = c_1 - c_2
    delta_A = a_1 - a_2
    delta_B = b_1 - b_2
    delta_H2 = delta_A ** 2 + delta_B ** 2 - delta_C ** 2

    v_1 = delta_L / (l * s_l)
    v_2 = delta_C / (c * s_c)
    v_3 = s_h

    d_E = np.sqrt(v_1 ** 2 + v_2 ** 2 + (delta_H2 / (v_3 * v_3)))

    return d_E
Exemplo n.º 45
0
def delta_E_CIE2000(Lab_1, Lab_2, textiles=False):
    """
    Returns the difference :math:`\\Delta E_{00}` between two given
    *CIE L\\*a\\*b\\** colourspace arrays using *CIE 2000* recommendation.

    Parameters
    ----------
    Lab_1 : array_like
        *CIE L\\*a\\*b\\** colourspace array 1.
    Lab_2 : array_like
        *CIE L\\*a\\*b\\** colourspace array 2.
    textiles : bool, optional
        Textiles application specific parametric factors
        :math:`k_L=2,\\ k_C=k_H=1` weights are used instead of
        :math:`k_L=k_C=k_H=1`.

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

    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] |
    +------------+-----------------------+-------------------+

    -   *CIE 2000* colour differences are not symmetrical: difference between
        ``Lab_1`` and ``Lab_2`` may not be the same as difference between
        ``Lab_2`` and ``Lab_1`` thus one colour must be understood to be the
        reference against which a sample colour is compared.
    -   Parametric factors :math:`k_L=k_C=k_H=1` weights under
        *reference conditions*:

        -   Illumination: D65 source
        -   Illuminance: 1000 lx
        -   Observer: Normal colour vision
        -   Background field: Uniform, neutral gray with :math:`L^*=50`
        -   Viewing mode: Object
        -   Sample size: Greater than 4 degrees
        -   Sample separation: Direct edge contact
        -   Sample colour-difference magnitude: Lower than 5.0
            :math:`\\Delta E_{00}`
        -   Sample structure: Homogeneous (without texture)

    References
    ----------
    :cite:`Lindbloom2009e`, :cite:`Melgosa2013b`

    Examples
    --------
    >>> Lab_1 = np.array([100.00000000, 21.57210357, 272.22819350])
    >>> Lab_2 = np.array([100.00000000, 426.67945353, 72.39590835])
    >>> delta_E_CIE2000(Lab_1, Lab_2)  # doctest: +ELLIPSIS
    94.0356490...
    >>> Lab_2 = np.array([50.00000000, 426.67945353, 72.39590835])
    >>> delta_E_CIE2000(Lab_1, Lab_2)  # doctest: +ELLIPSIS
    100.8779470...
    >>> delta_E_CIE2000(Lab_1, Lab_2, textiles=True)  # doctest: +ELLIPSIS
    95.7920535...
    """

    L_1, a_1, b_1 = tsplit(to_domain_100(Lab_1))
    L_2, a_2, b_2 = tsplit(to_domain_100(Lab_2))

    k_L = 2 if textiles else 1
    k_C = 1
    k_H = 1

    l_bar_prime = 0.5 * (L_1 + L_2)

    c_1 = np.hypot(a_1, b_1)
    c_2 = np.hypot(a_2, b_2)

    c_bar = 0.5 * (c_1 + c_2)
    c_bar7 = c_bar ** 7

    g = 0.5 * (1 - np.sqrt(c_bar7 / (c_bar7 + 25 ** 7)))

    a_1_prime = a_1 * (1 + g)
    a_2_prime = a_2 * (1 + g)
    c_1_prime = np.hypot(a_1_prime, b_1)
    c_2_prime = np.hypot(a_2_prime, b_2)
    c_bar_prime = 0.5 * (c_1_prime + c_2_prime)

    h_1_prime = np.degrees(np.arctan2(b_1, a_1_prime)) % 360
    h_2_prime = np.degrees(np.arctan2(b_2, a_2_prime)) % 360

    h_bar_prime = np.where(
        np.fabs(h_1_prime - h_2_prime) <= 180,
        0.5 * (h_1_prime + h_2_prime),
        (0.5 * (h_1_prime + h_2_prime + 360)),
    )

    t = (1 - 0.17 * np.cos(np.deg2rad(h_bar_prime - 30)) +
         0.24 * np.cos(np.deg2rad(2 * h_bar_prime)) +
         0.32 * np.cos(np.deg2rad(3 * h_bar_prime + 6)) -
         0.20 * np.cos(np.deg2rad(4 * h_bar_prime - 63)))

    h = h_2_prime - h_1_prime
    delta_h_prime = np.where(h_2_prime <= h_1_prime, h - 360, h + 360)
    delta_h_prime = np.where(np.fabs(h) <= 180, h, delta_h_prime)

    delta_L_prime = L_2 - L_1
    delta_C_prime = c_2_prime - c_1_prime
    delta_H_prime = (2 * np.sqrt(c_1_prime * c_2_prime) * np.sin(
        np.deg2rad(0.5 * delta_h_prime)))

    s_L = 1 + ((0.015 * (l_bar_prime - 50) * (l_bar_prime - 50)) /
               np.sqrt(20 + (l_bar_prime - 50) * (l_bar_prime - 50)))
    s_C = 1 + 0.045 * c_bar_prime
    s_H = 1 + 0.015 * c_bar_prime * t

    delta_theta = (
        30 * np.exp(-((h_bar_prime - 275) / 25) * ((h_bar_prime - 275) / 25)))

    c_bar_prime7 = c_bar_prime ** 7

    r_C = np.sqrt(c_bar_prime7 / (c_bar_prime7 + 25 ** 7))
    r_T = -2 * r_C * np.sin(np.deg2rad(2 * delta_theta))

    d_E = np.sqrt((delta_L_prime / (k_L * s_L)) ** 2 +
                  (delta_C_prime / (k_C * s_C)) ** 2 +
                  (delta_H_prime / (k_H * s_H)) ** 2 +
                  (delta_C_prime / (k_C * s_C)) * (delta_H_prime /
                                                   (k_H * s_H)) * r_T)

    return d_E
Exemplo n.º 46
0
def Luv_to_XYZ(
        Luv,
        illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65']):
    """
    Converts from *CIE L\\*u\\*v\\** colourspace to *CIE XYZ* tristimulus
    values.

    Parameters
    ----------
    Luv : array_like
        *CIE L\\*u\\*v\\** colourspace array.
    illuminant : array_like, optional
        Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array.

    Returns
    -------
    ndarray
        *CIE XYZ* tristimulus values.

    Notes
    -----

    +----------------+-----------------------+-----------------+
    | **Domain**     | **Scale - Reference** | **Scale - 1**   |
    +================+=======================+=================+
    | ``Luv``        | ``L`` : [0, 100]      | ``L`` : [0, 1]  |
    |                |                       |                 |
    |                | ``u`` : [-100, 100]   | ``u`` : [-1, 1] |
    |                |                       |                 |
    |                | ``v`` : [-100, 100]   | ``v`` : [-1, 1] |
    +----------------+-----------------------+-----------------+
    | ``illuminant`` | [0, 1]                | [0, 1]          |
    +----------------+-----------------------+-----------------+

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

    References
    ----------
    :cite:`CIETC1-482004m`, :cite:`Wikipedia2007b`

    Examples
    --------
    >>> Luv = np.array([41.52787529, 96.83626054, 17.75210149])
    >>> Luv_to_XYZ(Luv)  # doctest: +ELLIPSIS
    array([ 0.2065400...,  0.1219722...,  0.0513695...])
    """

    L, u, v = tsplit(to_domain_100(Luv))

    X_r, Y_r, Z_r = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant)))

    with domain_range_scale('100'):
        Y = luminance_CIE1976(L, Y_r)

    a = 1 / 3 * ((52 * L / (u + 13 * L * (4 * X_r /
                                          (X_r + 15 * Y_r + 3 * Z_r)))) - 1)
    b = -5 * Y
    c = -1 / 3.0
    d = Y * (39 * L / (v + 13 * L * (9 * Y_r /
                                     (X_r + 15 * Y_r + 3 * Z_r))) - 5)

    X = (d - b) / (a - c)
    Z = X * a + b

    XYZ = tstack([X, Y, Z])

    return from_range_1(XYZ)
Exemplo n.º 47
0
def XYZ_to_Nayatani95(XYZ, XYZ_n, Y_o, E_o, E_or, n=1):
    """
    Computes the *Nayatani (1995)* colour appearance model correlates.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of test sample / stimulus.
    XYZ_n : array_like
        *CIE XYZ* tristimulus values of reference white.
    Y_o : numeric or array_like
        Luminance factor :math:`Y_o` of achromatic background as percentage
        normalised to domain [0.18, 1.0] in **'Reference'** domain-range scale.
    E_o : numeric or array_like
        Illuminance :math:`E_o` of the viewing field in lux.
    E_or : numeric or array_like
        Normalising illuminance :math:`E_{or}` in lux usually normalised to
        domain [1000, 3000].
    n : numeric or array_like, optional
        Noise term used in the non linear chromatic adaptation model.

    Returns
    -------
    Nayatani95_Specification
        *Nayatani (1995)* colour appearance model specification.

    Notes
    -----

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

    +--------------------------------+-----------------------+---------------+
    | **Range**                      | **Scale - Reference** | **Scale - 1** |
    +================================+=======================+===============+
    | ``Nayatani95_Specification.h`` | [0, 360]              | [0, 1]        |
    +--------------------------------+-----------------------+---------------+

    References
    ----------
    :cite:`Fairchild2013ba`, :cite:`Nayatani1995a`

    Examples
    --------
    >>> XYZ = np.array([19.01, 20.00, 21.78])
    >>> XYZ_n = np.array([95.05, 100.00, 108.88])
    >>> Y_o = 20.0
    >>> E_o = 5000.0
    >>> E_or = 1000.0
    >>> XYZ_to_Nayatani95(XYZ, XYZ_n, Y_o, E_o, E_or)  # doctest: +ELLIPSIS
    Nayatani95_Specification(L_star_P=49.9998829..., C=0.0133550..., \
h=257.5232268..., s=0.0133550..., Q=62.6266734..., M=0.0167262..., H=None, \
HC=None, L_star_N=50.0039154...)
    """

    XYZ = to_domain_100(XYZ)
    XYZ_n = to_domain_100(XYZ_n)
    Y_o = as_float_array(Y_o)
    E_o = as_float_array(E_o)
    E_or = as_float_array(E_or)

    # Computing adapting luminance :math:`L_o` and normalising luminance
    # :math:`L_{or}` in in :math:`cd/m^2`.
    # L_o = illuminance_to_luminance(E_o, Y_o)
    L_or = illuminance_to_luminance(E_or, Y_o)

    # Computing :math:`\\xi` :math:`\\eta`, :math:`\\zeta` values.
    xez = intermediate_values(XYZ_to_xy(XYZ_n / 100))
    xi, eta, _zeta = tsplit(xez)

    # Computing adapting field cone responses.
    RGB_o = (((Y_o[..., np.newaxis] * E_o[..., np.newaxis]) /
              (100 * np.pi)) * xez)

    # Computing stimulus cone responses.
    RGB = XYZ_to_RGB_Nayatani95(XYZ)
    R, G, _B = tsplit(RGB)

    # Computing exponential factors of the chromatic adaptation.
    bRGB_o = exponential_factors(RGB_o)
    bL_or = beta_1(L_or)

    # Computing scaling coefficients :math:`e(R)` and :math:`e(G)`
    eR = scaling_coefficient(R, xi)
    eG = scaling_coefficient(G, eta)

    # Computing opponent colour dimensions.
    # Computing achromatic response :math:`Q`:
    Q_response = achromatic_response(RGB, bRGB_o, xez, bL_or, eR, eG, n)

    # Computing tritanopic response :math:`t`:
    t_response = tritanopic_response(RGB, bRGB_o, xez, n)

    # Computing protanopic response :math:`p`:
    p_response = protanopic_response(RGB, bRGB_o, xez, n)

    # Computing the correlate of *brightness* :math:`B_r`.
    B_r = brightness_correlate(bRGB_o, bL_or, Q_response)

    # Computing *brightness* :math:`B_{rw}` of ideal white.
    brightness_ideal_white = ideal_white_brightness_correlate(
        bRGB_o, xez, bL_or, n)

    # Computing the correlate of achromatic *Lightness* :math:`L_p^\\star`.
    L_star_P = (achromatic_lightness_correlate(Q_response))

    # Computing the correlate of normalised achromatic *Lightness*
    # :math:`L_n^\\star`.
    L_star_N = (normalised_achromatic_lightness_correlate(
        B_r, brightness_ideal_white))

    # Computing the *hue* angle :math:`\\theta`.
    theta = hue_angle(p_response, t_response)
    # TODO: Implement hue quadrature & composition computation.

    # Computing the correlate of *saturation* :math:`S`.
    S_RG, S_YB = tsplit(
        saturation_components(theta, bL_or, t_response, p_response))
    S = saturation_correlate(S_RG, S_YB)

    # Computing the correlate of *chroma* :math:`C`.
    # C_RG, C_YB = tsplit(chroma_components(L_star_P, S_RG, S_YB))
    C = chroma_correlate(L_star_P, S)

    # Computing the correlate of *colourfulness* :math:`M`.
    # TODO: Investigate components usage.
    # M_RG, M_YB = tsplit(colourfulness_components(C_RG, C_YB,
    # brightness_ideal_white))
    M = colourfulness_correlate(C, brightness_ideal_white)

    return Nayatani95_Specification(L_star_P, C, from_range_degrees(theta), S,
                                    B_r, M, None, None, L_star_N)
Exemplo n.º 48
0
def XYZ_to_ATD95(XYZ, XYZ_0, Y_0, k_1, k_2, sigma=300):
    """
    Computes the *ATD (1995)* colour vision model correlates.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of test sample / stimulus.
    XYZ_0 : array_like
        *CIE XYZ* tristimulus values of reference white.
    Y_0 : numeric or array_like
        Absolute adapting field luminance in :math:`cd/m^2`.
    k_1 : numeric or array_like
        Application specific weight :math:`k_1`.
    k_2 : numeric or array_like
        Application specific weight :math:`k_2`.
    sigma : numeric or array_like, optional
        Constant :math:`\\sigma` varied to predict different types of data.

    Returns
    -------
    CAM_Specification_ATD95
        *ATD (1995)* colour vision model specification.

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

    +-------------------------------+-----------------------+---------------+
    | **Range**                     | **Scale - Reference** | **Scale - 1** |
    +===============================+=======================+===============+
    | ``CAM_Specification_ATD95.h`` | [0, 360]              | [0, 1]        |
    +-------------------------------+-----------------------+---------------+

    -   For unrelated colors, there is only self-adaptation and :math:`k_1` is
        set to 1.0 while :math:`k_2` is set to 0.0. For related colors such as
        typical colorimetric applications, :math:`k_1` is set to 0.0 and
        :math:`k_2` is set to a value between 15 and 50 *(Guth, 1995)*.

    References
    ----------
    :cite:`Fairchild2013v`, :cite:`Guth1995a`

    Examples
    --------
    >>> XYZ = np.array([19.01, 20.00, 21.78])
    >>> XYZ_0 = np.array([95.05, 100.00, 108.88])
    >>> Y_0 = 318.31
    >>> k_1 = 0.0
    >>> k_2 = 50.0
    >>> XYZ_to_ATD95(XYZ, XYZ_0, Y_0, k_1, k_2)  # doctest: +ELLIPSIS
    CAM_Specification_ATD95(h=1.9089869..., C=1.2064060..., Q=0.1814003..., \
A_1=0.1787931... T_1=0.0286942..., D_1=0.0107584..., A_2=0.0192182..., \
T_2=0.0205377..., D_2=0.0107584...)
    """

    XYZ = to_domain_100(XYZ)
    XYZ_0 = to_domain_100(XYZ_0)
    Y_0 = as_float_array(Y_0)
    k_1 = as_float_array(k_1)
    k_2 = as_float_array(k_2)
    sigma = as_float_array(sigma)

    XYZ = luminance_to_retinal_illuminance(XYZ, Y_0)
    XYZ_0 = luminance_to_retinal_illuminance(XYZ_0, Y_0)

    # Computing adaptation model.
    LMS = XYZ_to_LMS_ATD95(XYZ)
    XYZ_a = k_1[..., np.newaxis] * XYZ + k_2[..., np.newaxis] * XYZ_0
    LMS_a = XYZ_to_LMS_ATD95(XYZ_a)

    LMS_g = LMS * (sigma[..., np.newaxis] / (sigma[..., np.newaxis] + LMS_a))

    # Computing opponent colour dimensions.
    A_1, T_1, D_1, A_2, T_2, D_2 = tsplit(opponent_colour_dimensions(LMS_g))

    # Computing the correlate of *brightness* :math:`Br`.
    Br = spow(A_1**2 + T_1**2 + D_1**2, 0.5)

    # Computing the correlate of *saturation* :math:`C`.
    C = spow(T_2**2 + D_2**2, 0.5) / A_2

    # Computing the *hue* :math:`H`. Note that the reference does not take the
    # modulus of the :math:`H`, thus :math:`H` can exceed 360 degrees.
    H = T_2 / D_2

    return CAM_Specification_ATD95(from_range_degrees(H), C, Br, A_1, T_1, D_1,
                                   A_2, T_2, D_2)
Exemplo n.º 49
0
def XYZ_to_CIECAM02(XYZ,
                    XYZ_w,
                    L_A,
                    Y_b,
                    surround=CIECAM02_VIEWING_CONDITIONS['Average'],
                    discount_illuminant=False):
    """
    Computes the *CIECAM02* colour appearance model correlates from given
    *CIE XYZ* tristimulus values.

    This is the *forward* implementation.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of test sample / stimulus.
    XYZ_w : array_like
        *CIE XYZ* tristimulus values of reference white.
    L_A : numeric or array_like
        Adapting field *luminance* :math:`L_A` in :math:`cd/m^2`, (often taken
        to be 20% of the luminance of a white object in the scene).
    Y_b : numeric or array_like
        Relative luminance of background :math:`Y_b` in :math:`cd/m^2`.
    surround : CIECAM02_InductionFactors, optional
        Surround viewing conditions induction factors.
    discount_illuminant : bool, optional
        Truth value indicating if the illuminant should be discounted.

    Returns
    -------
    CIECAM02_Specification
        *CIECAM02* colour appearance model specification.

    Notes
    -----

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

    +------------------------------+-----------------------+---------------+
    | **Range**                    | **Scale - Reference** | **Scale - 1** |
    +==============================+=======================+===============+
    | ``CIECAM02_specification.h`` | [0, 360]              | [0, 1]        |
    +------------------------------+-----------------------+---------------+
    | ``CIECAM02_specification.H`` | [0, 360]              | [0, 1]        |
    +------------------------------+-----------------------+---------------+

    References
    ----------
    :cite:`Fairchild2004c`, :cite:`Luo2013`, :cite:`Moroneya`,
    :cite:`Wikipedia2007a`

    Examples
    --------
    >>> XYZ = np.array([19.01, 20.00, 21.78])
    >>> XYZ_w = np.array([95.05, 100.00, 108.88])
    >>> L_A = 318.31
    >>> Y_b = 20.0
    >>> surround = CIECAM02_VIEWING_CONDITIONS['Average']
    >>> XYZ_to_CIECAM02(XYZ, XYZ_w, L_A, Y_b, surround)  # doctest: +ELLIPSIS
    CIECAM02_Specification(J=41.7310911..., C=0.1047077..., h=219.0484326..., \
s=2.3603053..., Q=195.3713259..., M=0.1088421..., H=278.0607358..., HC=None)
    """

    XYZ = to_domain_100(XYZ)
    XYZ_w = to_domain_100(XYZ_w)
    _X_w, Y_w, _Z_w = tsplit(XYZ_w)
    L_A = as_float_array(L_A)
    Y_b = as_float_array(Y_b)

    n, F_L, N_bb, N_cb, z = tsplit(
        viewing_condition_dependent_parameters(Y_b, Y_w, L_A))

    # Converting *CIE XYZ* tristimulus values to *CMCCAT2000* transform
    # sharpened *RGB* values.
    RGB = dot_vector(CAT02_CAT, XYZ)
    RGB_w = dot_vector(CAT02_CAT, XYZ_w)

    # Computing degree of adaptation :math:`D`.
    D = (degree_of_adaptation(surround.F, L_A)
         if not discount_illuminant else np.ones(L_A.shape))

    # Computing full chromatic adaptation.
    RGB_c = full_chromatic_adaptation_forward(RGB, RGB_w, Y_w, D)
    RGB_wc = full_chromatic_adaptation_forward(RGB_w, RGB_w, Y_w, D)

    # Converting to *Hunt-Pointer-Estevez* colourspace.
    RGB_p = RGB_to_rgb(RGB_c)
    RGB_pw = RGB_to_rgb(RGB_wc)

    # Applying forward post-adaptation non linear response compression.
    RGB_a = post_adaptation_non_linear_response_compression_forward(RGB_p, F_L)
    RGB_aw = post_adaptation_non_linear_response_compression_forward(
        RGB_pw, F_L)

    # Converting to preliminary cartesian coordinates.
    a, b = tsplit(opponent_colour_dimensions_forward(RGB_a))

    # Computing the *hue* angle :math:`h`.
    h = hue_angle(a, b)

    # Computing hue :math:`h` quadrature :math:`H`.
    H = hue_quadrature(h)
    # TODO: Compute hue composition.

    # Computing eccentricity factor *e_t*.
    e_t = eccentricity_factor(h)

    # Computing achromatic responses for the stimulus and the whitepoint.
    A = achromatic_response_forward(RGB_a, N_bb)
    A_w = achromatic_response_forward(RGB_aw, N_bb)

    # Computing the correlate of *Lightness* :math:`J`.
    J = lightness_correlate(A, A_w, surround.c, z)

    # Computing the correlate of *brightness* :math:`Q`.
    Q = brightness_correlate(surround.c, J, A_w, F_L)

    # Computing the correlate of *chroma* :math:`C`.
    C = chroma_correlate(J, n, surround.N_c, N_cb, e_t, a, b, RGB_a)

    # Computing the correlate of *colourfulness* :math:`M`.
    M = colourfulness_correlate(C, F_L)

    # Computing the correlate of *saturation* :math:`s`.
    s = saturation_correlate(M, Q)

    return CIECAM02_Specification(J, C, from_range_degrees(h), s, Q, M,
                                  from_range_degrees(H), None)
Exemplo n.º 50
0
def DIN99_to_Lab(Lab_99, k_E=1, k_CH=1):
    """
    Converts from *DIN99* colourspace to *CIE L\\*a\\*b\\** colourspace.

    Parameters
    ----------
    Lab_99 : array_like
        *DIN99* colourspace array.
    k_E : numeric, optional
        Parametric factor :math:`K_E` used to compensate for texture and other
        specimen presentation effects.
    k_CH : numeric, optional
        Parametric factor :math:`K_{CH}` used to compensate for texture and
        other specimen presentation effects.

    Returns
    -------
    ndarray
        *CIE L\\*a\\*b\\** colourspace array.

    Notes
    -----

    +------------+------------------------+--------------------+
    | **Domain** | **Scale - Reference**  | **Scale - 1**      |
    +============+========================+====================+
    | ``Lab_99`` | ``L_99`` : [0, 100]    | ``L_99`` : [0, 1]  |
    |            |                        |                    |
    |            | ``a_99`` : [-100, 100] | ``a_99`` : [-1, 1] |
    |            |                        |                    |
    |            | ``b_99`` : [-100, 100] | ``b_99`` : [-1, 1] |
    +------------+------------------------+--------------------+

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

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

    Examples
    --------
    >>> import numpy as np
    >>> Lab_99 = np.array([53.22821988, 28.41634656, 3.89839552])
    >>> DIN99_to_Lab(Lab_99)  # doctest: +ELLIPSIS
    array([ 41.5278752...,  52.6385830...,  26.9231792...])
    """

    L_99, a_99, b_99 = tsplit(to_domain_100(Lab_99))

    cos_16 = np.cos(np.radians(16))
    sin_16 = np.sin(np.radians(16))

    h_99 = np.arctan2(b_99, a_99)

    C_99 = np.sqrt(a_99 ** 2 + b_99 ** 2)
    G = (np.exp(0.045 * C_99 * k_CH * k_E) - 1) / 0.045

    e = G * np.cos(h_99)
    f = G * np.sin(h_99)

    a = e * cos_16 - (f / 0.7) * sin_16
    b = e * sin_16 + (f / 0.7) * cos_16
    L = (np.exp(L_99 * k_E / 105.509) - 1) / 0.0158

    Lab = tstack([L, a, b])

    return from_range_100(Lab)
Exemplo n.º 51
0
def chromatic_adaptation_Zhai2018(
    XYZ_b: ArrayLike,
    XYZ_wb: ArrayLike,
    XYZ_wd: ArrayLike,
    D_b: FloatingOrArrayLike = 1,
    D_d: FloatingOrArrayLike = 1,
    XYZ_wo: ArrayLike = np.array([1, 1, 1]),
    transform: Union[Literal["CAT02", "CAT16"], str] = "CAT02",
) -> NDArray:
    """
    Adapt given sample colour :math:`XYZ_{\\beta}` tristimulus values from
    input viewing conditions under :math:`\\beta` illuminant to output viewing
    conditions under :math:`\\delta` illuminant using *Zhai and Luo (2018)*
    chromatic adaptation model.

    According to the definition of :math:`D`, a one-step CAT such as CAT02 can
    only be used to transform colors from an incomplete adapted field into a
    complete adapted field. When CAT02 are used to transform an incomplete to
    incomplete case, :math:`D` has no baseline level to refer to.
    *Smet et al. (2017)* proposed a new concept of two-step CAT to replace the
    present CATs such as CAT02 with only one-step transform in order to define
    :math:`D` more clearly. A two-step CAT involves an illuminant representing
    the baseline states between the test and reference illuminants for the
    calculation. In the first step the test color is transformed from test
    illuminant to the baseline illuminant (:math:`BI`), and it is then
    transformed to the reference illuminant Degrees of adaptation under the
    other illuminants should be calculated relative to the adaptation under the
    :math:`BI`. When :math:`D` becomes lower towards zero, the adaptation point
    of the observer moves towards the :math:`BI`. Therefore, the chromaticity
    of the :math:`BI` should be an intrinsic property of the human vision
    system.

    Parameters
    ----------
    XYZ_b
        Sample colour :math:`XYZ_{\\beta}` under input illuminant
        :math:`\\beta`.
    XYZ_wb
        Input illuminant :math:`\\beta`.
    XYZ_wd
        Output illuminant :math:`\\delta`.
    D_b
        Degree of adaptation :math:`D_{\\beta}` of input illuminant
        :math:`\\beta`.
    D_d
        Degree of adaptation :math:`D_{\\delta}` of output illuminant
        :math:`\\delta`.
    XYZ_wo
        Baseline illuminant (:math:`BI`) :math:`o`.
    transform
        Chromatic adaptation transform.

    Returns
    -------
    :class:`numpy.ndarray`
        Sample corresponding colour :math:`XYZ_{\\delta}` tristimulus values
        under output illuminant :math:`D_{\\delta}`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``XYZ_b``  | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_wb`` | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_wd`` | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_wo`` | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

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

    References
    ----------
    :cite:`Zhai2018`

    Examples
    --------
    >>> XYZ_b = np.array([48.900, 43.620, 6.250])
    >>> XYZ_wb = np.array([109.850, 100, 35.585])
    >>> XYZ_wd = np.array([95.047, 100, 108.883])
    >>> D_b = 0.9407
    >>> D_d = 0.9800
    >>> XYZ_wo = np.array([100, 100, 100])
    >>> chromatic_adaptation_Zhai2018(
    ...     XYZ_b, XYZ_wb, XYZ_wd, D_b, D_d, XYZ_wo)  # doctest: +ELLIPSIS
    array([ 39.1856164...,  42.1546179...,  19.2367203...])
    >>> XYZ_d = np.array([39.18561644, 42.15461798, 19.23672036])
    >>> chromatic_adaptation_Zhai2018(
    ...     XYZ_d, XYZ_wd, XYZ_wb, D_d, D_b, XYZ_wo)  # doctest: +ELLIPSIS
    array([ 48.9 ,  43.62,   6.25])
    """

    XYZ_b = to_domain_100(XYZ_b)
    XYZ_wb = to_domain_100(XYZ_wb)
    XYZ_wd = to_domain_100(XYZ_wd)
    XYZ_wo = to_domain_100(XYZ_wo)
    D_b = as_float_array(D_b)
    D_d = as_float_array(D_d)

    Y_wb = XYZ_wb[..., 1][..., np.newaxis]
    Y_wd = XYZ_wd[..., 1][..., np.newaxis]
    Y_wo = XYZ_wo[..., 1][..., np.newaxis]

    transform = validate_method(transform, ["CAT02", "CAT16"])
    M = CHROMATIC_ADAPTATION_TRANSFORMS[transform]

    RGB_b = vector_dot(M, XYZ_b)
    RGB_wb = vector_dot(M, XYZ_wb)
    RGB_wd = vector_dot(M, XYZ_wd)
    RGB_wo = vector_dot(M, XYZ_wo)

    D_RGB_b = D_b * (Y_wb / Y_wo) * (RGB_wo / RGB_wb) + 1 - D_b
    D_RGB_d = D_d * (Y_wd / Y_wo) * (RGB_wo / RGB_wd) + 1 - D_d

    D_RGB = D_RGB_b / D_RGB_d

    RGB_d = D_RGB * RGB_b

    XYZ_d = vector_dot(np.linalg.inv(M), RGB_d)

    return from_range_100(XYZ_d)
Exemplo n.º 52
0
def hdr_IPT_to_XYZ(IPT_hdr, Y_s=0.2, Y_abs=100, method='Fairchild 2011'):
    """
    Converts from *hdr-IPT* colourspace to *CIE XYZ* tristimulus values.

    Parameters
    ----------
    IPT_hdr : array_like
        *hdr-IPT* colourspace array.
    Y_s : numeric or array_like
        Relative luminance :math:`Y_s` of the surround.
    Y_abs : numeric or array_like
        Absolute luminance :math:`Y_{abs}` of the scene diffuse white in
        :math:`cd/m^2`.
    method : unicode, optional
        **{'Fairchild 2011', 'Fairchild 2010'}**,
        Computation method.

    Returns
    -------
    ndarray
        *CIE XYZ* tristimulus values.

    Notes
    -----

    +-------------+-------------------------+---------------------+
    | **Domain**  | **Scale - Reference**   | **Scale - 1**       |
    +=============+=========================+=====================+
    | ``IPT_hdr`` | ``I_hdr`` : [0, 100]    | ``I_hdr`` : [0, 1]  |
    |             |                         |                     |
    |             | ``P_hdr`` : [-100, 100] | ``P_hdr`` : [-1, 1] |
    |             |                         |                     |
    |             | ``T_hdr`` : [-100, 100] | ``T_hdr`` : [-1, 1] |
    +-------------+-------------------------+---------------------+
    | ``Y_s``     | [0, 1]                  | [0, 1]              |
    +-------------+-------------------------+---------------------+

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

    References
    ----------
    :cite:`Fairchild2010`, :cite:`Fairchild2011`

    Examples
    --------
    >>> IPT_hdr = np.array([48.39376346, 42.44990202, 22.01954033])
    >>> hdr_IPT_to_XYZ(IPT_hdr)  # doctest: +ELLIPSIS
    array([ 0.2065400...,  0.1219722...,  0.0513695...])
    >>> IPT_hdr = np.array([30.02873147, 83.93845061, 34.90287382])
    >>> hdr_IPT_to_XYZ(IPT_hdr, method='Fairchild 2010')
    ... # doctest: +ELLIPSIS
    array([ 0.2065400...,  0.1219722...,  0.0513695...])
    """

    IPT_hdr = to_domain_100(IPT_hdr)

    method_l = method.lower()
    assert method.lower() in [
        m.lower() for m in HDR_IPT_METHODS
    ], ('"{0}" method is invalid, must be one of {1}!'.format(
        method, HDR_IPT_METHODS))

    if method_l == 'fairchild 2010':
        luminance_callable = luminance_Fairchild2010
    else:
        luminance_callable = luminance_Fairchild2011

    e = exponent_hdr_IPT(Y_s, Y_abs, method)[..., np.newaxis]

    LMS = dot_vector(IPT_IPT_TO_LMS_MATRIX, IPT_hdr)

    # Domain and range scaling has already be handled.
    with domain_range_scale('ignore'):
        LMS_prime = np.sign(LMS) * np.abs(luminance_callable(LMS, e))

    XYZ = dot_vector(IPT_LMS_TO_XYZ_MATRIX, LMS_prime)

    return from_range_1(XYZ)
Exemplo n.º 53
0
def CIECAM02_to_XYZ(CIECAM02_specification,
                    XYZ_w,
                    L_A,
                    Y_b,
                    surround=CIECAM02_VIEWING_CONDITIONS['Average'],
                    discount_illuminant=False):
    """
    Converts *CIECAM02* specification to *CIE XYZ* tristimulus values.

    This is the *reverse* implementation.

    Parameters
    ----------
    CIECAM02_specification : CIECAM02_Specification
        *CIECAM02* colour appearance model specification. Correlate of
        *Lightness* :math:`J`, correlate of *chroma* :math:`C` or correlate of
        *colourfulness* :math:`M` and *hue* angle :math:`h` in degrees must be
        specified, e.g. :math:`JCh` or :math:`JMh`.
    XYZ_w : array_like
        *CIE XYZ* tristimulus values of reference white.
    L_A : numeric or array_like
        Adapting field *luminance* :math:`L_A` in :math:`cd/m^2`, (often taken
        to be 20% of the luminance of a white object in the scene).
    Y_b : numeric or array_like
        Relative luminance of background :math:`Y_b` in :math:`cd/m^2`.
    surround : CIECAM02_InductionFactors, optional
        Surround viewing conditions.
    discount_illuminant : bool, optional
        Discount the illuminant.

    Returns
    -------
    XYZ : ndarray
        *CIE XYZ* tristimulus values.

    Raises
    ------
    ValueError
        If neither *C* or *M* correlates have been defined in the
        ``CIECAM02_specification`` argument.

    Warning
    -------
    The output range of that definition is non standard!

    Notes
    -----

    +------------------------------+-----------------------+---------------+
    | **Domain**                   | **Scale - Reference** | **Scale - 1** |
    +==============================+=======================+===============+
    | ``CIECAM02_specification.h`` | [0, 360]              | [0, 1]        |
    +------------------------------+-----------------------+---------------+
    | ``CIECAM02_specification.H`` | [0, 360]              | [0, 1]        |
    +------------------------------+-----------------------+---------------+
    | ``XYZ_w``                    | [0, 100]              | [0, 1]        |
    +------------------------------+-----------------------+---------------+

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

    -   ``CIECAM02_specification`` can also be passed as a compatible argument
        to :func:`colour.utilities.as_namedtuple` definition.

    References
    ----------
    :cite:`Fairchild2004c`, :cite:`Luo2013`, :cite:`Moroneya`,
    :cite:`Wikipedia2007a`

    Examples
    --------
    >>> specification = CIECAM02_Specification(J=41.731091132513917,
    ...                                        C=0.104707757171031,
    ...                                        h=219.048432658311780)
    >>> XYZ_w = np.array([95.05, 100.00, 108.88])
    >>> L_A = 318.31
    >>> Y_b = 20.0
    >>> CIECAM02_to_XYZ(specification, XYZ_w, L_A, Y_b)  # doctest: +ELLIPSIS
    array([ 19.01...,  20...  ,  21.78...])
    """

    J, C, h, _s, _Q, M, _H, _HC = as_namedtuple(CIECAM02_specification,
                                                CIECAM02_Specification)
    L_A = as_float_array(L_A)

    h = to_domain_degrees(h)
    XYZ_w = to_domain_100(XYZ_w)
    _X_w, Y_w, _Z_w = tsplit(XYZ_w)

    n, F_L, N_bb, N_cb, z = tsplit(
        viewing_condition_dependent_parameters(Y_b, Y_w, L_A))

    if C is None and M is not None:
        C = M / spow(F_L, 0.25)
    elif C is None:
        raise ValueError('Either "C" or "M" correlate must be defined in '
                         'the "CIECAM02_specification" argument!')

    # Converting *CIE XYZ* tristimulus values to *CMCCAT2000* transform
    # sharpened *RGB* values.
    RGB_w = dot_vector(CAT02_CAT, XYZ_w)

    # Computing degree of adaptation :math:`D`.
    D = (degree_of_adaptation(surround.F, L_A)
         if not discount_illuminant else np.ones(L_A.shape))

    # Computing full chromatic adaptation.
    RGB_wc = full_chromatic_adaptation_forward(RGB_w, RGB_w, Y_w, D)

    # Converting to *Hunt-Pointer-Estevez* colourspace.
    RGB_pw = RGB_to_rgb(RGB_wc)

    # Applying post-adaptation non linear response compression.
    RGB_aw = post_adaptation_non_linear_response_compression_forward(
        RGB_pw, F_L)

    # Computing achromatic response for the whitepoint.
    A_w = achromatic_response_forward(RGB_aw, N_bb)

    # Computing temporary magnitude quantity :math:`t`.
    t = temporary_magnitude_quantity_reverse(C, J, n)

    # Computing eccentricity factor *e_t*.
    e_t = eccentricity_factor(h)

    # Computing achromatic response :math:`A` for the stimulus.
    A = achromatic_response_reverse(A_w, J, surround.c, z)

    # Computing *P_1* to *P_3*.
    P_n = P(surround.N_c, N_cb, e_t, t, A, N_bb)
    _P_1, P_2, _P_3 = tsplit(P_n)

    # Computing opponent colour dimensions :math:`a` and :math:`b`.
    a, b = tsplit(opponent_colour_dimensions_reverse(P_n, h))

    # Computing post-adaptation non linear response compression matrix.
    RGB_a = post_adaptation_non_linear_response_compression_matrix(P_2, a, b)

    # Applying reverse post-adaptation non linear response compression.
    RGB_p = post_adaptation_non_linear_response_compression_reverse(RGB_a, F_L)

    # Converting to *Hunt-Pointer-Estevez* colourspace.
    RGB_c = rgb_to_RGB(RGB_p)

    # Applying reverse full chromatic adaptation.
    RGB = full_chromatic_adaptation_reverse(RGB_c, RGB_w, Y_w, D)

    # Converting *CMCCAT2000* transform sharpened *RGB* values to *CIE XYZ*
    # tristimulus values.
    XYZ = dot_vector(CAT02_INVERSE_CAT, RGB)

    return from_range_100(XYZ)
Exemplo n.º 54
0
def chromatic_adaptation_forward_CMCCAT2000(
        XYZ,
        XYZ_w,
        XYZ_wr,
        L_A1,
        L_A2,
        surround=CMCCAT2000_VIEWING_CONDITIONS['Average']):
    """
    Adapts given stimulus *CIE XYZ* tristimulus values from test viewing
    conditions to reference viewing conditions using *CMCCAT2000* forward
    chromatic adaptation model.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of the 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.
    L_A1 : numeric or array_like
        Luminance of test adapting field :math:`L_{A1}` in :math:`cd/m^2`.
    L_A2 : numeric or array_like
        Luminance of reference adapting field :math:`L_{A2}` in :math:`cd/m^2`.
    surround : CMCCAT2000_InductionFactors, optional
        Surround viewing conditions induction factors.

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

    Notes
    -----

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

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

    References
    ----------
    :cite:`Li2002a`, :cite:`Westland2012k`

    Examples
    --------
    >>> XYZ = np.array([22.48, 22.74, 8.54])
    >>> XYZ_w = np.array([111.15, 100.00, 35.20])
    >>> XYZ_wr = np.array([94.81, 100.00, 107.30])
    >>> L_A1 = 200
    >>> L_A2 = 200
    >>> chromatic_adaptation_forward_CMCCAT2000(XYZ, XYZ_w, XYZ_wr, L_A1, L_A2)
    ... # doctest: +ELLIPSIS
    array([ 19.5269832...,  23.0683396...,  24.9717522...])
    """

    XYZ = to_domain_100(XYZ)
    XYZ_w = to_domain_100(XYZ_w)
    XYZ_wr = to_domain_100(XYZ_wr)
    L_A1 = as_float_array(L_A1)
    L_A2 = as_float_array(L_A2)

    RGB = dot_vector(CMCCAT2000_CAT, XYZ)
    RGB_w = dot_vector(CMCCAT2000_CAT, XYZ_w)
    RGB_wr = dot_vector(CMCCAT2000_CAT, XYZ_wr)

    D = (surround.F * (0.08 * np.log10(0.5 * (L_A1 + L_A2)) + 0.76 - 0.45 *
                       (L_A1 - L_A2) / (L_A1 + L_A2)))

    D = np.clip(D, 0, 1)
    a = D * XYZ_w[..., 1] / XYZ_wr[..., 1]

    RGB_c = (
        RGB * (a[..., np.newaxis] * (RGB_wr / RGB_w) + 1 - D[..., np.newaxis]))
    XYZ_c = dot_vector(CMCCAT2000_INVERSE_CAT, RGB_c)

    return from_range_100(XYZ_c)
Exemplo n.º 55
0
def hdr_IPT_to_XYZ(IPT_hdr, Y_s=0.2, Y_abs=100, method='Fairchild 2011'):
    """
    Converts from *hdr-IPT* colourspace to *CIE XYZ* tristimulus values.

    Parameters
    ----------
    IPT_hdr : array_like
        *hdr-IPT* colourspace array.
    Y_s : numeric or array_like
        Relative luminance :math:`Y_s` of the surround.
    Y_abs : numeric or array_like
        Absolute luminance :math:`Y_{abs}` of the scene diffuse white in
        :math:`cd/m^2`.
    method : unicode, optional
        **{'Fairchild 2011', 'Fairchild 2010'}**,
        Computation method.

    Returns
    -------
    ndarray
        *CIE XYZ* tristimulus values.

    Notes
    -----

    +-------------+-------------------------+---------------------+
    | **Domain**  | **Scale - Reference**   | **Scale - 1**       |
    +=============+=========================+=====================+
    | ``IPT_hdr`` | ``I_hdr`` : [0, 100]    | ``I_hdr`` : [0, 1]  |
    |             |                         |                     |
    |             | ``P_hdr`` : [-100, 100] | ``P_hdr`` : [-1, 1] |
    |             |                         |                     |
    |             | ``T_hdr`` : [-100, 100] | ``T_hdr`` : [-1, 1] |
    +-------------+-------------------------+---------------------+
    | ``Y_s``     | [0, 1]                  | [0, 1]              |
    +-------------+-------------------------+---------------------+

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

    References
    ----------
    :cite:`Fairchild2010`, :cite:`Fairchild2011`

    Examples
    --------
    >>> IPT_hdr = np.array([48.39376346, 42.44990202, 22.01954033])
    >>> hdr_IPT_to_XYZ(IPT_hdr)  # doctest: +ELLIPSIS
    array([ 0.2065400...,  0.1219722...,  0.0513695...])
    >>> IPT_hdr = np.array([30.02873147, 83.93845061, 34.90287382])
    >>> hdr_IPT_to_XYZ(IPT_hdr, method='Fairchild 2010')
    ... # doctest: +ELLIPSIS
    array([ 0.2065400...,  0.1219722...,  0.0513695...])
    """

    IPT_hdr = to_domain_100(IPT_hdr)

    method_l = method.lower()
    assert method.lower() in [
        m.lower() for m in HDR_IPT_METHODS
    ], ('"{0}" method is invalid, must be one of {1}!'.format(
        method, HDR_IPT_METHODS))

    if method_l == 'fairchild 2010':
        luminance_callable = luminance_Fairchild2010
    else:
        luminance_callable = luminance_Fairchild2011

    e = exponent_hdr_IPT(Y_s, Y_abs, method)[..., np.newaxis]

    LMS = dot_vector(IPT_IPT_TO_LMS_MATRIX, IPT_hdr)

    # Domain and range scaling has already be handled.
    with domain_range_scale('ignore'):
        LMS_prime = np.sign(LMS) * np.abs(luminance_callable(LMS, e))

    XYZ = dot_vector(IPT_LMS_TO_XYZ_MATRIX, LMS_prime)

    return from_range_1(XYZ)
Exemplo n.º 56
0
def OSA_UCS_to_XYZ(Ljg, optimisation_parameters=None):
    """
    Converts from *OSA UCS* colourspace to *CIE XYZ* tristimulus values under
    the *CIE 1964 10 Degree Standard Observer*.

    Parameters
    ----------
    Ljg : array_like
        *OSA UCS* :math:`Ljg` lightness, jaune (yellowness), and greenness.
    optimisation_parameters : dict_like, optional
        Parameters for :func:`scipy.optimize.fmin` definition.

    Returns
    -------
    ndarray
        *CIE XYZ* tristimulus values under the
        *CIE 1964 10 Degree Standard Observer*.

    Warnings
    --------
    There is no analytical reverse transformation from *OSA UCS* to :math:`Ljg`
    lightness, jaune (yellowness), and greenness to *CIE XYZ* tristimulus
    values, the current implementation relies on optimization using
    :func:`scipy.optimize.fmin` definition and thus has reduced precision and
    poor performance.

    Notes
    -----

    +------------+-----------------------+--------------------+
    | **Domain** | **Scale - Reference** | **Scale - 1**      |
    +============+=======================+====================+
    | ``Ljg``    | ``L`` : [-100, 100]   | ``L`` : [-1, 1]    |
    |            |                       |                    |
    |            | ``j`` : [-100, 100]   | ``j`` : [-1, 1]    |
    |            |                       |                    |
    |            | ``g`` : [-100, 100]   | ``g`` : [-1, 1]    |
    +------------+-----------------------+--------------------+

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

    -   *OSA UCS* uses the *CIE 1964 10 Degree Standard Observer*.

    References
    ----------
    :cite:`Cao2013`, :cite:`Moroney2003`

    Examples
    --------
    >>> import numpy as np
    >>> Ljg = np.array([-3.00499790, 2.99713697, -9.66784231])
    >>> OSA_UCS_to_XYZ(Ljg)  # doctest: +ELLIPSIS
    array([ 20.6540240...,  12.1972369...,   5.1369372...])
    """

    Ljg = to_domain_100(Ljg)
    shape = Ljg.shape
    Ljg = np.atleast_1d(Ljg.reshape([-1, 3]))

    optimisation_settings = {'disp': False}
    if optimisation_parameters is not None:
        optimisation_settings.update(optimisation_parameters)

    def error_function(XYZ, Ljg):
        """
        Error function.
        """

        # Error must be computed in "reference" domain and range.
        with domain_range_scale('ignore'):
            error = np.linalg.norm(XYZ_to_OSA_UCS(XYZ) - Ljg)

        return error

    x_0 = np.array([30, 30, 30])
    XYZ = np.array([
        fmin(error_function, x_0, (Ljg_i, ), **optimisation_settings)
        for Ljg_i in Ljg
    ])

    return from_range_100(XYZ.reshape(shape))
Exemplo n.º 57
0
def chromatic_adaptation_Fairchild1990(
    XYZ_1: ArrayLike,
    XYZ_n: ArrayLike,
    XYZ_r: ArrayLike,
    Y_n: FloatingOrArrayLike,
    discount_illuminant: Boolean = False,
) -> NDArray:
    """
    Adapt given stimulus *CIE XYZ_1* tristimulus values from test viewing
    conditions to reference viewing conditions using *Fairchild (1990)*
    chromatic adaptation model.

    Parameters
    ----------
    XYZ_1
        *CIE XYZ_1* tristimulus values of test sample / stimulus.
    XYZ_n
        Test viewing condition *CIE XYZ_n* tristimulus values of whitepoint.
    XYZ_r
        Reference viewing condition *CIE XYZ_r* tristimulus values of
        whitepoint.
    Y_n
        Luminance :math:`Y_n` of test adapting stimulus in :math:`cd/m^2`.
    discount_illuminant
        Truth value indicating if the illuminant should be discounted.

    Returns
    -------
    :class:`numpy.ndarray`
        Adapted *CIE XYZ_2* tristimulus values of stimulus.

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

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

    References
    ----------
    :cite:`Fairchild1991a`, :cite:`Fairchild2013s`

    Examples
    --------
    >>> XYZ_1 = np.array([19.53, 23.07, 24.97])
    >>> XYZ_n = np.array([111.15, 100.00, 35.20])
    >>> XYZ_r = np.array([94.81, 100.00, 107.30])
    >>> Y_n = 200
    >>> chromatic_adaptation_Fairchild1990(XYZ_1, XYZ_n, XYZ_r, Y_n)
    ... # doctest: +ELLIPSIS
    array([ 23.3252634...,  23.3245581...,  76.1159375...])
    """

    XYZ_1 = to_domain_100(XYZ_1)
    XYZ_n = to_domain_100(XYZ_n)
    XYZ_r = to_domain_100(XYZ_r)
    Y_n = as_float_array(Y_n)

    LMS_1 = vector_dot(MATRIX_XYZ_TO_RGB_FAIRCHILD1990, XYZ_1)
    LMS_n = vector_dot(MATRIX_XYZ_TO_RGB_FAIRCHILD1990, XYZ_n)
    LMS_r = vector_dot(MATRIX_XYZ_TO_RGB_FAIRCHILD1990, XYZ_r)

    p_LMS = degrees_of_adaptation(
        LMS_1, Y_n, discount_illuminant=discount_illuminant
    )

    a_LMS_1 = p_LMS / LMS_n
    a_LMS_2 = p_LMS / LMS_r

    A_1 = row_as_diagonal(a_LMS_1)
    A_2 = row_as_diagonal(a_LMS_2)

    LMSp_1 = vector_dot(A_1, LMS_1)

    c = 0.219 - 0.0784 * np.log10(Y_n)
    C = row_as_diagonal(tstack([c, c, c]))

    LMS_a = vector_dot(C, LMSp_1)
    LMSp_2 = vector_dot(np.linalg.inv(C), LMS_a)

    LMS_c = vector_dot(np.linalg.inv(A_2), LMSp_2)
    XYZ_c = vector_dot(MATRIX_RGB_TO_XYZ_FAIRCHILD1990, LMS_c)

    return from_range_100(XYZ_c)
Exemplo n.º 58
0
def XYZ_to_OSA_UCS(XYZ):
    """
    Converts from *CIE XYZ* tristimulus values under the
    *CIE 1964 10 Degree Standard Observer* to *OSA UCS* colourspace.

    The lightness axis, *L* is usually in range [-9, 5] and centered around
    middle gray (Munsell N/6). The yellow-blue axis, *j* is usually in range
    [-15, 15]. The red-green axis, *g* is usually in range [-20, 15].

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values under the
        *CIE 1964 10 Degree Standard Observer*.

    Returns
    -------
    ndarray
        *OSA UCS* :math:`Ljg` lightness, jaune (yellowness), and greenness.

    Notes
    -----

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

    +------------+-----------------------+--------------------+
    | **Range**  | **Scale - Reference** | **Scale - 1**      |
    +============+=======================+====================+
    | ``Ljg``    | ``L`` : [-100, 100]   | ``L`` : [-1, 1]    |
    |            |                       |                    |
    |            | ``j`` : [-100, 100]   | ``j`` : [-1, 1]    |
    |            |                       |                    |
    |            | ``g`` : [-100, 100]   | ``g`` : [-1, 1]    |
    +------------+-----------------------+--------------------+

    -   *OSA UCS* uses the *CIE 1964 10 Degree Standard Observer*.

    References
    ----------
    :cite:`Cao2013`, :cite:`Moroney2003`

    Examples
    --------
    >>> import numpy as np
    >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) * 100
    >>> XYZ_to_OSA_UCS(XYZ)  # doctest: +ELLIPSIS
    array([-3.0049979...,  2.9971369..., -9.6678423...])
    """

    XYZ = to_domain_100(XYZ)
    x, y, Y = tsplit(XYZ_to_xyY(XYZ))

    Y_0 = Y * (4.4934 * x ** 2 + 4.3034 * y ** 2 - 4.276 * x * y - 1.3744 * x -
               2.5643 * y + 1.8103)

    o_3 = 1 / 3
    Y_0_es = spow(Y_0, o_3) - 2 / 3
    # Gracefully handles Y_0 < 30.
    Y_0_s = Y_0 - 30
    Lambda = 5.9 * (Y_0_es + 0.042 * spow(Y_0_s, o_3))

    RGB = dot_vector(M_XYZ_TO_RGB_OSA_UCS, XYZ)
    RGB_3 = spow(RGB, 1 / 3)

    C = Lambda / (5.9 * Y_0_es)
    L = (Lambda - 14.4) / spow(2, 1 / 2)
    j = C * np.dot(RGB_3, np.array([1.7, 8, -9.7]))
    g = C * np.dot(RGB_3, np.array([-13.7, 17.7, -4]))

    Ljg = tstack([L, j, g])

    return from_range_100(Ljg)
Exemplo n.º 59
0
def delta_E_CIE1994(Lab_1, Lab_2, textiles=False):
    """
    Returns the difference :math:`\\Delta E_{94}` between two given
    *CIE L\\*a\\*b\\** colourspace arrays using *CIE 1994* recommendation.

    Parameters
    ----------
    Lab_1 : array_like
        *CIE L\\*a\\*b\\** colourspace array 1.
    Lab_2 : array_like
        *CIE L\\*a\\*b\\** colourspace array 2.
    textiles : bool, optional
        Textiles application specific parametric factors
        :math:`k_L=2,\\ k_C=k_H=1,\\ k_1=0.048,\\ k_2=0.014` weights are used
        instead of :math:`k_L=k_C=k_H=1,\\ k_1=0.045,\\ k_2=0.015`.

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

    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] |
    +------------+-----------------------+-------------------+

    -   *CIE 1994* colour differences are not symmetrical: difference between
        ``Lab_1`` and ``Lab_2`` may not be the same as difference between
        ``Lab_2`` and ``Lab_1`` thus one colour must be understood to be the
        reference against which a sample colour is compared.

    References
    ----------
    :cite:`Lindbloom2011a`

    Examples
    --------
    >>> Lab_1 = np.array([100.00000000, 21.57210357, 272.22819350])
    >>> Lab_2 = np.array([100.00000000, 426.67945353, 72.39590835])
    >>> delta_E_CIE1994(Lab_1, Lab_2)  # doctest: +ELLIPSIS
    83.7792255...
    >>> delta_E_CIE1994(Lab_1, Lab_2, textiles=True)  # doctest: +ELLIPSIS
    88.3355530...
    """

    L_1, a_1, b_1 = tsplit(to_domain_100(Lab_1))
    L_2, a_2, b_2 = tsplit(to_domain_100(Lab_2))

    k_1 = 0.048 if textiles else 0.045
    k_2 = 0.014 if textiles else 0.015
    k_L = 2 if textiles else 1
    k_C = 1
    k_H = 1

    C_1 = np.hypot(a_1, b_1)
    C_2 = np.hypot(a_2, b_2)

    s_L = 1
    s_C = 1 + k_1 * C_1
    s_H = 1 + k_2 * C_1

    delta_L = L_1 - L_2
    delta_C = C_1 - C_2
    delta_A = a_1 - a_2
    delta_B = b_1 - b_2

    delta_H = np.sqrt(delta_A ** 2 + delta_B ** 2 - delta_C ** 2)

    L = (delta_L / (k_L * s_L)) ** 2
    C = (delta_C / (k_C * s_C)) ** 2
    H = (delta_H / (k_H * s_H)) ** 2

    d_E = np.sqrt(L + C + H)

    return d_E
Exemplo n.º 60
0
def luminance_Fairchild2011(L_hdr, epsilon=0.474, method='hdr-CIELAB'):
    """
    Computes *luminance* :math:`Y` of given *Lightness* :math:`L_{hdr}` using
    *Fairchild and Chen (2011)* method according to *Michealis-Menten*
    kinetics.

    Parameters
    ----------
    L_hdr : array_like
        *Lightness* :math:`L_{hdr}`.
    epsilon : numeric or array_like, optional
        :math:`\\epsilon` exponent.
    method : unicode, optional
        **{'hdr-CIELAB', 'hdr-IPT'}**,
        *Lightness* :math:`L_{hdr}` computation method.

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

    Notes
    -----

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

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

    References
    ----------
    :cite:`Fairchild2011`

    Examples
    --------
    >>> luminance_Fairchild2011(51.852958445912506)  # doctest: +ELLIPSIS
    0.1219722...
    >>> luminance_Fairchild2011(51.643108411718522, method='hdr-IPT')
    ... # doctest: +ELLIPSIS
    0.1219722...
    """

    L_hdr = to_domain_100(L_hdr)

    if method.lower() == 'hdr-cielab':
        maximum_perception = 247
    else:
        maximum_perception = 246

    Y = np.exp(
        np.log(
            substrate_concentration_MichealisMenten(
                L_hdr - 0.02, maximum_perception, 2 ** epsilon)) / epsilon)

    return from_range_1(Y)