def test_nan_uv_to_CCT_Robertson1968(self): """ Tests :func:`colour.temperature.cct.uv_to_CCT_Robertson1968` definition nan support. """ cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] cases = set(permutations(cases * 3, r=2)) for case in cases: uv = np.array(case) uv_to_CCT_Robertson1968(uv)
def test_nan_uv_to_CCT_Robertson1968(self): """ Test :func:`colour.temperature.robertson1968.uv_to_CCT_Robertson1968` definition nan support. """ cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] cases = set(permutations(cases * 3, r=2)) for case in cases: uv = np.array(case) uv_to_CCT_Robertson1968(uv)
def test_n_dimensional_uv_to_CCT_Robertson1968(self): """ Tests :func:`colour.temperature.cct.uv_to_CCT_Robertson1968` definition n-dimensional arrays support. """ uv = np.array([0.1978, 0.3122]) CCT_D_uv = uv_to_CCT_Robertson1968(uv) uv = np.tile(uv, (6, 1)) CCT_D_uv = np.tile(CCT_D_uv, (6, 1)) np.testing.assert_almost_equal( uv_to_CCT_Robertson1968(uv), CCT_D_uv, decimal=7) uv = np.reshape(uv, (2, 3, 2)) CCT_D_uv = np.reshape(CCT_D_uv, (2, 3, 2)) np.testing.assert_almost_equal( uv_to_CCT_Robertson1968(uv), CCT_D_uv, decimal=7)
def test_uv_to_CCT_Robertson1968(self): """ Tests :func:`colour.temperature.cct.uv_to_CCT_Robertson1968` definition. """ for key, value in TEMPERATURE_DUV_TO_UV.items(): np.testing.assert_allclose( uv_to_CCT_Robertson1968(value), key, atol=0.25)
def test_uv_to_CCT_Robertson1968(self): """ Tests :func:`colour.temperature.cct.uv_to_CCT_Robertson1968` definition. """ for key, value in TEMPERATURE_DUV_TO_UV.items(): np.testing.assert_allclose(uv_to_CCT_Robertson1968(value), key, atol=0.25)
def test_n_dimensional_uv_to_CCT_Robertson1968(self): """ Test :func:`colour.temperature.robertson1968.uv_to_CCT_Robertson1968` definition n-dimensional arrays support. """ uv = np.array([0.1978, 0.3122]) CCT_D_uv = uv_to_CCT_Robertson1968(uv) uv = np.tile(uv, (6, 1)) CCT_D_uv = np.tile(CCT_D_uv, (6, 1)) np.testing.assert_almost_equal(uv_to_CCT_Robertson1968(uv), CCT_D_uv, decimal=7) uv = np.reshape(uv, (2, 3, 2)) CCT_D_uv = np.reshape(CCT_D_uv, (2, 3, 2)) np.testing.assert_almost_equal(uv_to_CCT_Robertson1968(uv), CCT_D_uv, decimal=7)
def colour_rendering_index(spd_test, additional_data=False): """ Returns the *colour rendering index* :math:`Q_a` of given spectral power distribution. Parameters ---------- spd_test : SpectralPowerDistribution Test spectral power distribution. additional_data : bool, optional Output additional data. Returns ------- numeric or CRI_Specification Colour rendering index. Examples -------- >>> from colour import ILLUMINANTS_RELATIVE_SPDS >>> spd = ILLUMINANTS_RELATIVE_SPDS.get('F2') >>> colour_rendering_index(spd) # doctest: +ELLIPSIS 64.1507331... """ cmfs = STANDARD_OBSERVERS_CMFS.get('CIE 1931 2 Degree Standard Observer') shape = cmfs.shape spd_test = spd_test.clone().align(shape) tcs_spds = {} for index, tcs_spd in TCS_SPDS.items(): tcs_spds[index] = tcs_spd.clone().align(shape) XYZ = spectral_to_XYZ(spd_test, cmfs) uv = UCS_to_uv(XYZ_to_UCS(XYZ)) CCT, _D_uv = uv_to_CCT_Robertson1968(uv) if CCT < 5000: spd_reference = blackbody_spd(CCT, shape) else: xy = CCT_to_xy_CIE_D(CCT) spd_reference = D_illuminant_relative_spd(xy) spd_reference.align(shape) test_tcs_colorimetry_data = tcs_colorimetry_data( spd_test, spd_reference, tcs_spds, cmfs, chromatic_adaptation=True) reference_tcs_colorimetry_data = tcs_colorimetry_data( spd_reference, spd_reference, tcs_spds, cmfs) Q_as = colour_rendering_indexes( test_tcs_colorimetry_data, reference_tcs_colorimetry_data) Q_a = np.average([v.Q_a for k, v in Q_as.items() if k in (1, 2, 3, 4, 5, 6, 7, 8)]) if additional_data: return CRI_Specification(spd_test.name, Q_a, Q_as, (test_tcs_colorimetry_data, reference_tcs_colorimetry_data)) else: return Q_a
def colour_rendering_index(sd_test, additional_data=False): """ Returns the *Colour Rendering Index* (CRI) :math:`Q_a` of given spectral distribution. Parameters ---------- sd_test : SpectralDistribution Test spectral distribution. additional_data : bool, optional Whether to output additional data. Returns ------- numeric or CRI_Specification *Colour Rendering Index* (CRI). References ---------- :cite:`Ohno2008a` Examples -------- >>> from colour import ILLUMINANTS_SDS >>> sd = ILLUMINANTS_SDS['FL2'] >>> colour_rendering_index(sd) # doctest: +ELLIPSIS 64.1515202... """ cmfs = STANDARD_OBSERVERS_CMFS['CIE 1931 2 Degree Standard Observer'].copy( ).trim(DEFAULT_SPECTRAL_SHAPE) shape = cmfs.shape sd_test = sd_test.copy().align(shape) tcs_sds = {sd.name: sd.copy().align(shape) for sd in TCS_SDS.values()} with domain_range_scale('1'): XYZ = sd_to_XYZ(sd_test, cmfs) uv = UCS_to_uv(XYZ_to_UCS(XYZ)) CCT, _D_uv = uv_to_CCT_Robertson1968(uv) if CCT < 5000: sd_reference = sd_blackbody(CCT, shape) else: xy = CCT_to_xy_CIE_D(CCT) sd_reference = sd_CIE_illuminant_D_series(xy) sd_reference.align(shape) test_tcs_colorimetry_data = tcs_colorimetry_data(sd_test, sd_reference, tcs_sds, cmfs, chromatic_adaptation=True) reference_tcs_colorimetry_data = tcs_colorimetry_data( sd_reference, sd_reference, tcs_sds, cmfs) Q_as = colour_rendering_indexes(test_tcs_colorimetry_data, reference_tcs_colorimetry_data) Q_a = np.average( [v.Q_a for k, v in Q_as.items() if k in (1, 2, 3, 4, 5, 6, 7, 8)]) if additional_data: return CRI_Specification( sd_test.name, Q_a, Q_as, (test_tcs_colorimetry_data, reference_tcs_colorimetry_data)) else: return Q_a
def colour_rendering_index(spd_test, additional_data=False): """ Returns the *Colour Rendering Index* (CRI) :math:`Q_a` of given spectral power distribution. Parameters ---------- spd_test : SpectralPowerDistribution Test spectral power distribution. additional_data : bool, optional Output additional data. Returns ------- numeric or CRI_Specification *Colour Rendering Index* (CRI). Examples -------- >>> from colour import ILLUMINANTS_RELATIVE_SPDS >>> spd = ILLUMINANTS_RELATIVE_SPDS['F2'] >>> colour_rendering_index(spd) # doctest: +ELLIPSIS 64.1515202... """ cmfs = STANDARD_OBSERVERS_CMFS[ 'CIE 1931 2 Degree Standard Observer'].clone().trim_wavelengths( ASTME30815_PRACTISE_SHAPE) shape = cmfs.shape spd_test = spd_test.clone().align(shape) tcs_spds = { spd.name: spd.clone().align(shape) for spd in TCS_SPDS.values() } XYZ = spectral_to_XYZ(spd_test, cmfs) uv = UCS_to_uv(XYZ_to_UCS(XYZ)) CCT, _D_uv = uv_to_CCT_Robertson1968(uv) if CCT < 5000: spd_reference = blackbody_spd(CCT, shape) else: xy = CCT_to_xy_CIE_D(CCT) spd_reference = D_illuminant_relative_spd(xy) spd_reference.align(shape) test_tcs_colorimetry_data = tcs_colorimetry_data( spd_test, spd_reference, tcs_spds, cmfs, chromatic_adaptation=True) reference_tcs_colorimetry_data = tcs_colorimetry_data( spd_reference, spd_reference, tcs_spds, cmfs) Q_as = colour_rendering_indexes(test_tcs_colorimetry_data, reference_tcs_colorimetry_data) Q_a = np.average( [v.Q_a for k, v in Q_as.items() if k in (1, 2, 3, 4, 5, 6, 7, 8)]) if additional_data: return CRI_Specification(spd_test.name, Q_a, Q_as, (test_tcs_colorimetry_data, reference_tcs_colorimetry_data)) else: return Q_a
def camera_space_to_XYZ_matrix(xy, CCT_calibration_illuminant_1, CCT_calibration_illuminant_2, M_color_matrix_1, M_color_matrix_2, M_camera_calibration_1, M_camera_calibration_2, analog_balance, M_forward_matrix_1, M_forward_matrix_2, chromatic_adaptation_transform='Bradford'): """ Returns the *Camera Space* to *CIE XYZ* matrix for given *xy* white balance chromaticity coordinates. Parameters ---------- xy : array_like *xy* white balance chromaticity coordinates. CCT_calibration_illuminant_1 : numeric Correlated colour temperature of *CalibrationIlluminant1*. CCT_calibration_illuminant_2 : numeric Correlated colour temperature of *CalibrationIlluminant2*. M_color_matrix_1 : array_like *ColorMatrix1* tag matrix. M_color_matrix_2 : array_like *ColorMatrix2* tag matrix. M_camera_calibration_1 : array_like *CameraCalibration1* tag matrix. M_camera_calibration_2 : array_like *CameraCalibration2* tag matrix. analog_balance : array_like *AnalogBalance* tag vector. M_forward_matrix_1 : array_like *ForwardMatrix1* tag matrix. M_forward_matrix_2 : array_like *ForwardMatrix2* tag 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. Returns ------- ndarray *Camera Space* to *CIE XYZ* matrix. Notes ----- - The reference illuminant is D50 as defined per :attr:`colour_hdri.models.dataset.dng.ADOBE_DNG_XYZ_ILLUMINANT` attribute. References ---------- - :cite:`AdobeSystems2012f` - :cite:`AdobeSystems2012g` - :cite:`AdobeSystems2015d` - :cite:`McGuffog2012a` Examples -------- >>> M_color_matrix_1 = np.array( ... [[0.5309, -0.0229, -0.0336], ... [-0.6241, 1.3265, 0.3337], ... [-0.0817, 0.1215, 0.6664]]) >>> M_color_matrix_2 = np.array( ... [[0.4716, 0.0603, -0.0830], ... [-0.7798, 1.5474, 0.2480], ... [-0.1496, 0.1937, 0.6651]]) >>> M_camera_calibration_1 = np.identity(3) >>> M_camera_calibration_2 = np.identity(3) >>> analog_balance = np.ones(3) >>> M_forward_matrix_1 = np.array( ... [[0.8924, -0.1041, 0.1760], ... [0.4351, 0.6621, -0.0972], ... [0.0505, -0.1562, 0.9308]]) >>> M_forward_matrix_2 = np.array( ... [[0.8924, -0.1041, 0.1760], ... [0.4351, 0.6621, -0.0972], ... [0.0505, -0.1562, 0.9308]]) >>> camera_space_to_XYZ_matrix( # doctest: +ELLIPSIS ... np.array([0.32816244, 0.34698169]), ... 2850, ... 6500, ... M_color_matrix_1, ... M_color_matrix_2, ... M_camera_calibration_1, ... M_camera_calibration_2, ... analog_balance, ... M_forward_matrix_1, ... M_forward_matrix_2) array([[ 2.1604087..., -0.1041... , 0.2722498...], [ 1.0533324..., 0.6621... , -0.1503561...], [ 0.1222553..., -0.1562... , 1.4398304...]]) """ # *ForwardMatrix1* and *ForwardMatrix2* are not included in the camera # profile. if is_identity(M_forward_matrix_1) and is_identity(M_forward_matrix_2): M_camera_to_XYZ = np.linalg.inv( XYZ_to_camera_space_matrix(xy, CCT_calibration_illuminant_1, CCT_calibration_illuminant_2, M_color_matrix_1, M_color_matrix_2, M_camera_calibration_1, M_camera_calibration_2, analog_balance)) M_CAT = chromatic_adaptation_matrix_VonKries( xy_to_XYZ(xy), xy_to_XYZ(ADOBE_DNG_XYZ_ILLUMINANT), chromatic_adaptation_transform) M_camera_space_to_XYZ = dot_matrix(M_CAT, M_camera_to_XYZ) else: uv = UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(xy))) CCT, _D_uv = uv_to_CCT_Robertson1968(uv) M_CC = interpolated_matrix(CCT, CCT_calibration_illuminant_1, CCT_calibration_illuminant_2, M_camera_calibration_1, M_camera_calibration_2) # The reference implementation :cite:`AdobeSystems2015d` diverges from # the white-paper :cite:`AdobeSystems2012f`: # The reference implementation directly computes the camera neutral by # multiplying directly the interpolated colour matrix :math:`CM` with # the tristimulus values of the *xy* white balance chromaticity # coordinates. # The current implementation is based on the white-paper so that the # interpolated camera calibration matrix :math:`CC` and the # analog balance matrix :math:`AB` are accounted for. camera_neutral = xy_to_camera_neutral( xy, CCT_calibration_illuminant_1, CCT_calibration_illuminant_2, M_color_matrix_1, M_color_matrix_2, M_camera_calibration_1, M_camera_calibration_2, analog_balance) M_AB = np.diagflat(analog_balance) M_reference_neutral = dot_vector(np.linalg.inv(dot_matrix(M_AB, M_CC)), camera_neutral) M_D = np.linalg.inv(np.diagflat(M_reference_neutral)) M_FM = interpolated_matrix(CCT, CCT_calibration_illuminant_1, CCT_calibration_illuminant_2, M_forward_matrix_1, M_forward_matrix_2) M_camera_space_to_XYZ = dot_matrix( dot_matrix(M_FM, M_D), np.linalg.inv(dot_matrix(M_AB, M_CC))) return M_camera_space_to_XYZ
def XYZ_to_camera_space_matrix(xy, CCT_calibration_illuminant_1, CCT_calibration_illuminant_2, M_color_matrix_1, M_color_matrix_2, M_camera_calibration_1, M_camera_calibration_2, analog_balance): """ Returns the *CIE XYZ* to *Camera Space* matrix for given *xy* white balance chromaticity coordinates. Parameters ---------- xy : array_like *xy* white balance chromaticity coordinates. CCT_calibration_illuminant_1 : numeric Correlated colour temperature of *CalibrationIlluminant1*. CCT_calibration_illuminant_2 : numeric Correlated colour temperature of *CalibrationIlluminant2*. M_color_matrix_1 : array_like *ColorMatrix1* tag matrix. M_color_matrix_2 : array_like *ColorMatrix2* tag matrix. M_camera_calibration_1 : array_like *CameraCalibration1* tag matrix. M_camera_calibration_2 : array_like *CameraCalibration2* tag matrix. analog_balance : array_like *AnalogBalance* tag vector. Returns ------- ndarray *CIE XYZ* to *Camera Space* matrix. Notes ----- - The reference illuminant is D50 as defined per :attr:`colour_hdri.models.dataset.dng.ADOBE_DNG_XYZ_ILLUMINANT` attribute. References ---------- - :cite:`AdobeSystems2012f` - :cite:`AdobeSystems2015d` - :cite:`McGuffog2012a` Examples -------- >>> M_color_matrix_1 = np.array( ... [[0.5309, -0.0229, -0.0336], ... [-0.6241, 1.3265, 0.3337], ... [-0.0817, 0.1215, 0.6664]]) >>> M_color_matrix_2 = np.array( ... [[0.4716, 0.0603, -0.0830], ... [-0.7798, 1.5474, 0.2480], ... [-0.1496, 0.1937, 0.6651]]) >>> M_camera_calibration_1 = np.identity(3) >>> M_camera_calibration_2 = np.identity(3) >>> analog_balance = np.ones(3) >>> XYZ_to_camera_space_matrix( # doctest: +ELLIPSIS ... np.array([0.34510414, 0.35162252]), ... 2850, ... 6500, ... M_color_matrix_1, ... M_color_matrix_2, ... M_camera_calibration_1, ... M_camera_calibration_2, ... analog_balance) array([[ 0.4854908..., 0.0408106..., -0.0714282...], [-0.7433278..., 1.4956549..., 0.2680749...], [-0.1336946..., 0.1767874..., 0.6654045...]]) """ M_AB = np.diagflat(analog_balance) uv = UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(xy))) CCT, _D_uv = uv_to_CCT_Robertson1968(uv) if is_identity(M_color_matrix_1) or is_identity(M_color_matrix_2): M_CM = (M_color_matrix_1 if is_identity(M_color_matrix_2) else M_color_matrix_2) else: M_CM = interpolated_matrix(CCT, CCT_calibration_illuminant_1, CCT_calibration_illuminant_2, M_color_matrix_1, M_color_matrix_2) M_CC = interpolated_matrix(CCT, CCT_calibration_illuminant_1, CCT_calibration_illuminant_2, M_camera_calibration_1, M_camera_calibration_2) M_XYZ_to_camera_space = dot_matrix(dot_matrix(M_AB, M_CC), M_CM) return M_XYZ_to_camera_space
def colour_rendering_index(sd_test, additional_data=False): """ Returns the *Colour Rendering Index* (CRI) :math:`Q_a` of given spectral distribution. Parameters ---------- sd_test : SpectralDistribution Test spectral distribution. additional_data : bool, optional Whether to output additional data. Returns ------- numeric or CRI_Specification *Colour Rendering Index* (CRI). References ---------- :cite:`Ohno2008a` Examples -------- >>> from colour import ILLUMINANTS_SDS >>> sd = ILLUMINANTS_SDS['FL2'] >>> colour_rendering_index(sd) # doctest: +ELLIPSIS 64.1515202... """ cmfs = STANDARD_OBSERVERS_CMFS['CIE 1931 2 Degree Standard Observer'].copy( ).trim(ASTME30815_PRACTISE_SHAPE) shape = cmfs.shape sd_test = sd_test.copy().align(shape) tcs_sds = {sd.name: sd.copy().align(shape) for sd in TCS_SDS.values()} with domain_range_scale('1'): XYZ = sd_to_XYZ(sd_test, cmfs) uv = UCS_to_uv(XYZ_to_UCS(XYZ)) CCT, _D_uv = uv_to_CCT_Robertson1968(uv) if CCT < 5000: sd_reference = sd_blackbody(CCT, shape) else: xy = CCT_to_xy_CIE_D(CCT) sd_reference = sd_CIE_illuminant_D_series(xy) sd_reference.align(shape) test_tcs_colorimetry_data = tcs_colorimetry_data( sd_test, sd_reference, tcs_sds, cmfs, chromatic_adaptation=True) reference_tcs_colorimetry_data = tcs_colorimetry_data( sd_reference, sd_reference, tcs_sds, cmfs) Q_as = colour_rendering_indexes(test_tcs_colorimetry_data, reference_tcs_colorimetry_data) Q_a = np.average( [v.Q_a for k, v in Q_as.items() if k in (1, 2, 3, 4, 5, 6, 7, 8)]) if additional_data: return CRI_Specification( sd_test.name, Q_a, Q_as, (test_tcs_colorimetry_data, reference_tcs_colorimetry_data)) else: return Q_a
def colour_rendering_index( sd_test: SpectralDistribution, additional_data: Boolean = False ) -> Union[Floating, ColourRendering_Specification_CRI]: """ Return the *Colour Rendering Index* (CRI) :math:`Q_a` of given spectral distribution. Parameters ---------- sd_test Test spectral distribution. additional_data Whether to output additional data. Returns ------- :class:`numpy.floating` or \ :class:`colour.quality.ColourRendering_Specification_CRI` *Colour Rendering Index* (CRI). References ---------- :cite:`Ohno2008a` Examples -------- >>> from colour import SDS_ILLUMINANTS >>> sd = SDS_ILLUMINANTS['FL2'] >>> colour_rendering_index(sd) # doctest: +ELLIPSIS 64.2337241... """ # pylint: disable=E1102 cmfs = reshape_msds( MSDS_CMFS["CIE 1931 2 Degree Standard Observer"], SPECTRAL_SHAPE_DEFAULT, ) shape = cmfs.shape sd_test = reshape_sd(sd_test, shape) tcs_sds = {sd.name: reshape_sd(sd, shape) for sd in SDS_TCS.values()} with domain_range_scale("1"): XYZ = sd_to_XYZ(sd_test, cmfs) uv = UCS_to_uv(XYZ_to_UCS(XYZ)) CCT, _D_uv = uv_to_CCT_Robertson1968(uv) if CCT < 5000: sd_reference = sd_blackbody(CCT, shape) else: xy = CCT_to_xy_CIE_D(CCT) sd_reference = sd_CIE_illuminant_D_series(xy) sd_reference.align(shape) test_tcs_colorimetry_data = tcs_colorimetry_data( sd_test, sd_reference, tcs_sds, cmfs, chromatic_adaptation=True ) reference_tcs_colorimetry_data = tcs_colorimetry_data( sd_reference, sd_reference, tcs_sds, cmfs ) Q_as = colour_rendering_indexes( test_tcs_colorimetry_data, reference_tcs_colorimetry_data ) Q_a = as_float_scalar( np.average( [v.Q_a for k, v in Q_as.items() if k in (1, 2, 3, 4, 5, 6, 7, 8)] ) ) if additional_data: return ColourRendering_Specification_CRI( sd_test.name, Q_a, Q_as, (test_tcs_colorimetry_data, reference_tcs_colorimetry_data), ) else: return Q_a