Beispiel #1
0
def XYZ_to_LMS_ATD95(XYZ):
    """
    Converts from *CIE XYZ* tristimulus values to *LMS* cone responses.

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

    Returns
    -------
    ndarray
        *LMS* cone responses.

    Examples
    --------
    >>> XYZ = np.array([19.01, 20.00, 21.78])
    >>> XYZ_to_LMS_ATD95(XYZ)  # doctest: +ELLIPSIS
    array([ 6.2283272...,  7.4780666...,  3.8859772...])
    """

    X, Y, Z = tsplit(XYZ)

    L = ((0.66 * (0.2435 * X + 0.8524 * Y - 0.0516 * Z))**0.7) + 0.024
    M = ((-0.3954 * X + 1.1642 * Y + 0.0837 * Z)**0.7) + 0.036
    S = ((0.43 * (0.04 * Y + 0.6225 * Z))**0.7) + 0.31

    LMS = tstack((L, M, S))

    return LMS
Beispiel #2
0
def XYZ_to_LMS_ATD95(XYZ):
    """
    Converts from *CIE XYZ* tristimulus values to *LMS* cone responses.

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

    Returns
    -------
    ndarray
        *LMS* cone responses.

    Examples
    --------
    >>> XYZ = np.array([19.01, 20.00, 21.78])
    >>> XYZ_to_LMS_ATD95(XYZ)  # doctest: +ELLIPSIS
    array([ 6.2283272...,  7.4780666...,  3.8859772...])
    """

    X, Y, Z = tsplit(XYZ)

    L = ((0.66 * (0.2435 * X + 0.8524 * Y - 0.0516 * Z)) ** 0.7) + 0.024
    M = ((-0.3954 * X + 1.1642 * Y + 0.0837 * Z) ** 0.7) + 0.036
    S = ((0.43 * (0.04 * Y + 0.6225 * Z)) ** 0.7) + 0.31

    LMS = tstack((L, M, S))

    return LMS
Beispiel #3
0
def opponent_colour_dimensions(LMS_g):
    """
    Returns opponent colour dimensions from given post adaptation cone signals.

    Parameters
    ----------
    LMS_g : array_like
        Post adaptation cone signals.

    Returns
    -------
    ndarray
        Opponent colour dimensions.

    Examples
    --------
    >>> LMS_g = np.array([6.95457922, 7.08945043, 6.44069316])
    >>> opponent_colour_dimensions(LMS_g)  # doctest: +ELLIPSIS
    array([ 0.1787931...,  0.0286942...,  0.0107584...,  0.0192182...,  0.0205377...,
            0.0107584...])
    """

    L_g, M_g, S_g = tsplit(LMS_g)

    A_1i = 3.57 * L_g + 2.64 * M_g
    T_1i = 7.18 * L_g - 6.21 * M_g
    D_1i = -0.7 * L_g + 0.085 * M_g + S_g
    A_2i = 0.09 * A_1i
    T_2i = 0.43 * T_1i + 0.76 * D_1i
    D_2i = D_1i

    A_1 = final_response(A_1i)
    T_1 = final_response(T_1i)
    D_1 = final_response(D_1i)
    A_2 = final_response(A_2i)
    T_2 = final_response(T_2i)
    D_2 = final_response(D_2i)

    return tstack((A_1, T_1, D_1, A_2, T_2, D_2))
Beispiel #4
0
def opponent_colour_dimensions(LMS_g):
    """
    Returns opponent colour dimensions from given post adaptation cone signals.

    Parameters
    ----------
    LMS_g : array_like
        Post adaptation cone signals.

    Returns
    -------
    ndarray
        Opponent colour dimensions.

    Examples
    --------
    >>> LMS_g = np.array([6.95457922, 7.08945043, 6.44069316])
    >>> opponent_colour_dimensions(LMS_g)  # doctest: +ELLIPSIS
    array([ 0.1787931...,  0.0286942...,  0.0107584...,  0.0192182..., ...])
    """

    L_g, M_g, S_g = tsplit(LMS_g)

    A_1i = 3.57 * L_g + 2.64 * M_g
    T_1i = 7.18 * L_g - 6.21 * M_g
    D_1i = -0.7 * L_g + 0.085 * M_g + S_g
    A_2i = 0.09 * A_1i
    T_2i = 0.43 * T_1i + 0.76 * D_1i
    D_2i = D_1i

    A_1 = final_response(A_1i)
    T_1 = final_response(T_1i)
    D_1 = final_response(D_1i)
    A_2 = final_response(A_2i)
    T_2 = final_response(T_2i)
    D_2 = final_response(D_2i)

    return tstack((A_1, T_1, D_1, A_2, T_2, D_2))
Beispiel #5
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 in domain
        [0, 100].
    XYZ_0 : array_like
        *CIE XYZ* tristimulus values of reference white in domain [0, 100].
    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
    -------
    ATD95_Specification
        ATD (1995) colour vision model specification.

    Warning
    -------
    The input domain of that definition is non standard!

    Notes
    -----
    -   Input *CIE XYZ* tristimulus values are in domain [0, 100].
    -   Input *CIE XYZ_0* tristimulus values are in domain [0, 100].
    -   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)*.

    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
    ATD95_Specification(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...)
    """

    Y_0 = np.asarray(Y_0)
    k_1 = np.asarray(k_1)
    k_2 = np.asarray(k_2)
    sigma = np.asarray(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 = (A_1**2 + T_1**2 + D_1**2)**0.5

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

    # -------------------------------------------------------------------------
    # Computing the *hue* :math:`H`.
    # -------------------------------------------------------------------------
    H = T_2 / D_2

    return ATD95_Specification(H, C, Br, A_1, T_1, D_1, A_2, T_2, D_2)
Beispiel #6
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 in domain
        [0, 100].
    XYZ_0 : array_like
        *CIE XYZ* tristimulus values of reference white in domain [0, 100].
    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
    -------
    ATD95_Specification
        ATD (1995) colour vision model specification.

    Warning
    -------
    The input domain of that definition is non standard!

    Notes
    -----
    -   Input *CIE XYZ* tristimulus values are in domain [0, 100].
    -   Input *CIE XYZ_0* tristimulus values are in domain [0, 100].
    -   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)*.

    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
    ATD95_Specification(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...)
    """

    Y_0 = np.asarray(Y_0)
    k_1 = np.asarray(k_1)
    k_2 = np.asarray(k_2)
    sigma = np.asarray(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 = (A_1 ** 2 + T_1 ** 2 + D_1 ** 2) ** 0.5

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

    # -------------------------------------------------------------------------
    # Computing the *hue* :math:`H`.
    # -------------------------------------------------------------------------
    H = T_2 / D_2

    return ATD95_Specification(H, C, Br, A_1, T_1, D_1, A_2, T_2, D_2)