def test_domain_range_scale_XYZ_to_CAM16(self): """ Tests :func:`colour.appearance.cam16.XYZ_to_CAM16` definition domain and range scale support. """ 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 = CAM16_VIEWING_CONDITIONS['Average'] specification = XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround)[:-1] d_r = ( ('reference', 1, 1), (1, 0.01, np.array([1, 1, 1 / 360, 1, 1, 1, 1 / 360])), (100, 1, np.array([1, 1, 100 / 360, 1, 1, 1, 100 / 360])), ) for scale, factor_a, factor_b in d_r: with domain_range_scale(scale): np.testing.assert_almost_equal( XYZ_to_CAM16(XYZ * factor_a, XYZ_w * factor_a, L_A, Y_b, surround)[:-1], specification * factor_b, decimal=7)
def test_domain_range_scale_XYZ_to_CAM16(self): """ Test :func:`colour.appearance.cam16.XYZ_to_CAM16` definition domain and range scale support. """ 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 surround = VIEWING_CONDITIONS_CAM16["Average"] specification = XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround) d_r = ( ("reference", 1, 1), ( "1", 0.01, np.array([ 1 / 100, 1 / 100, 1 / 360, 1 / 100, 1 / 100, 1 / 100, 1 / 400, np.nan, ]), ), ( "100", 1, np.array([1, 1, 100 / 360, 1, 1, 1, 100 / 400, np.nan]), ), ) for scale, factor_a, factor_b in d_r: with domain_range_scale(scale): np.testing.assert_almost_equal( XYZ_to_CAM16(XYZ * factor_a, XYZ_w * factor_a, L_A, Y_b, surround), as_float_array(specification) * factor_b, decimal=7, )
def test_nan_XYZ_to_CAM16(self): """ Tests :func:`colour.appearance.cam16.XYZ_to_CAM16` 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: XYZ = np.array(case) XYZ_w = np.array(case) L_A = case[0] Y_b = case[0] surround = CAM16_InductionFactors(case[0], case[0], case[0]) XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround)
def test_n_dimensional_XYZ_to_CAM16(self): """ Test :func:`colour.appearance.cam16.XYZ_to_CAM16` definition n-dimensional support. """ 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 surround = VIEWING_CONDITIONS_CAM16["Average"] specification = XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround) XYZ = np.tile(XYZ, (6, 1)) specification = np.tile(specification, (6, 1)) np.testing.assert_almost_equal( XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround), specification, decimal=7, ) XYZ_w = np.tile(XYZ_w, (6, 1)) np.testing.assert_almost_equal( XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround), specification, decimal=7, ) XYZ = np.reshape(XYZ, (2, 3, 3)) XYZ_w = np.reshape(XYZ_w, (2, 3, 3)) specification = np.reshape(specification, (2, 3, 8)) np.testing.assert_almost_equal( XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround), specification, decimal=7, )
def output_specification_from_data(self, data): """ Returns the *CAM16* colour appearance model output specification from given data. Parameters ---------- data : list Fixture data. Returns ------- CAM16_Specification *CAM16* colour appearance model specification. """ XYZ = tstack([data['X'], data['Y'], data['Z']]) XYZ_w = tstack([data['X_w'], data['Y_w'], data['Z_w']]) specification = XYZ_to_CAM16( XYZ, XYZ_w, data['L_A'], data['Y_b'], CAM16_InductionFactors(data['F'], data['c'], data['N_c'])) return specification
def XYZ_to_UCS_Li2017(XYZ: ArrayLike, coefficients: ArrayLike, **kwargs: Any) -> NDArray: """ Convert from *CIE XYZ* tristimulus values to one of the *Li et al. (2017)* *CAM16-LCD*, *CAM16-SCD*, or *CAM16-UCS* colourspaces :math:`J'a'b'` array. Parameters ---------- XYZ *CIE XYZ* tristimulus values. coefficients Coefficients of one of the *Li et al. (2017)* *CAM16-LCD*, *CAM16-SCD*, or *CAM16-UCS* colourspaces. Other Parameters ---------------- kwargs {:func:`colour.XYZ_to_CAM16`}, See the documentation of the previously listed definition. The default viewing conditions are that of *IEC 61966-2-1:1999*, i.e. *sRGB* 64 Lux ambient illumination, 80 :math:`cd/m^2`, adapting field luminance about 20% of a white object in the scene. Returns ------- :class:`numpy.ndarray` *Li et al. (2017)* *CAM16-LCD*, *CAM16-SCD*, or *CAM16-UCS* colourspaces :math:`J'a'b'` array. Warnings -------- The ``XYZ_w`` parameter for :func:`colour.XYZ_to_CAM16` definition must be given in the same domain-range scale than the ``XYZ`` parameter. Notes ----- +------------+------------------------+------------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+========================+==================+ | ``XYZ`` | [0, 1] | [0, 1] | +------------+------------------------+------------------+ +------------+------------------------+------------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+========================+==================+ | ``Jpapbp`` | ``Jp`` : [0, 100] | ``Jp`` : [0, 1] | | | | | | | ``ap`` : [-100, 100] | ``ap`` : [-1, 1] | | | | | | | ``bp`` : [-100, 100] | ``bp`` : [-1, 1] | +------------+------------------------+------------------+ Examples -------- >>> import numpy as np >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) >>> XYZ_to_UCS_Li2017(XYZ, COEFFICIENTS_UCS_LUO2006['CAM02-LCD']) ... # doctest: +ELLIPSIS array([ 46.0658603..., 41.0758649..., 14.5102582...]) >>> from colour.appearance import CAM_KWARGS_CIECAM02_sRGB >>> XYZ_w = CAM_KWARGS_CIECAM02_sRGB['XYZ_w'] >>> XYZ_to_UCS_Li2017( ... XYZ, COEFFICIENTS_UCS_LUO2006['CAM02-LCD'], XYZ_w=XYZ_w / 100) ... # doctest: +ELLIPSIS array([ 46.0658603..., 41.0758649..., 14.5102582...]) """ from colour.appearance import CAM_KWARGS_CIECAM02_sRGB, XYZ_to_CAM16 domain_range_reference = get_domain_range_scale() == "reference" settings = CAM_KWARGS_CIECAM02_sRGB.copy() settings.update(**kwargs) XYZ_w = kwargs.get("XYZ_w") if XYZ_w is not None and domain_range_reference: settings["XYZ_w"] = XYZ_w * 100 if domain_range_reference: XYZ = as_float_array(XYZ) * 100 specification = XYZ_to_CAM16(XYZ, **settings) JMh = tstack([specification.J, specification.M, specification.h]) return JMh_CAM16_to_UCS_Li2017(JMh, coefficients)
def test_XYZ_to_CAM16(self): """Test :func:`colour.appearance.cam16.XYZ_to_CAM16` definition.""" 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 surround = VIEWING_CONDITIONS_CAM16["Average"] np.testing.assert_almost_equal( XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround), np.array([ 41.73120791, 0.10335574, 217.06795977, 2.34501507, 195.37170899, 0.10743677, 275.59498615, np.nan, ]), decimal=7, ) XYZ = np.array([57.06, 43.06, 31.96]) L_A = 31.83 np.testing.assert_almost_equal( XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround), np.array([ 65.42828069, 49.67956420, 17.48659243, 52.94308868, 152.06985268, 42.62473321, 398.03047943, np.nan, ]), decimal=7, ) XYZ = np.array([3.53, 6.56, 2.14]) XYZ_w = np.array([109.85, 100, 35.58]) L_A = 318.31 np.testing.assert_almost_equal( XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround), np.array([ 21.36052893, 50.99381895, 178.86724266, 61.57953092, 139.78582768, 53.00732582, 223.01823806, np.nan, ]), decimal=7, ) XYZ = np.array([19.01, 20.00, 21.78]) L_A = 318.31 np.testing.assert_almost_equal( XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround), np.array([ 41.36326063, 52.81154022, 258.88676291, 53.12406914, 194.52011798, 54.89682038, 311.24768647, np.nan, ]), decimal=7, ) XYZ = np.array([61.45276998, 7.00421901, 82.2406738]) XYZ_w = np.array([95.05, 100.00, 108.88]) L_A = 4.074366543152521 np.testing.assert_almost_equal( XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround), np.array([ 21.03801957, 457.78881613, 350.06445098, 241.50642846, 56.74143988, 330.94646237, 376.43915877, np.nan, ]), decimal=7, )