Source code for colour.adaptation.fairchild1990

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Fairchild (1990) Chromatic Adaptation Model
===========================================

Defines Fairchild (1990) chromatic adaptation model objects:

-   :func:`chromatic_adaptation_Fairchild1990`

See Also
--------
`Fairchild (1990) Chromatic Adaptation Model IPython Notebook
<http://nbviewer.ipython.org/github/colour-science/colour-ipython/blob/master/notebooks/adaptation/fairchild1990.ipynb>`_  # noqa

References
----------
.. [1]  Fairchild, M. D. (1991). Formulation and testing of an
        incomplete-chromatic-adaptation model. Color Research & Application,
        16(4), 243–250. doi:10.1002/col.5080160406
.. [2]  Fairchild, M. D. (2013). FAIRCHILD’S 1990 MODEL. In Color Appearance
        Models (3rd ed., pp. 4418–4495). Wiley. ASIN:B00DAYO8E2
"""

from __future__ import division, unicode_literals

import numpy as np

from colour.adaptation import VON_KRIES_CAT
from colour.utilities import dot_vector, row_as_diagonal, tsplit, tstack

__author__ = 'Colour Developers'
__copyright__ = 'Copyright (C) 2013 - 2015 - Colour Developers'
__license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause'
__maintainer__ = 'Colour Developers'
__email__ = 'colour-science@googlegroups.com'
__status__ = 'Production'

__all__ = ['FAIRCHILD1990_XYZ_TO_RGB_MATRIX',
           'FAIRCHILD1990_RGB_TO_XYZ_MATRIX',
           'chromatic_adaptation_Fairchild1990',
           'XYZ_to_RGB_fairchild1990',
           'RGB_to_XYZ_fairchild1990',
           'degrees_of_adaptation']

FAIRCHILD1990_XYZ_TO_RGB_MATRIX = VON_KRIES_CAT
"""
Fairchild (1990) colour appearance model *CIE XYZ* tristimulus values to cone
responses matrix.

FAIRCHILD1990_XYZ_TO_RGB_MATRIX : array_like, (3, 3)
"""

FAIRCHILD1990_RGB_TO_XYZ_MATRIX = np.linalg.inv(VON_KRIES_CAT)
"""
Fairchild (1990) colour appearance model cone responses to *CIE XYZ*
tristimulus values matrix.

FAIRCHILD1990_RGB_TO_XYZ_MATRIX : array_like, (3, 3)
"""


[docs]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 in domain [0, 100]. 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. Warning ------- The input domain of that definition is non standard! Notes ----- - Input *CIE XYZ_1*, *CIE XYZ_n* and *CIE XYZ_r* tristimulus values are in domain [0, 100]. - Output *CIE XYZ_2* tristimulus values are in domain [0, 100]. 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( # doctest: +ELLIPSIS ... XYZ_1, XYZ_n, XYZ_r, Y_n) array([ 23.3252634..., 23.3245581..., 76.1159375...]) """ XYZ_1 = np.asarray(XYZ_1) XYZ_n = np.asarray(XYZ_n) XYZ_r = np.asarray(XYZ_r) Y_n = np.asarray(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 XYZ_c
[docs]def XYZ_to_RGB_fairchild1990(XYZ): """ Converts from *CIE XYZ* tristimulus values to cone responses. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. Returns ------- ndarray Cone responses. Examples -------- >>> XYZ = np.array([19.53, 23.07, 24.97]) >>> XYZ_to_RGB_fairchild1990(XYZ) # doctest: +ELLIPSIS array([ 22.1231935..., 23.6054224..., 22.9279534...]) """ return dot_vector(FAIRCHILD1990_XYZ_TO_RGB_MATRIX, XYZ)
[docs]def RGB_to_XYZ_fairchild1990(RGB): """ Converts from cone responses to *CIE XYZ* tristimulus values. Parameters ---------- RGB : array_like Cone responses. Returns ------- ndarray *CIE XYZ* tristimulus values. Examples -------- >>> RGB = np.array([22.12319350, 23.60542240, 22.92795340]) >>> RGB_to_XYZ_fairchild1990(RGB) # doctest: +ELLIPSIS array([ 19.53, 23.07, 24.97]) """ return dot_vector(FAIRCHILD1990_RGB_TO_XYZ_MATRIX, RGB)
[docs]def degrees_of_adaptation(LMS, Y_n, v=1 / 3, discount_illuminant=False): """ Computes the degrees of adaptation :math:`p_L`, :math:`p_M` and :math:`p_S`. Parameters ---------- LMS : array_like Cone responses. Y_n : numeric or array_like Luminance :math:`Y_n` of test adapting stimulus in :math:`cd/m^2`. v : numeric or array_like, optional Exponent :math:`v`. discount_illuminant : bool, optional Truth value indicating if the illuminant should be discounted. Returns ------- ndarray Degrees of adaptation :math:`p_L`, :math:`p_M` and :math:`p_S`. Examples -------- >>> LMS = np.array([20.00052060, 19.99978300, 19.99883160]) >>> Y_n = 31.83 >>> degrees_of_adaptation(LMS, Y_n) # doctest: +ELLIPSIS array([ 0.9799324..., 0.9960035..., 1.0233041...]) >>> degrees_of_adaptation(LMS, Y_n, 1 / 3, True) array([ 1., 1., 1.]) """ LMS = np.asarray(LMS) if discount_illuminant: return np.ones(LMS.shape) Y_n = np.asarray(Y_n) v = np.asarray(v) L, M, S = tsplit(LMS) LMS_E = dot_vector(VON_KRIES_CAT, np.ones(LMS.shape)) # E illuminant. L_E, M_E, S_E = tsplit(LMS_E) Ye_n = Y_n ** v f_E = lambda x, y: (3 * (x / y)) / (L / L_E + M / M_E + S / S_E) f_P = lambda x: (1 + Ye_n + x) / (1 + Ye_n + 1 / x) p_L = f_P(f_E(L, L_E)) p_M = f_P(f_E(M, M_E)) p_S = f_P(f_E(S, S_E)) p_LMS = tstack((p_L, p_M, p_S)) return p_LMS