def test_n_dimensional_xyY_to_XYZ(self): """ Tests :func:`colour.models.cie_xyy.xyY_to_XYZ` definition n-dimensions support. """ xyY = np.array([0.26414772, 0.37770001, 0.10080000]) XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) np.testing.assert_almost_equal( xyY_to_XYZ(xyY), XYZ, decimal=7) xyY = np.tile(xyY, (6, 1)) XYZ = np.tile(XYZ, (6, 1)) np.testing.assert_almost_equal( xyY_to_XYZ(xyY), XYZ, decimal=7) xyY = np.reshape(xyY, (2, 3, 3)) XYZ = np.reshape(XYZ, (2, 3, 3)) np.testing.assert_almost_equal( xyY_to_XYZ(xyY), XYZ, decimal=7)
def test_xyY_to_XYZ(self): """ Tests :func:`colour.models.cie_xyy.xyY_to_XYZ` definition. """ np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.26414772, 0.37770001, 0.10080000])), np.array([0.07049534, 0.10080000, 0.09558313]), decimal=7, ) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.50453169, 0.374400000000, 0.34950000])), np.array([0.47097710, 0.34950000, 0.11301649]), decimal=7, ) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.47670437, 0.35790000, 0.1915])), np.array([0.25506814, 0.19150000, 0.08849752]), decimal=7, ) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.34567, 0.3585, 0.00000000])), np.array([0.0, 0.0, 0.0]), decimal=7 )
def test_nan_xyY_to_XYZ(self): """Test :func:`colour.models.cie_xyy.xyY_to_XYZ` definition nan support.""" cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] cases = set(permutations(cases * 3, r=3)) for case in cases: xyY = np.array(case) xyY_to_XYZ(xyY)
def test_nan_xyY_to_XYZ(self): """ Tests :func:`colour.models.cie_xyy.xyY_to_XYZ` definition nan support. """ cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] cases = set(permutations(cases * 3, r=3)) for case in cases: xyY = np.array(case) xyY_to_XYZ(xyY)
def test_n_dimensional_xyY_to_XYZ(self): """ Tests :func:`colour.models.cie_xyy.xyY_to_XYZ` definition n-dimensional support. """ xyY = np.array([0.54369557, 0.32107944, 0.12197225]) XYZ = xyY_to_XYZ(xyY) xyY = np.tile(xyY, (6, 1)) XYZ = np.tile(XYZ, (6, 1)) np.testing.assert_almost_equal(xyY_to_XYZ(xyY), XYZ, decimal=7) xyY = np.reshape(xyY, (2, 3, 3)) XYZ = np.reshape(XYZ, (2, 3, 3)) np.testing.assert_almost_equal(xyY_to_XYZ(xyY), XYZ, decimal=7)
def _XYZ_optimal_colour_stimuli(illuminant): """ Returns given illuminant *Optimal Colour Stimuli* in *CIE XYZ* tristimulus values and caches it if not existing. Parameters ---------- illuminant : unicode Illuminant. Returns ------- tuple Illuminant *Optimal Colour Stimuli*. """ optimal_colour_stimuli = ILLUMINANTS_OPTIMAL_COLOUR_STIMULI.get(illuminant) if optimal_colour_stimuli is None: raise KeyError('"{0}" not found in factory ' '"Optimal Colour Stimuli": "{1}".'.format( illuminant, sorted(ILLUMINANTS_OPTIMAL_COLOUR_STIMULI.keys()))) vertices = _XYZ_OPTIMAL_COLOUR_STIMULI_CACHE.get(illuminant) if vertices is None: _XYZ_OPTIMAL_COLOUR_STIMULI_CACHE[illuminant] = vertices = ( xyY_to_XYZ(optimal_colour_stimuli) / 100) return vertices
def _XYZ_optimal_colour_stimuli(illuminant): """ Returns given illuminant optimal colour stimuli in *CIE XYZ* colourspace and caches it if not existing. Parameters ---------- illuminant : unicode Illuminant. Returns ------- tuple Illuminant optimal colour stimuli. """ optimal_colour_stimuli = ILLUMINANTS_OPTIMAL_COLOUR_STIMULI.get(illuminant) if optimal_colour_stimuli is None: raise KeyError( '"{0}" not found in factory optimal colour stimuli: "{1}".'.format( illuminant, sorted(ILLUMINANTS_OPTIMAL_COLOUR_STIMULI.keys()))) cached_ocs = _XYZ_OPTIMAL_COLOUR_STIMULI_CACHE.get(illuminant) if cached_ocs is None: _XYZ_OPTIMAL_COLOUR_STIMULI_CACHE[illuminant] = cached_ocs = ( np.array([np.ravel(xyY_to_XYZ(x) / 100) for x in optimal_colour_stimuli])) return cached_ocs
def _XYZ_optimal_colour_stimuli(illuminant): """ Returns given illuminant *Optimal Colour Stimuli* in *CIE XYZ* tristimulus values and caches it if not existing. Parameters ---------- illuminant : unicode Illuminant. Returns ------- tuple Illuminant *Optimal Colour Stimuli*. """ optimal_colour_stimuli = ILLUMINANTS_OPTIMAL_COLOUR_STIMULI.get(illuminant) if optimal_colour_stimuli is None: raise KeyError('"{0}" not found in factory ' '"Optimal Colour Stimuli": "{1}".'.format( illuminant, sorted(ILLUMINANTS_OPTIMAL_COLOUR_STIMULI.keys()))) cached_ocs = _XYZ_OPTIMAL_COLOUR_STIMULI_CACHE.get(illuminant) if cached_ocs is None: _XYZ_OPTIMAL_COLOUR_STIMULI_CACHE[illuminant] = cached_ocs = ( xyY_to_XYZ(optimal_colour_stimuli) / 100) return cached_ocs
def _XYZ_optimal_colour_stimuli(illuminant): """ Returns given illuminant optimal colour stimuli in *CIE XYZ* colourspace and caches it if not existing. Parameters ---------- illuminant : unicode Illuminant. Returns ------- tuple Illuminant optimal colour stimuli. """ optimal_colour_stimuli = ILLUMINANTS_OPTIMAL_COLOUR_STIMULI.get(illuminant) if optimal_colour_stimuli is None: raise KeyError( '"{0}" not found in factory optimal colour stimuli: "{1}".'.format( illuminant, sorted(ILLUMINANTS_OPTIMAL_COLOUR_STIMULI.keys()))) cached_ocs = _XYZ_OPTIMAL_COLOUR_STIMULI_CACHE.get(illuminant) if cached_ocs is None: _XYZ_OPTIMAL_COLOUR_STIMULI_CACHE[illuminant] = cached_ocs = (np.array( [np.ravel(xyY_to_XYZ(x) / 100) for x in optimal_colour_stimuli])) return cached_ocs
def ProLab_to_XYZ( ProLab: ArrayLike, illuminant: ArrayLike = CCS_ILLUMINANTS[ "CIE 1931 2 Degree Standard Observer"]["D65"], ) -> NDArray: """ Convert from *ProLab* colourspace to *CIE XYZ* tristimulus values. Parameters ---------- ProLab *ProLab* colourspace array. illuminant Reference *illuminant* *CIE xy* chromaticity coordinates or *CIE xyY* colourspace array. Returns ------- :class:`numpy.ndarray` *CIE XYZ* tristimulus values. Notes ----- +------------+-----------------------+-----------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+=================+ | ``Lab`` | ``L`` : [0, 1] | ``L`` : [0, 1] | | | | | | | ``a`` : [-1, 1] | ``a`` : [-1, 1] | | | | | | | ``b`` : [-1, 1] | ``b`` : [-1, 1] | +------------+-----------------------+-----------------+ +------------+-----------------------+-----------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+=================+ | ``XYZ`` | [0, 1] | [0, 1] | +------------+-----------------------+-----------------+ References ---------- :cite:`Ivan2021` Examples -------- >>> ProLab = np.array([59.8466286, 115.0396354, 20.12510352]) >>> ProLab_to_XYZ(ProLab) # doctest: +ELLIPSIS array([ 0.5163401..., 0.154695 ..., 0.0628957...]) """ ProLab = to_domain_1(ProLab) XYZ_n = xyY_to_XYZ(xy_to_xyY(illuminant)) XYZ = projective_transformation(ProLab, MATRIX_INVERSE_Q) XYZ *= XYZ_n return from_range_1(XYZ)
def XYZ_to_hdr_CIELab( XYZ, illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D50'], Y_s=0.2, Y_abs=100): """ Converts from *CIE XYZ* tristimulus values to *hdr-CIELAB* colourspace. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. illuminant : array_like, optional Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array. Y_s : numeric or array_like Relative luminance :math:`Y_s` of the surround in domain [0, 1]. Y_abs : numeric or array_like Absolute luminance :math:`Y_{abs}` of the scene diffuse white in :math:`cd/m^2`. Returns ------- ndarray *hdr-CIELAB* colourspace array. Notes ----- - Conversion to polar coordinates to compute the *chroma* :math:`C_{hdr}` and *hue* :math:`h_{hdr}` correlates can be safely performed with :func:`colour.Lab_to_LCHab` definition. - Conversion to cartesian coordinates from the *Lightness* :math:`L_{hdr}`, *chroma* :math:`C_{hdr}` and *hue* :math:`h_{hdr}` correlates can be safely performed with :func:`colour.LCHab_to_Lab` definition. - Input *CIE XYZ* tristimulus values are in domain [0, math:`\infty`]. - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. Examples -------- >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) >>> XYZ_to_hdr_CIELab(XYZ) # doctest: +ELLIPSIS array([ 24.9020664..., -46.8312760..., -10.14274843]) """ X, Y, Z = tsplit(XYZ) X_n, Y_n, Z_n = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant))) e = exponent_hdr_CIELab(Y_s, Y_abs) L_hdr = lightness_Fairchild2010(Y / Y_n, e) a_hdr = 5 * (lightness_Fairchild2010(X / X_n, e) - L_hdr) b_hdr = 2 * (L_hdr - lightness_Fairchild2010(Z / Z_n, e)) Lab_hdr = tstack((L_hdr, a_hdr, b_hdr)) return Lab_hdr
def Luv_to_XYZ( Luv, illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D50']): """ 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 ----- - Input :math:`L^*` is in domain [0, 100]. - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output *CIE XYZ* tristimulus values are in range [0, 1]. References ---------- - :cite:`CIETC1-482004m` - :cite:`Wikipediaby` Examples -------- >>> Luv = np.array([37.9856291 , -28.80219593, -1.35800706]) >>> Luv_to_XYZ(Luv) # doctest: +ELLIPSIS array([ 0.0704953..., 0.1008 , 0.0955831...]) """ L, u, v = tsplit(Luv) X_r, Y_r, Z_r = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant))) Y = np.where(L > CIE_E * CIE_K, ((L + 16) / 116)**3, L / CIE_K) 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 XYZ
def XYZ_to_UVW( XYZ, illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D50']): """ 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 ----- - Input *CIE XYZ* tristimulus values are in domain [0, 100]. - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output *CIE 1964 U\*V\*W\** colourspace array is in range [0, 100]. References ---------- - :cite:`Wikipediacj` Examples -------- >>> import numpy as np >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) * 100 >>> XYZ_to_UVW(XYZ) # doctest: +ELLIPSIS array([-28.0579733..., -0.8819449..., 37.0041149...]) """ xyY = XYZ_to_xyY(XYZ, xyY_to_xy(illuminant)) _x, _y, Y = tsplit(xyY) u, v = tsplit(UCS_to_uv(XYZ_to_UCS(XYZ))) u_0, v_0 = tsplit(UCS_to_uv(XYZ_to_UCS(xyY_to_XYZ(xy_to_xyY(illuminant))))) W = 25 * Y**(1 / 3) - 17 U = 13 * W * (u - u_0) V = 13 * W * (v - v_0) UVW = tstack((U, V, W)) return UVW
def XYZ_to_Lab(XYZ, illuminant=ILLUMINANTS.get( 'CIE 1931 2 Degree Standard Observer').get('D50')): """ Converts from *CIE XYZ* tristimulus values to *CIE Lab* 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 Lab* colourspace array. Notes ----- - Input *CIE XYZ* tristimulus values are in domain [0, 1]. - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output *Lightness* :math:`L^*` is in range [0, 100]. References ---------- .. [2] Lindbloom, B. (2003). XYZ to Lab. Retrieved February 24, 2014, from http://www.brucelindbloom.com/Eqn_XYZ_to_Lab.html Examples -------- >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) >>> XYZ_to_Lab(XYZ) # doctest: +ELLIPSIS array([ 37.9856291..., -23.6290768..., -4.4174661...]) """ XYZ = np.asarray(XYZ) XYZ_r = xyY_to_XYZ(xy_to_xyY(illuminant)) XYZ_f = XYZ / XYZ_r XYZ_f = np.where(XYZ_f > CIE_E, np.power(XYZ_f, 1 / 3), (CIE_K * XYZ_f + 16) / 116) X_f, Y_f, Z_f = tsplit(XYZ_f) L = 116 * Y_f - 16 a = 500 * (X_f - Y_f) b = 200 * (Y_f - Z_f) Lab = tstack((L, a, b)) return Lab
def Luv_to_XYZ(Luv, illuminant=ILLUMINANTS.get( 'CIE 1931 2 Degree Standard Observer').get('D50')): """ Converts from *CIE Luv* colourspace to *CIE XYZ* tristimulus values. Parameters ---------- Luv : array_like *CIE Luv* colourspace array. illuminant : array_like, optional Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array. Returns ------- ndarray *CIE XYZ* tristimulus values. Notes ----- - Input :math:`L^*` is in domain [0, 100]. - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output *CIE XYZ* tristimulus values are in range [0, 1]. References ---------- .. [3] Lindbloom, B. (2003). Luv to XYZ. Retrieved February 24, 2014, from http://brucelindbloom.com/Eqn_Luv_to_XYZ.html Examples -------- >>> Luv = np.array([37.9856291 , -28.80219593, -1.35800706]) >>> Luv_to_XYZ(Luv) # doctest: +ELLIPSIS array([ 0.0704953..., 0.1008 , 0.0955831...]) """ L, u, v = tsplit(Luv) X_r, Y_r, Z_r = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant))) Y = np.where(L > CIE_E * CIE_K, ((L + 16) / 116) ** 3, L / CIE_K) 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 XYZ
def XYZ_to_Lab(XYZ, illuminant=ILLUMINANTS.get( 'CIE 1931 2 Degree Standard Observer').get('D50')): """ Converts from *CIE XYZ* tristimulus values to *CIE Lab* 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 Lab* colourspace array. Notes ----- - Input *CIE XYZ* tristimulus values are in domain [0, 1]. - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output *Lightness* :math:`L^*` is in domain [0, 100]. References ---------- .. [2] Lindbloom, B. (2003). XYZ to Lab. Retrieved February 24, 2014, from http://www.brucelindbloom.com/Eqn_XYZ_to_Lab.html Examples -------- >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) >>> XYZ_to_Lab(XYZ) # doctest: +ELLIPSIS array([ 37.9856291..., -23.6230288..., -4.4141703...]) """ XYZ = np.asarray(XYZ) XYZ_r = xyY_to_XYZ(xy_to_xyY(illuminant)) XYZ_f = XYZ / XYZ_r XYZ_f = np.where(XYZ_f > CIE_E, np.power(XYZ_f, 1 / 3), (CIE_K * XYZ_f + 16) / 116) X_f, Y_f, Z_f = tsplit(XYZ_f) L = 116 * Y_f - 16 a = 500 * (X_f - Y_f) b = 200 * (Y_f - Z_f) Lab = tstack((L, a, b)) return Lab
def test_xyY_to_XYZ(self): """ Tests :func:`colour.models.cie_xyy.xyY_to_XYZ` definition. """ np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.4325, 0.3788, 0.1034])), np.array([0.11805834, 0.1034, 0.05150892]), decimal=7) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.3439, 0.3565, 0.0320])), np.array([0.030869, 0.032, 0.02689257]), decimal=7) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.4325, 0, 0.1034])), np.array([0., 0., 0.]), decimal=7)
def test_domain_range_scale_xyY_to_XYZ(self): """ Tests :func:`colour.models.cie_xyy.xyY_to_XYZ` definition domain and range scale support. """ xyY = np.array([0.54369557, 0.32107944, 0.12197225]) XYZ = xyY_to_XYZ(xyY) xyY = np.tile(xyY, (6, 1)).reshape(2, 3, 3) XYZ = np.tile(XYZ, (6, 1)).reshape(2, 3, 3) d_r = (('reference', 1, 1), (1, 1, 1), ( 100, np.array([1, 1, 100]), 100, )) for scale, factor_a, factor_b in d_r: with domain_range_scale(scale): np.testing.assert_almost_equal( xyY_to_XYZ(xyY * factor_a), XYZ * factor_b, decimal=7)
def XYZ_to_Lab( XYZ, illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D50']): """ Converts from *CIE XYZ* tristimulus values to *CIE L\*a\*b\** 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 L\*a\*b\** colourspace array. Notes ----- - Input *CIE XYZ* tristimulus values are in domain [0, 1]. - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output *Lightness* :math:`L^*` is in range [0, 100]. References ---------- - :cite:`CIETC1-482004m` Examples -------- >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) >>> XYZ_to_Lab(XYZ) # doctest: +ELLIPSIS array([ 37.9856291..., -23.6290768..., -4.4174661...]) """ XYZ = np.asarray(XYZ) XYZ_r = xyY_to_XYZ(xy_to_xyY(illuminant)) XYZ_f = XYZ / XYZ_r XYZ_f = np.where(XYZ_f > CIE_E, np.power(XYZ_f, 1 / 3), (CIE_K * XYZ_f + 16) / 116) X_f, Y_f, Z_f = tsplit(XYZ_f) L = 116 * Y_f - 16 a = 500 * (X_f - Y_f) b = 200 * (Y_f - Z_f) Lab = tstack((L, a, b)) return Lab
def test_xyY_to_XYZ(self): """Test :func:`colour.models.cie_xyy.xyY_to_XYZ` definition.""" np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.54369557, 0.32107944, 0.12197225])), np.array([0.20654008, 0.12197225, 0.05136952]), decimal=7, ) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.29777735, 0.48246446, 0.23042768])), np.array([0.14222010, 0.23042768, 0.10495772]), decimal=7, ) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.18582823, 0.14633764, 0.06157201])), np.array([0.07818780, 0.06157201, 0.28099326]), decimal=7, ) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.34567, 0.3585, 0.00000000])), np.array([0.00000000, 0.00000000, 0.00000000]), decimal=7, ) np.testing.assert_almost_equal( xyY_to_XYZ( np.array([ [0.54369557, 0.32107944, 0.12197225], [0.31270000, 0.32900000, 0.00000000], [0.00000000, 1.00000000, 1.00000000], ])), np.array([ [0.20654008, 0.12197225, 0.05136952], [0.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], ]), decimal=7, )
def XYZ_to_Luv( XYZ, illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D50']): """ Converts from *CIE XYZ* tristimulus values to *CIE L\*u\*v\** 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 L\*u\*v\** colourspace array. Notes ----- - Input *CIE XYZ* tristimulus values are in domain [0, 1]. - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output :math:`L^*` is in range [0, 100]. References ---------- - :cite:`CIETC1-482004m` - :cite:`Wikipediaby` Examples -------- >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) >>> XYZ_to_Luv(XYZ) # doctest: +ELLIPSIS array([ 37.9856291..., -28.8021959..., -1.3580070...]) """ X, Y, Z = tsplit(XYZ) X_r, Y_r, Z_r = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant))) y_r = Y / Y_r L = np.where(y_r > CIE_E, 116 * y_r**(1 / 3) - 16, CIE_K * y_r) u = (13 * L * ((4 * X / (X + 15 * Y + 3 * Z)) - (4 * X_r / (X_r + 15 * Y_r + 3 * Z_r)))) v = (13 * L * ((9 * Y / (X + 15 * Y + 3 * Z)) - (9 * Y_r / (X_r + 15 * Y_r + 3 * Z_r)))) Luv = tstack((L, u, v)) return Luv
def is_within_macadam_limits( xyY: ArrayLike, illuminant: Union[Literal["A", "C", "D65"], str] = "D65", tolerance: Optional[Floating] = None, ) -> NDArray: """ Return whether given *CIE xyY* colourspace array is within MacAdam limits of given illuminant. Parameters ---------- xyY *CIE xyY* colourspace array. illuminant Illuminant name. tolerance Tolerance allowed in the inside-triangle check. Returns ------- :class:`numpy.ndarray` Whether given *CIE xyY* colourspace array is within MacAdam limits. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``xyY`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ Examples -------- >>> is_within_macadam_limits(np.array([0.3205, 0.4131, 0.51]), 'A') array(True, dtype=bool) >>> a = np.array([[0.3205, 0.4131, 0.51], ... [0.0005, 0.0031, 0.001]]) >>> is_within_macadam_limits(a, 'A') array([ True, False], dtype=bool) """ optimal_colour_stimuli = _XYZ_optimal_colour_stimuli(illuminant) triangulation = _CACHE_OPTIMAL_COLOUR_STIMULI_XYZ_TRIANGULATIONS.get( illuminant) if triangulation is None: _CACHE_OPTIMAL_COLOUR_STIMULI_XYZ_TRIANGULATIONS[ illuminant] = triangulation = Delaunay(optimal_colour_stimuli) simplex = triangulation.find_simplex(xyY_to_XYZ(xyY), tol=tolerance) simplex = np.where(simplex >= 0, True, False) return simplex
def XYZ_to_UVW(XYZ, illuminant=ILLUMINANTS.get( 'CIE 1931 2 Degree Standard Observer').get('D50')): """ 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. Notes ----- - Input *CIE XYZ* tristimulus values are in domain [0, 100]. - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output *CIE UVW* colourspace array is in range [0, 100]. Warning ------- The input / output domains of that definition are non standard! Examples -------- >>> import numpy as np >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) * 100 >>> XYZ_to_UVW(XYZ) # doctest: +ELLIPSIS array([-28.0579733..., -0.8819449..., 37.0041149...]) """ xyY = XYZ_to_xyY(XYZ, xyY_to_xy(illuminant)) _x, _y, Y = tsplit(xyY) u, v = tsplit(UCS_to_uv(XYZ_to_UCS(XYZ))) u_0, v_0 = tsplit( UCS_to_uv(XYZ_to_UCS(xyY_to_XYZ(xy_to_xyY(illuminant))))) W = 25 * Y ** (1 / 3) - 17 U = 13 * W * (u - u_0) V = 13 * W * (v - v_0) UVW = tstack((U, V, W)) return UVW
def XYZ_to_Luv(XYZ, illuminant=ILLUMINANTS.get( 'CIE 1931 2 Degree Standard Observer').get('D50')): """ Converts from *CIE XYZ* tristimulus values to *CIE Luv* 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 Luv* colourspace array. Notes ----- - Input *CIE XYZ* tristimulus values are in domain [0, 1]. - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output :math:`L^*` is in range [0, 100]. References ---------- .. [2] Lindbloom, B. (2003). XYZ to Luv. Retrieved February 24, 2014, from http://brucelindbloom.com/Eqn_XYZ_to_Luv.html Examples -------- >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) >>> XYZ_to_Luv(XYZ) # doctest: +ELLIPSIS array([ 37.9856291..., -28.8021959..., -1.3580070...]) """ X, Y, Z = tsplit(XYZ) X_r, Y_r, Z_r = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant))) y_r = Y / Y_r L = np.where(y_r > CIE_E, 116 * y_r ** (1 / 3) - 16, CIE_K * y_r) u = (13 * L * ((4 * X / (X + 15 * Y + 3 * Z)) - (4 * X_r / (X_r + 15 * Y_r + 3 * Z_r)))) v = (13 * L * ((9 * Y / (X + 15 * Y + 3 * Z)) - (9 * Y_r / (X_r + 15 * Y_r + 3 * Z_r)))) Luv = tstack((L, u, v)) return Luv
def Lab_to_XYZ(Lab, illuminant=ILLUMINANTS.get( 'CIE 1931 2 Degree Standard Observer').get('D50')): """ Converts from *CIE Lab* colourspace to *CIE XYZ* tristimulus values. Parameters ---------- Lab : array_like *CIE Lab* colourspace array. illuminant : array_like, optional Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array. Returns ------- ndarray *CIE XYZ* tristimulus values. Notes ----- - Input *Lightness* :math:`L^*` is in domain [0, 100]. - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output *CIE XYZ* tristimulus values are in domain [0, 1]. References ---------- .. [3] Lindbloom, B. (2008). Lab to XYZ. Retrieved February 24, 2014, from http://www.brucelindbloom.com/Eqn_Lab_to_XYZ.html Examples -------- >>> Lab = np.array([37.98562910, -23.62302887, -4.41417036]) >>> Lab_to_XYZ(Lab) # doctest: +ELLIPSIS array([ 0.0704953..., 0.1008 , 0.0955831...]) """ L, a, b = tsplit(Lab) XYZ_r = xyY_to_XYZ(xy_to_xyY(illuminant)) f_y = (L + 16) / 116 f_x = a / 500 + f_y f_z = f_y - b / 200 x_r = np.where(f_x**3 > CIE_E, f_x**3, (116 * f_x - 16) / CIE_K) y_r = np.where(L > CIE_K * CIE_E, ((L + 16) / 116)**3, L / CIE_K) z_r = np.where(f_z**3 > CIE_E, f_z**3, (116 * f_z - 16) / CIE_K) XYZ = tstack((x_r, y_r, z_r)) * XYZ_r return XYZ
def Lab_to_XYZ(Lab, illuminant=ILLUMINANTS.get( 'CIE 1931 2 Degree Standard Observer').get('D50')): """ Converts from *CIE Lab* colourspace to *CIE XYZ* tristimulus values. Parameters ---------- Lab : array_like *CIE Lab* colourspace array. illuminant : array_like, optional Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array. Returns ------- ndarray *CIE XYZ* tristimulus values. Notes ----- - Input *Lightness* :math:`L^*` is in domain [0, 100]. - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output *CIE XYZ* tristimulus values are in domain [0, 1]. References ---------- .. [3] Lindbloom, B. (2008). Lab to XYZ. Retrieved February 24, 2014, from http://www.brucelindbloom.com/Eqn_Lab_to_XYZ.html Examples -------- >>> Lab = np.array([37.98562910, -23.62302887, -4.41417036]) >>> Lab_to_XYZ(Lab) # doctest: +ELLIPSIS array([ 0.0704953..., 0.1008 , 0.0955831...]) """ L, a, b = tsplit(Lab) XYZ_r = xyY_to_XYZ(xy_to_xyY(illuminant)) f_y = (L + 16) / 116 f_x = a / 500 + f_y f_z = f_y - b / 200 x_r = np.where(f_x ** 3 > CIE_E, f_x ** 3, (116 * f_x - 16) / CIE_K) y_r = np.where(L > CIE_K * CIE_E, ((L + 16) / 116) ** 3, L / CIE_K) z_r = np.where(f_z ** 3 > CIE_E, f_z ** 3, (116 * f_z - 16) / CIE_K) XYZ = tstack((x_r, y_r, z_r)) * XYZ_r return XYZ
def hdr_CIELab_to_XYZ( Lab_hdr, illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D50'], Y_s=0.2, Y_abs=100): """ Converts from *hdr-CIELAB* colourspace to *CIE XYZ* tristimulus values. Parameters ---------- Lab_hdr : array_like *hdr-CIELAB* colourspace array. illuminant : array_like, optional Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array. Y_s : numeric or array_like Relative luminance :math:`Y_s` of the surround in domain [0, 1]. Y_abs : numeric or array_like Absolute luminance :math:`Y_{abs}` of the scene diffuse white in :math:`cd/m^2`. Returns ------- ndarray *CIE XYZ* tristimulus values. Notes ----- - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output *CIE XYZ* tristimulus values are in range [0, math:`\infty`]. Examples -------- >>> Lab_hdr = np.array([24.90206646, -46.83127607, -10.14274843]) >>> hdr_CIELab_to_XYZ(Lab_hdr) # doctest: +ELLIPSIS array([ 0.0704953..., 0.1008 , 0.0955831...]) """ L_hdr, a_hdr, b_hdr = tsplit(Lab_hdr) X_n, Y_n, Z_n = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant))) e = exponent_hdr_CIELab(Y_s, Y_abs) Y = luminance_Fairchild2010(L_hdr, e) * Y_n X = luminance_Fairchild2010((a_hdr + 5 * L_hdr) / 5, e) * X_n Z = luminance_Fairchild2010((-b_hdr + 2 * L_hdr) / 2, e) * Z_n XYZ = tstack((X, Y, Z)) return XYZ
def Lab_to_XYZ( Lab, illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D50']): """ 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 ----- - Input *Lightness* :math:`L^*` is in domain [0, 100]. - Input *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output *CIE XYZ* tristimulus values are in range [0, 1]. References ---------- - :cite:`CIETC1-482004m` Examples -------- >>> Lab = np.array([37.98562910, -23.62907688, -4.41746615]) >>> Lab_to_XYZ(Lab) # doctest: +ELLIPSIS array([ 0.0704953..., 0.1008 , 0.0955831...]) """ L, a, b = tsplit(Lab) XYZ_r = xyY_to_XYZ(xy_to_xyY(illuminant)) f_y = (L + 16) / 116 f_x = a / 500 + f_y f_z = f_y - b / 200 x_r = np.where(f_x**3 > CIE_E, f_x**3, (116 * f_x - 16) / CIE_K) y_r = np.where(L > CIE_K * CIE_E, ((L + 16) / 116)**3, L / CIE_K) z_r = np.where(f_z**3 > CIE_E, f_z**3, (116 * f_z - 16) / CIE_K) XYZ = tstack((x_r, y_r, z_r)) * XYZ_r return XYZ
def test_xyY_to_XYZ(self): """ Tests :func:`colour.models.cie_xyy.xyY_to_XYZ` definition. """ np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.54369557, 0.32107944, 0.12197225])), np.array([0.20654008, 0.12197225, 0.05136952]), decimal=7) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.29777735, 0.48246446, 0.23042768])), np.array([0.14222010, 0.23042768, 0.10495772]), decimal=7) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.18582823, 0.14633764, 0.06157201])), np.array([0.07818780, 0.06157201, 0.28099326]), decimal=7) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.34567, 0.3585, 0.00000000])), np.array([0.00000000, 0.00000000, 0.00000000]), decimal=7) np.testing.assert_almost_equal( xyY_to_XYZ( np.array([ [0.54369557, 0.32107944, 0.12197225], [0.31270000, 0.32900000, 0.00000000], [0.00000000, 1.00000000, 1.00000000], ])), np.array([ [0.20654008, 0.12197225, 0.05136952], [0.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], ]), decimal=7)
def is_within_macadam_limits(xyY, illuminant, tolerance=None): """ Returns if given *CIE xyY* colourspace array is within MacAdam limits of given illuminant. Parameters ---------- xyY : array_like *CIE xyY* colourspace array. illuminant : unicode Illuminant. tolerance : numeric, optional Tolerance allowed in the inside-triangle check. Returns ------- bool Is within MacAdam limits. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``xyY`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ Examples -------- >>> is_within_macadam_limits(np.array([0.3205, 0.4131, 0.51]), 'A') array(True, dtype=bool) >>> a = np.array([[0.3205, 0.4131, 0.51], ... [0.0005, 0.0031, 0.001]]) >>> is_within_macadam_limits(a, 'A') array([ True, False], dtype=bool) """ optimal_colour_stimuli = _XYZ_optimal_colour_stimuli(illuminant) triangulation = _XYZ_OPTIMAL_COLOUR_STIMULI_TRIANGULATIONS_CACHE.get( illuminant) if triangulation is None: _XYZ_OPTIMAL_COLOUR_STIMULI_TRIANGULATIONS_CACHE[illuminant] = \ triangulation = Delaunay(optimal_colour_stimuli) simplex = triangulation.find_simplex(xyY_to_XYZ(xyY), tol=tolerance) simplex = np.where(simplex >= 0, True, False) return simplex
def xy_to_rgb(xy, name='ITU-R BT.2020', normalize='maximum', specific=None): """ xy値からRGB値を算出する。 いい感じに正規化もしておく。 Parameters ---------- xy : array_like xy value. name : string color space name. normalize : string normalize method. You can select 'maximum', 'specific' or None. Returns ------- array_like rgb value. the value is normalized. """ illuminant_XYZ = D65_WHITE illuminant_RGB = D65_WHITE chromatic_adaptation_transform = 'CAT02' large_xyz_to_rgb_matrix = get_xyz_to_rgb_matrix(name) if normalize == 'specific': xyY = xy_to_xyY(xy) xyY[..., 2] = specific large_xyz = xyY_to_XYZ(xyY) else: large_xyz = xy_to_XYZ(xy) rgb = XYZ_to_RGB(large_xyz, illuminant_XYZ, illuminant_RGB, large_xyz_to_rgb_matrix, chromatic_adaptation_transform) """ そのままだとビデオレベルが低かったりするので、 各ドット毎にRGB値を正規化&最大化する。必要であれば。 """ if normalize == 'maximum': rgb = normalise_maximum(rgb, axis=-1) else: if(np.sum(rgb > 1.0) > 0): print("warning: over flow has occured at xy_to_rgb") if(np.sum(rgb < 0.0) > 0): print("warning: under flow has occured at xy_to_rgb") rgb[rgb < 0] = 0 rgb[rgb > 1.0] = 1.0 return rgb
def test_xyY_to_XYZ(self): """ Tests :func:`colour.models.cie_xyy.xyY_to_XYZ` definition. """ np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.26414772, 0.37770001, 0.10080000])), np.array([0.07049534, 0.10080000, 0.09558313]), decimal=7) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.50453169, 0.37440000, 0.34950000])), np.array([0.47097710, 0.34950000, 0.11301649]), decimal=7) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.47670437, 0.35790000, 0.19150000])), np.array([0.25506814, 0.19150000, 0.08849752]), decimal=7) np.testing.assert_almost_equal( xyY_to_XYZ(np.array([0.34567, 0.3585, 0.00000000])), np.array([0.00000000, 0.00000000, 0.00000000]), decimal=7)
def is_within_macadam_limits(xyY, illuminant, tolerance=None): """ Returns if given *CIE xyY* colourspace array is within MacAdam limits of given illuminant. Parameters ---------- xyY : array_like *CIE xyY* colourspace array. illuminant : unicode Illuminant. tolerance : numeric, optional Tolerance allowed in the inside-triangle check. Returns ------- bool Is within MacAdam limits. Notes ----- - Input *CIE xyY* colourspace array is in domain [0, 1]. - This definition requires *scipy* to be installed. Examples -------- >>> is_within_macadam_limits(np.array([0.3205, 0.4131, 0.51]), 'A') array(True, dtype=bool) >>> a = np.array([[0.3205, 0.4131, 0.51], ... [0.0005, 0.0031, 0.001]]) >>> is_within_macadam_limits(a, 'A') array([ True, False], dtype=bool) """ if is_scipy_installed(raise_exception=True): from scipy.spatial import Delaunay optimal_colour_stimuli = _XYZ_optimal_colour_stimuli(illuminant) triangulation = _XYZ_OPTIMAL_COLOUR_STIMULI_TRIANGULATIONS_CACHE.get( illuminant) if triangulation is None: _XYZ_OPTIMAL_COLOUR_STIMULI_TRIANGULATIONS_CACHE[illuminant] = \ triangulation = Delaunay(optimal_colour_stimuli) simplex = triangulation.find_simplex(xyY_to_XYZ(xyY), tol=tolerance) simplex = np.where(simplex >= 0, True, False) return simplex
def is_within_macadam_limits(xyY, illuminant): """ Returns if given *CIE xyY* colourspace matrix is within *MacAdam* limits of given illuminant. Parameters ---------- xyY : array_like, (3,) *CIE xyY* colourspace matrix. illuminant : unicode Illuminant. Returns ------- bool Is within *MacAdam* limits. Notes ----- - Input *CIE xyY* colourspace matrix is in domain [0, 1]. - This definition requires *scipy* to be installed. Examples -------- >>> is_within_macadam_limits((0.3205, 0.4131, 0.51), 'A') True >>> is_within_macadam_limits((0.0005, 0.0031, 0.001), 'A') False """ if is_scipy_installed(raise_exception=True): from scipy.spatial import Delaunay optimal_colour_stimuli = _XYZ_optimal_colour_stimuli(illuminant) triangulation = _XYZ_OPTIMAL_COLOUR_STIMULI_TRIANGULATIONS_CACHE.get( illuminant) if triangulation is None: _XYZ_OPTIMAL_COLOUR_STIMULI_TRIANGULATIONS_CACHE[illuminant] = \ triangulation = Delaunay(optimal_colour_stimuli) simplex = triangulation.find_simplex(np.ravel(xyY_to_XYZ(xyY))) return True if simplex != -1 else False
def _XYZ_optimal_colour_stimuli( illuminant: Union[Literal["A", "C", "D65"], str] = "D65") -> NDArray: """ Return given illuminant *Optimal Colour Stimuli* in *CIE XYZ* tristimulus values and caches it if not existing. Parameters ---------- illuminant Illuminant name. Returns ------- :class:`numpy.ndarray` Illuminant *Optimal Colour Stimuli*. """ illuminant = validate_method( illuminant, list(OPTIMAL_COLOUR_STIMULI_ILLUMINANTS.keys()), '"{0}" illuminant is invalid, it must be one of {1}!', ) optimal_colour_stimuli = OPTIMAL_COLOUR_STIMULI_ILLUMINANTS.get(illuminant) if optimal_colour_stimuli is None: raise KeyError( f'"{illuminant}" not found in factory "Optimal Colour Stimuli": ' f'"{sorted(OPTIMAL_COLOUR_STIMULI_ILLUMINANTS.keys())}".') vertices = _CACHE_OPTIMAL_COLOUR_STIMULI_XYZ.get(illuminant) if vertices is None: _CACHE_OPTIMAL_COLOUR_STIMULI_XYZ[illuminant] = vertices = ( xyY_to_XYZ(optimal_colour_stimuli) / 100) return vertices
def RGB_to_XYZ(RGB, illuminant_RGB, illuminant_XYZ, RGB_to_XYZ_matrix, chromatic_adaptation_transform='CAT02', decoding_cctf=None): """ Converts given *RGB* colourspace array to *CIE XYZ* tristimulus values. Parameters ---------- RGB : array_like *RGB* colourspace array. illuminant_RGB : array_like *RGB* colourspace *illuminant* chromaticity coordinates or *CIE xyY* colourspace array. illuminant_XYZ : array_like *CIE XYZ* tristimulus values *illuminant* chromaticity coordinates or *CIE xyY* colourspace array. RGB_to_XYZ_matrix : array_like *Normalised primary matrix*. chromatic_adaptation_transform : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC', None}**, *Chromatic adaptation* transform, if *None* no chromatic adaptation is performed. decoding_cctf : object, optional Decoding colour component transfer function (Decoding CCTF) or electro-optical transfer function (EOTF / EOCF). Returns ------- ndarray *CIE XYZ* tristimulus values. Notes ----- +--------------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +====================+=======================+===============+ | ``RGB`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ | ``illuminant_XYZ`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ | ``illuminant_RGB`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ +--------------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +====================+=======================+===============+ | ``XYZ`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ Examples -------- >>> RGB = np.array([0.45595571, 0.03039702, 0.04087245]) >>> illuminant_RGB = np.array([0.31270, 0.32900]) >>> illuminant_XYZ = np.array([0.34570, 0.35850]) >>> chromatic_adaptation_transform = 'Bradford' >>> RGB_to_XYZ_matrix = np.array( ... [[0.41240000, 0.35760000, 0.18050000], ... [0.21260000, 0.71520000, 0.07220000], ... [0.01930000, 0.11920000, 0.95050000]] ... ) >>> RGB_to_XYZ(RGB, illuminant_RGB, illuminant_XYZ, RGB_to_XYZ_matrix, ... chromatic_adaptation_transform) # doctest: +ELLIPSIS array([ 0.2163881..., 0.1257 , 0.0384749...]) """ RGB = to_domain_1(RGB) if decoding_cctf is not None: with domain_range_scale('ignore'): RGB = decoding_cctf(RGB) XYZ = dot_vector(RGB_to_XYZ_matrix, RGB) if chromatic_adaptation_transform is not None: M_CAT = chromatic_adaptation_matrix_VonKries( xyY_to_XYZ(xy_to_xyY(illuminant_RGB)), xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)), transform=chromatic_adaptation_transform) XYZ = dot_vector(M_CAT, XYZ) return from_range_1(XYZ)
def plot_multi_colour_checkers(colour_checkers=None, **kwargs): """ Plots and compares given colour checkers. Parameters ---------- colour_checkers : array_like, optional Color checker names, must be less than or equal to 2 names. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_multi_colour_swatches`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_multi_colour_checkers(['ColorChecker 1976', 'ColorChecker 2005']) ... # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Multi_Colour_Checkers.png :align: center :alt: plot_multi_colour_checkers """ if colour_checkers is None: colour_checkers = ['ColorChecker 1976', 'ColorChecker 2005'] else: assert len(colour_checkers) <= 2, ( 'Only two colour checkers can be compared at a time!') colour_checkers = filter_colour_checkers(colour_checkers).values() _figure, axes = artist(**kwargs) compare_swatches = len(colour_checkers) == 2 colour_swatches = [] colour_checker_names = [] for colour_checker in colour_checkers: colour_checker_names.append(colour_checker.name) for label, xyY in colour_checker.data.items(): XYZ = xyY_to_XYZ(xyY) RGB = XYZ_to_plotting_colourspace(XYZ, colour_checker.illuminant) colour_swatches.append( ColourSwatch(label.title(), np.clip(np.ravel(RGB), 0, 1))) if compare_swatches: colour_swatches = [ swatch for pairs in zip(colour_swatches[0:len(colour_swatches) // 2], colour_swatches[len(colour_swatches) // 2:]) for swatch in pairs ] background_colour = '0.1' width = height = 1.0 spacing = 0.25 columns = 6 settings = { 'axes': axes, 'width': width, 'height': height, 'spacing': spacing, 'columns': columns, 'text_parameters': { 'size': 8 }, 'background_colour': background_colour, 'compare_swatches': 'Stacked' if compare_swatches else None, } settings.update(kwargs) settings['standalone'] = False plot_multi_colour_swatches(colour_swatches, **settings) axes.text( 0.5, 0.005, '{0} - {1} - Colour Rendition Chart'.format( ', '.join(colour_checker_names), COLOUR_STYLE_CONSTANTS.colour.colourspace.name), transform=axes.transAxes, color=COLOUR_STYLE_CONSTANTS.colour.bright, ha='center', va='bottom') settings.update({ 'axes': axes, 'standalone': True, 'title': ', '.join(colour_checker_names), }) return render(**settings)
def XYZ_to_Lab( XYZ, illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65']): """ Converts from *CIE XYZ* tristimulus values to *CIE L\\*a\\*b\\** 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 L\\*a\\*b\\** colourspace array. Notes ----- +----------------+-----------------------+-----------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +================+=======================+=================+ | ``XYZ`` | [0, 1] | [0, 1] | +----------------+-----------------------+-----------------+ | ``illuminant`` | [0, 1] | [0, 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:`CIETC1-482004m` Examples -------- >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) >>> XYZ_to_Lab(XYZ) # doctest: +ELLIPSIS array([ 41.5278752..., 52.6385830..., 26.9231792...]) """ X, Y, Z = tsplit(to_domain_1(XYZ)) X_n, Y_n, Z_n = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant))) f_X_X_n = intermediate_lightness_function_CIE1976(X, X_n) f_Y_Y_n = intermediate_lightness_function_CIE1976(Y, Y_n) f_Z_Z_n = intermediate_lightness_function_CIE1976(Z, Z_n) L = 116 * f_Y_Y_n - 16 a = 500 * (f_X_X_n - f_Y_Y_n) b = 200 * (f_Y_Y_n - f_Z_Z_n) Lab = tstack([L, a, b]) return from_range_100(Lab)
def XYZ_to_Luv( XYZ, illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65']): """ Converts from *CIE XYZ* tristimulus values to *CIE L\\*u\\*v\\** 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 L\\*u\\*v\\** colourspace array. Notes ----- +----------------+-----------------------+-----------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +================+=======================+=================+ | ``XYZ`` | [0, 1] | [0, 1] | +----------------+-----------------------+-----------------+ | ``illuminant`` | [0, 1] | [0, 1] | +----------------+-----------------------+-----------------+ +----------------+-----------------------+-----------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +================+=======================+=================+ | ``Luv`` | ``L`` : [0, 100] | ``L`` : [0, 1] | | | | | | | ``u`` : [-100, 100] | ``u`` : [-1, 1] | | | | | | | ``v`` : [-100, 100] | ``v`` : [-1, 1] | +----------------+-----------------------+-----------------+ References ---------- :cite:`CIETC1-482004m`, :cite:`Wikipedia2007b` Examples -------- >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) >>> XYZ_to_Luv(XYZ) # doctest: +ELLIPSIS array([ 41.5278752..., 96.8362605..., 17.7521014...]) """ X, Y, Z = tsplit(to_domain_1(XYZ)) X_r, Y_r, Z_r = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant))) with domain_range_scale('100'): L = lightness_CIE1976(Y, Y_r) u = (13 * L * ((4 * X / (X + 15 * Y + 3 * Z)) - (4 * X_r / (X_r + 15 * Y_r + 3 * Z_r)))) v = (13 * L * ((9 * Y / (X + 15 * Y + 3 * Z)) - (9 * Y_r / (X_r + 15 * Y_r + 3 * Z_r)))) Luv = tstack([L, u, v]) return from_range_100(Luv)
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)
def XYZ_to_RGB(XYZ, illuminant_XYZ, illuminant_RGB, XYZ_to_RGB_matrix, chromatic_adaptation_transform='CAT02', OECF=None): """ Converts from *CIE XYZ* tristimulus values to given *RGB* colourspace. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. illuminant_XYZ : array_like *CIE XYZ* tristimulus values *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array. illuminant_RGB : array_like *RGB* colourspace *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array. XYZ_to_RGB_matrix : array_like *Normalised primary matrix*. chromatic_adaptation_transform : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild, 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC'}**, *Chromatic adaptation* transform. OECF : object, optional *Opto-electronic conversion function*. Returns ------- ndarray *RGB* colourspace array. Notes ----- - Input *CIE XYZ* tristimulus values are in domain [0, 1]. - Input *illuminant_XYZ* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Input *illuminant_RGB* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output *RGB* colourspace array is in domain [0, 1]. Examples -------- >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) >>> illuminant_XYZ = np.array([0.34567, 0.35850]) >>> illuminant_RGB = np.array([0.31271, 0.32902]) >>> chromatic_adaptation_transform = 'Bradford' >>> XYZ_to_RGB_matrix = np.array([ ... [3.24100326, -1.53739899, -0.49861587], ... [-0.96922426, 1.87592999, 0.04155422], ... [0.05563942, -0.20401120, 1.05714897]]) >>> XYZ_to_RGB( ... XYZ, ... illuminant_XYZ, ... illuminant_RGB, ... XYZ_to_RGB_matrix, ... chromatic_adaptation_transform) # doctest: +ELLIPSIS array([ 0.0110360..., 0.1273446..., 0.1163103...]) """ M = chromatic_adaptation_matrix_VonKries( xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)), xyY_to_XYZ(xy_to_xyY(illuminant_RGB)), transform=chromatic_adaptation_transform) XYZ_a = dot_vector(M, XYZ) RGB = dot_vector(XYZ_to_RGB_matrix, XYZ_a) if OECF is not None: RGB = OECF(RGB) return RGB
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)
def XYZ_to_RGB(XYZ, illuminant_XYZ, illuminant_RGB, XYZ_to_RGB_matrix, chromatic_adaptation_transform='CAT02', encoding_cctf=None): """ Converts from *CIE XYZ* tristimulus values to *RGB* colourspace array. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. illuminant_XYZ : array_like *CIE XYZ* tristimulus values *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array. illuminant_RGB : array_like *RGB* colourspace *illuminant* *xy* chromaticity coordinates or *CIE xyY* colourspace array. XYZ_to_RGB_matrix : array_like *Normalised primary matrix*. chromatic_adaptation_transform : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC', None}**, *Chromatic adaptation* transform, if *None* no chromatic adaptation is performed. encoding_cctf : object, optional Encoding colour component transfer function (Encoding CCTF) or opto-electronic transfer function (OETF / OECF). Returns ------- ndarray *RGB* colourspace array. Notes ----- +--------------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +====================+=======================+===============+ | ``XYZ`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ | ``illuminant_XYZ`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ | ``illuminant_RGB`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ +--------------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +====================+=======================+===============+ | ``RGB`` | [0, 1] | [0, 1] | +--------------------+-----------------------+---------------+ Examples -------- >>> XYZ = np.array([0.21638819, 0.12570000, 0.03847493]) >>> illuminant_XYZ = np.array([0.34570, 0.35850]) >>> illuminant_RGB = np.array([0.31270, 0.32900]) >>> chromatic_adaptation_transform = 'Bradford' >>> XYZ_to_RGB_matrix = np.array( ... [[3.24062548, -1.53720797, -0.49862860], ... [-0.96893071, 1.87575606, 0.04151752], ... [0.05571012, -0.20402105, 1.05699594]] ... ) >>> XYZ_to_RGB(XYZ, illuminant_XYZ, illuminant_RGB, XYZ_to_RGB_matrix, ... chromatic_adaptation_transform) # doctest: +ELLIPSIS array([ 0.4559557..., 0.0303970..., 0.0408724...]) """ XYZ = to_domain_1(XYZ) if chromatic_adaptation_transform is not None: M_CAT = chromatic_adaptation_matrix_VonKries( xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)), xyY_to_XYZ(xy_to_xyY(illuminant_RGB)), transform=chromatic_adaptation_transform) XYZ = dot_vector(M_CAT, XYZ) RGB = dot_vector(XYZ_to_RGB_matrix, XYZ) if encoding_cctf is not None: with domain_range_scale('ignore'): RGB = encoding_cctf(RGB) return from_range_1(RGB)
def convert_experiment_results_Breneman1987(experiment): """ Converts *Breneman (1987)* experiment results to a :class:`colour.CorrespondingColourDataset` class instance. Parameters ---------- experiment : integer {1, 2, 3, 4, 6, 8, 9, 11, 12} *Breneman (1987)* experiment number. Returns ------- CorrespondingColourDataset :class:`colour.CorrespondingColourDataset` class instance. Examples -------- >>> from pprint import pprint >>> pprint(tuple(convert_experiment_results_Breneman1987(2))) ... # doctest: +ELLIPSIS (2, array([ 0.9582463..., 1. , 0.9436325...]), array([ 0.9587332..., 1. , 0.4385796...]), array([[ 388.125 , 405. , 345.625 ], [ 266.8957925..., 135. , 28.5983365...], [ 474.5717821..., 405. , 222.75 ...], [ 538.3899082..., 405. , 24.8944954...], [ 178.7430167..., 135. , 19.6089385...], [ 436.6749547..., 405. , 26.5483725...], [ 124.7746282..., 135. , 36.1965613...], [ 77.0794172..., 135. , 60.5850563...], [ 279.9390889..., 405. , 455.8395127...], [ 149.5808157..., 135. , 498.7046827...], [ 372.1113689..., 405. , 669.9883990...], [ 212.3638968..., 135. , 414.6704871...]]), array([[ 400.1039651..., 405. , 191.7287234...], [ 271.0384615..., 135. , 13.5 ...], [ 495.4705323..., 405. , 119.7290874...], [ 580.7967033..., 405. , 6.6758241...], [ 190.1933701..., 135. , 7.4585635...], [ 473.7184115..., 405. , 10.2346570...], [ 135.4936014..., 135. , 20.2376599...], [ 86.4689781..., 135. , 35.2281021...], [ 283.5396281..., 405. , 258.1775929...], [ 119.7044335..., 135. , 282.6354679...], [ 359.9532224..., 405. , 381.0031185...], [ 181.8271461..., 135. , 204.0661252...]]), array(1500), array(1500), 0.3, 0.3, {}) """ valid_experiment_results = (1, 2, 3, 4, 6, 8, 9, 11, 12) assert experiment in valid_experiment_results, ( '"Breneman (1987)" experiment result must be one of "{0}"!'.format( valid_experiment_results)) samples_luminance = [ 0.270, 0.090, 0.270, 0.270, 0.090, 0.270, 0.090, 0.090, 0.270, 0.090, 0.270, 0.090, ] experiment_results = list(BRENEMAN_EXPERIMENTS[experiment]) illuminant_chromaticities = experiment_results.pop(0) Y_r = Y_t = BRENEMAN_EXPERIMENTS_PRIMARIES_CHROMATICITIES[experiment].Y B_r = B_t = 0.3 XYZ_t, XYZ_r = xy_to_XYZ( np.hstack([ Luv_uv_to_xy(illuminant_chromaticities[1:3]), np.full([2, 1], Y_r) ])) / Y_r xyY_cr, xyY_ct = [], [] for i, experiment_result in enumerate(experiment_results): xyY_cr.append( np.hstack([ Luv_uv_to_xy(experiment_result[2]), samples_luminance[i] * Y_r ])) xyY_ct.append( np.hstack([ Luv_uv_to_xy(experiment_result[1]), samples_luminance[i] * Y_t ])) XYZ_cr = xyY_to_XYZ(xyY_cr) XYZ_ct = xyY_to_XYZ(xyY_ct) return CorrespondingColourDataset(experiment, XYZ_r, XYZ_t, XYZ_cr, XYZ_ct, Y_r, Y_t, B_r, B_t, {})
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)
def colour_checker_plot(colour_checker='ColorChecker 2005', **kwargs): """ Plots given colour checker. Parameters ---------- colour_checker : unicode, optional Color checker name. \**kwargs : dict, optional Keywords arguments. Returns ------- bool Definition success. Raises ------ KeyError If the given colour rendition chart is not found in the factory colour rendition charts. Examples -------- >>> colour_checker_plot() # doctest: +SKIP True """ canvas(**kwargs) colour_checker, name = COLOURCHECKERS.get(colour_checker), colour_checker if colour_checker is None: raise KeyError( ('Colour checker "{0}" not found in ' 'factory colour checkers: "{1}".').format( name, sorted(COLOURCHECKERS.keys()))) _name, data, illuminant = colour_checker colour_parameters = [] for _index, label, x, y, Y in data: XYZ = xyY_to_XYZ((x, y, Y)) RGB = XYZ_to_sRGB(XYZ, illuminant) colour_parameters.append( ColourParameter(label.title(), np.clip(np.ravel(RGB), 0, 1))) background_colour = '0.1' matplotlib.pyplot.gca().patch.set_facecolor(background_colour) width = height = 1.0 spacing = 0.25 across = 6 settings = { 'standalone': False, 'width': width, 'height': height, 'spacing': spacing, 'across': across, 'text_size': 8, 'margins': (-0.125, 0.125, -0.5, 0.125)} settings.update(kwargs) multi_colour_plot(colour_parameters, **settings) text_x = width * (across / 2) + (across * (spacing / 2)) - spacing / 2 text_y = -(len(colour_parameters) / across + spacing / 2) pylab.text(text_x, text_y, '{0} - {1} - Colour Rendition Chart'.format( name, RGB_COLOURSPACES.get('sRGB').name), color='0.95', clip_on=True, ha='center') settings.update({ 'title': name, 'facecolor': background_colour, 'edgecolor': None, 'standalone': True}) boundaries(**settings) decorate(**settings) return display(**settings)
def hdr_CIELab_to_XYZ( Lab_hdr, illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65'], Y_s=0.2, Y_abs=100, method='Fairchild 2011'): """ Converts from *hdr-CIELAB* colourspace to *CIE XYZ* tristimulus values. Parameters ---------- Lab_hdr : array_like *hdr-CIELAB* colourspace array. illuminant : array_like, optional Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY* 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** | +================+=========================+=====================+ | ``Lab_hdr`` | ``L_hdr`` : [0, 100] | ``L_hdr`` : [0, 1] | | | | | | | ``a_hdr`` : [-100, 100] | ``a_hdr`` : [-1, 1] | | | | | | | ``b_hdr`` : [-100, 100] | ``b_hdr`` : [-1, 1] | +----------------+-------------------------+---------------------+ | ``illuminant`` | [0, 1] | [0, 1] | +----------------+-------------------------+---------------------+ | ``Y_s`` | [0, 1] | [0, 1] | +----------------+-------------------------+---------------------+ +----------------+-------------------------+---------------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +================+=========================+=====================+ | ``XYZ`` | [0, 1] | [0, 1] | +----------------+-------------------------+---------------------+ References ---------- :cite:`Fairchild2010`, :cite:`Fairchild2011` Examples -------- >>> Lab_hdr = np.array([51.87002062, 60.4763385, 32.14551912]) >>> hdr_CIELab_to_XYZ(Lab_hdr) # doctest: +ELLIPSIS array([ 0.2065400..., 0.1219722..., 0.0513695...]) >>> Lab_hdr = np.array([31.99621114, 128.00763036, 48.76952309]) >>> hdr_CIELab_to_XYZ(Lab_hdr, method='Fairchild 2010') ... # doctest: +ELLIPSIS array([ 0.2065400..., 0.1219722..., 0.0513695...]) """ L_hdr, a_hdr, b_hdr = tsplit(to_domain_100(Lab_hdr)) X_n, Y_n, Z_n = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant))) method_l = method.lower() assert method.lower() in [ m.lower() for m in HDR_CIELAB_METHODS ], ('"{0}" method is invalid, must be one of {1}!'.format( method, HDR_CIELAB_METHODS)) if method_l == 'fairchild 2010': luminance_callable = luminance_Fairchild2010 else: luminance_callable = luminance_Fairchild2011 e = exponent_hdr_CIELab(Y_s, Y_abs, method) # Domain and range scaling has already be handled. with domain_range_scale('ignore'): Y = luminance_callable(L_hdr, e) * Y_n X = luminance_callable((a_hdr + 5 * L_hdr) / 5, e) * X_n Z = luminance_callable((-b_hdr + 2 * L_hdr) / 2, e) * Z_n XYZ = tstack([X, Y, Z]) return from_range_1(XYZ)
def RGB_to_XYZ(RGB, illuminant_RGB, illuminant_XYZ, RGB_to_XYZ_matrix, chromatic_adaptation_transform='CAT02', EOCF=None): """ Converts from given *RGB* colourspace to *CIE XYZ* tristimulus values. Parameters ---------- RGB : array_like *RGB* colourspace array. illuminant_RGB : array_like *RGB* colourspace *illuminant* chromaticity coordinates or *CIE xyY* colourspace array. illuminant_XYZ : array_like *CIE XYZ* tristimulus values *illuminant* chromaticity coordinates or *CIE xyY* colourspace array. RGB_to_XYZ_matrix : array_like *Normalised primary matrix*. chromatic_adaptation_transform : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild, 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC'}**, *Chromatic adaptation* transform. EOCF : object, optional *Electro-optical conversion function*. Returns ------- ndarray *CIE XYZ* tristimulus values. Notes ----- - Input *RGB* colourspace array is in domain [0, 1]. - Input *illuminant_RGB* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Input *illuminant_XYZ* *xy* chromaticity coordinates or *CIE xyY* colourspace array are in domain [0, :math:`\infty`]. - Output *CIE XYZ* tristimulus values are in domain [0, 1]. Examples -------- >>> RGB = np.array([0.01103604, 0.12734466, 0.11631037]) >>> illuminant_RGB = np.array([0.31271, 0.32902]) >>> illuminant_XYZ = np.array([0.34567, 0.35850]) >>> chromatic_adaptation_transform = 'Bradford' >>> RGB_to_XYZ_matrix = np.array([ ... [0.41238656, 0.35759149, 0.18045049], ... [0.21263682, 0.71518298, 0.07218020], ... [0.01933062, 0.11919716, 0.95037259]]) >>> RGB_to_XYZ( ... RGB, ... illuminant_RGB, ... illuminant_XYZ, ... RGB_to_XYZ_matrix, ... chromatic_adaptation_transform) # doctest: +ELLIPSIS array([ 0.0704953..., 0.1008 , 0.0955831...]) """ if EOCF is not None: RGB = EOCF(RGB) M = chromatic_adaptation_matrix_VonKries( xyY_to_XYZ(xy_to_xyY(illuminant_RGB)), xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)), transform=chromatic_adaptation_transform) XYZ = dot_vector(RGB_to_XYZ_matrix, RGB) XYZ_a = dot_vector(M, XYZ) return XYZ_a
def XYZ_to_hdr_CIELab( XYZ, illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65'], Y_s=0.2, Y_abs=100, method='Fairchild 2011'): """ Converts from *CIE XYZ* tristimulus values to *hdr-CIELAB* colourspace. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. illuminant : array_like, optional Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY* 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 *hdr-CIELAB* colourspace array. Notes ----- +----------------+-------------------------+---------------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +================+=========================+=====================+ | ``XYZ`` | [0, 1] | [0, 1] | +----------------+-------------------------+---------------------+ | ``illuminant`` | [0, 1] | [0, 1] | +----------------+-------------------------+---------------------+ | ``Y_s`` | [0, 1] | [0, 1] | +----------------+-------------------------+---------------------+ +----------------+-------------------------+---------------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +================+=========================+=====================+ | ``Lab_hdr`` | ``L_hdr`` : [0, 100] | ``L_hdr`` : [0, 1] | | | | | | | ``a_hdr`` : [-100, 100] | ``a_hdr`` : [-1, 1] | | | | | | | ``b_hdr`` : [-100, 100] | ``b_hdr`` : [-1, 1] | +----------------+-------------------------+---------------------+ - Conversion to polar coordinates to compute the *chroma* :math:`C_{hdr}` and *hue* :math:`h_{hdr}` correlates can be safely performed with :func:`colour.Lab_to_LCHab` definition. - Conversion to cartesian coordinates from the *Lightness* :math:`L_{hdr}`, *chroma* :math:`C_{hdr}` and *hue* :math:`h_{hdr}` correlates can be safely performed with :func:`colour.LCHab_to_Lab` definition. References ---------- :cite:`Fairchild2010`, :cite:`Fairchild2011` Examples -------- >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) >>> XYZ_to_hdr_CIELab(XYZ) # doctest: +ELLIPSIS array([ 51.8700206..., 60.4763385..., 32.1455191...]) >>> XYZ_to_hdr_CIELab(XYZ, method='Fairchild 2010') # doctest: +ELLIPSIS array([ 31.9962111..., 128.0076303..., 48.7695230...]) """ X, Y, Z = tsplit(to_domain_1(XYZ)) X_n, Y_n, Z_n = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant))) method_l = method.lower() assert method.lower() in [ m.lower() for m in HDR_CIELAB_METHODS ], ('"{0}" method is invalid, must be one of {1}!'.format( method, HDR_CIELAB_METHODS)) if method_l == 'fairchild 2010': lightness_callable = lightness_Fairchild2010 else: lightness_callable = lightness_Fairchild2011 e = exponent_hdr_CIELab(Y_s, Y_abs, method) # Domain and range scaling has already be handled. with domain_range_scale('ignore'): L_hdr = lightness_callable(Y / Y_n, e) a_hdr = 5 * (lightness_callable(X / X_n, e) - L_hdr) b_hdr = 2 * (L_hdr - lightness_callable(Z / Z_n, e)) Lab_hdr = tstack([L_hdr, a_hdr, b_hdr]) return from_range_100(Lab_hdr)
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)