def test_nan_uv_to_CCT_Ohno2013(self): """ Test :func:`colour.temperature.ohno2013.uv_to_CCT_Ohno2013` 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_Ohno2013(uv)
def test_nan_uv_to_CCT_Ohno2013(self): """ Tests :func:`colour.temperature.cct.uv_to_CCT_Ohno2013` 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_Ohno2013(uv)
def CCT_reference_illuminant(sd: SpectralDistribution) -> NDArray: """ Compute the reference illuminant correlated colour temperature :math:`T_{cp}` and :math:`\\Delta_{uv}` for given test spectral distribution using *Ohno (2013)* method. Parameters ---------- sd Test spectral distribution. Returns ------- :class:`numpy.ndarray` Correlated colour temperature :math:`T_{cp}`, :math:`\\Delta_{uv}`. Examples -------- >>> from colour import SDS_ILLUMINANTS >>> sd = SDS_ILLUMINANTS['FL2'] >>> CCT_reference_illuminant(sd) # doctest: +ELLIPSIS array([ 4.2244697...e+03, 1.7871111...e-03]) """ XYZ = sd_to_XYZ(sd) return uv_to_CCT_Ohno2013(UCS_to_uv(XYZ_to_UCS(XYZ)))
def CCT_reference_illuminant(sd): """ Computes the reference illuminant correlated colour temperature :math:`T_{cp}` and :math:`\\Delta_{uv}` for given test spectral distribution using *Ohno (2013)* method. Parameters ---------- sd : SpectralDistribution Test spectral distribution. Returns ------- ndarray Correlated colour temperature :math:`T_{cp}`, :math:`\\Delta_{uv}`. Examples -------- >>> from colour import SDS_ILLUMINANTS >>> sd = SDS_ILLUMINANTS['FL2'] >>> CCT_reference_illuminant(sd) # doctest: +ELLIPSIS (4224.4697052..., 0.0017871...) """ XYZ = sd_to_XYZ(sd) CCT, D_uv = uv_to_CCT_Ohno2013(UCS_to_uv(XYZ_to_UCS(XYZ))) return CCT, D_uv
def test_n_dimensional_uv_to_CCT_Ohno2013(self): """ Tests :func:`colour.temperature.cct.uv_to_CCT_Ohno2013` definition n-dimensional arrays support. """ uv = np.array([0.1978, 0.3122]) CCT_D_uv = uv_to_CCT_Ohno2013(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_Ohno2013(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_Ohno2013(uv), CCT_D_uv, decimal=7)
def test_uv_to_CCT_Ohno2013(self): """ Tests :func:`colour.temperature.cct.uv_to_CCT_Ohno2013` definition. """ cmfs = STANDARD_OBSERVERS_CMFS['CIE 1931 2 Degree Standard Observer'] np.testing.assert_almost_equal( uv_to_CCT_Ohno2013(np.array([0.1978, 0.3122]), cmfs), np.array([6507.47380460, 0.00322335]), decimal=7) np.testing.assert_almost_equal( uv_to_CCT_Ohno2013(np.array([0.4328, 0.2883]), cmfs), np.array([1041.68315360, -0.06737802]), decimal=7) np.testing.assert_almost_equal( uv_to_CCT_Ohno2013(np.array([0.2927, 0.2722]), cmfs, iterations=4), np.array([2452.15316417, -0.08437064]), decimal=7)
def test_n_dimensional_uv_to_CCT_Ohno2013(self): """ Test :func:`colour.temperature.ohno2013.uv_to_CCT_Ohno2013` definition n-dimensional arrays support. """ uv = np.array([0.1978, 0.3122]) CCT_D_uv = uv_to_CCT_Ohno2013(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_Ohno2013(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_Ohno2013(uv), CCT_D_uv, decimal=7)
def test_uv_to_CCT_Ohno2013(self): """ Tests :func:`colour.temperature.cct.uv_to_CCT_Ohno2013` definition. """ cmfs = STANDARD_OBSERVERS_CMFS['CIE 1931 2 Degree Standard Observer'] np.testing.assert_almost_equal( uv_to_CCT_Ohno2013(np.array([0.1978, 0.3122]), cmfs), np.array([6507.51282029, 0.00322336]), decimal=7) np.testing.assert_almost_equal( uv_to_CCT_Ohno2013(np.array([0.4328, 0.2883]), cmfs), np.array([1041.68315360, -0.06737802]), decimal=7) np.testing.assert_almost_equal( uv_to_CCT_Ohno2013(np.array([0.2927, 0.2722]), cmfs, iterations=4), np.array([2452.15316417, -0.08437064]), decimal=7)
def test_uv_to_CCT_Ohno2013(self): """ Tests :func:`colour.temperature.cct.uv_to_CCT_Ohno2013` definition. """ cmfs = STANDARD_OBSERVERS_CMFS.get( 'CIE 1931 2 Degree Standard Observer') np.testing.assert_almost_equal( uv_to_CCT_Ohno2013(np.array([0.1978, 0.3122]), cmfs), np.array([6507.5470349001507, 0.0032236908012382953]), decimal=7) np.testing.assert_almost_equal( uv_to_CCT_Ohno2013(np.array([0.4328, 0.2883]), cmfs), np.array([1041.8672179878763, -0.067377582642145384]), decimal=7) np.testing.assert_almost_equal( uv_to_CCT_Ohno2013(np.array([0.2927, 0.2722]), cmfs, iterations=4), np.array([2452.1932942782669, -0.084369982045528508]), decimal=7)
def test_uv_to_CCT_Ohno2013(self): """ Test :func:`colour.temperature.ohno2013.uv_to_CCT_Ohno2013` definition. """ np.testing.assert_almost_equal( uv_to_CCT_Ohno2013(np.array([0.1978, 0.3122])), np.array([6507.47380460, 0.00322335]), decimal=7, ) np.testing.assert_almost_equal( uv_to_CCT_Ohno2013(np.array([0.4328, 0.2883])), np.array([1041.68315360, -0.06737802]), decimal=7, ) np.testing.assert_almost_equal( uv_to_CCT_Ohno2013(np.array([0.2927, 0.2722]), iterations=4), np.array([2452.15316417, -0.08437064]), decimal=7, )
def colour_quality_scale(spd_test, additional_data=False): """ Returns the *colour quality scale* of given spectral power distribution. Parameters ---------- spd_test : SpectralPowerDistribution Test spectral power distribution. additional_data : bool, optional Output additional data. Returns ------- numeric or CQS_Specification Color quality scale. Examples -------- >>> from colour import ILLUMINANTS_RELATIVE_SPDS >>> spd = ILLUMINANTS_RELATIVE_SPDS.get('F2') >>> colour_quality_scale(spd) # doctest: +ELLIPSIS 64.6781117... """ cmfs = STANDARD_OBSERVERS_CMFS.get( 'CIE 1931 2 Degree Standard Observer') shape = cmfs.shape XYZ = spectral_to_XYZ(spd_test, cmfs) uv = UCS_to_uv(XYZ_to_UCS(XYZ)) CCT, _D_uv = uv_to_CCT_Ohno2013(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_vs_colorimetry_data = vs_colorimetry_data( spd_test, spd_reference, VS_SPDS, cmfs, chromatic_adaptation=True) reference_vs_colorimetry_data = vs_colorimetry_data( spd_reference, spd_reference, VS_SPDS, cmfs) XYZ_r = spectral_to_XYZ(spd_reference, cmfs) XYZ_r /= XYZ_r[1] CCT_f = CCT_factor(reference_vs_colorimetry_data, XYZ_r) Q_as = colour_quality_scales( test_vs_colorimetry_data, reference_vs_colorimetry_data, CCT_f) D_E_RMS = delta_E_RMS(Q_as, 'D_E_ab') D_Ep_RMS = delta_E_RMS(Q_as, 'D_Ep_ab') Q_a = scale_conversion(D_Ep_RMS, CCT_f) Q_f = scale_conversion(D_E_RMS, CCT_f, 2.928) p_delta_C = np.average( [sample_data.D_C_ab if sample_data.D_C_ab > 0 else 0 for sample_data in Q_as.values()]) Q_p = 100 - 3.6 * (D_Ep_RMS - p_delta_C) G_t = gamut_area([vs_CQS_data.Lab for vs_CQS_data in test_vs_colorimetry_data]) G_r = gamut_area([vs_CQS_data.Lab for vs_CQS_data in reference_vs_colorimetry_data]) Q_g = G_t / D65_GAMUT_AREA * 100 Q_d = G_t / G_r * CCT_f * 100 if additional_data: return CQS_Specification(spd_test.name, Q_a, Q_f, Q_p, Q_g, Q_d, Q_as, (test_vs_colorimetry_data, reference_vs_colorimetry_data)) else: return Q_a
def colour_quality_scale(sd_test, additional_data=False, method='NIST CQS 9.0'): """ Returns the *Colour Quality Scale* (CQS) of given spectral distribution using given method. Parameters ---------- sd_test : SpectralDistribution Test spectral distribution. additional_data : bool, optional Whether to output additional data. method : unicode, optional **{'NIST CQS 9.0', 'NIST CQS 7.4'}**, Computation method. Returns ------- numeric or CQS_Specification Color quality scale. References ---------- :cite:`Davis2010a`, :cite:`Ohno2008a`, :cite:`Ohno2013` Examples -------- >>> from colour import ILLUMINANTS_SDS >>> sd = ILLUMINANTS_SDS['FL2'] >>> colour_quality_scale(sd) # doctest: +ELLIPSIS 64.0172835... """ method = method.lower() assert method.lower() in [ m.lower() for m in COLOUR_QUALITY_SCALE_METHODS ], ('"{0}" method is invalid, must be one of {1}!'.format( method, COLOUR_QUALITY_SCALE_METHODS)) 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) vs_sds = { sd.name: sd.copy().align(shape) for sd in VS_SDS[method].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_Ohno2013(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_vs_colorimetry_data = vs_colorimetry_data(sd_test, sd_reference, vs_sds, cmfs, chromatic_adaptation=True) reference_vs_colorimetry_data = vs_colorimetry_data( sd_reference, sd_reference, vs_sds, cmfs) if method == 'nist cqs 9.0': CCT_f = 1 scaling_f = 3.2 else: XYZ_r = sd_to_XYZ(sd_reference, cmfs) XYZ_r /= XYZ_r[1] CCT_f = CCT_factor(reference_vs_colorimetry_data, XYZ_r) scaling_f = 3.104 Q_as = colour_quality_scales(test_vs_colorimetry_data, reference_vs_colorimetry_data, scaling_f, CCT_f) D_E_RMS = delta_E_RMS(Q_as, 'D_E_ab') D_Ep_RMS = delta_E_RMS(Q_as, 'D_Ep_ab') Q_a = scale_conversion(D_Ep_RMS, CCT_f, scaling_f) if method == 'nist cqs 9.0': scaling_f = 2.93 * 1.0343 else: scaling_f = 2.928 Q_f = scale_conversion(D_E_RMS, CCT_f, scaling_f) G_t = gamut_area( [vs_CQS_data.Lab for vs_CQS_data in test_vs_colorimetry_data]) G_r = gamut_area( [vs_CQS_data.Lab for vs_CQS_data in reference_vs_colorimetry_data]) Q_g = G_t / D65_GAMUT_AREA * 100 if method == 'nist cqs 9.0': Q_d = Q_p = None else: p_delta_C = np.average([ sample_data.D_C_ab if sample_data.D_C_ab > 0 else 0 for sample_data in Q_as.values() ]) Q_p = 100 - 3.6 * (D_Ep_RMS - p_delta_C) Q_d = G_t / G_r * CCT_f * 100 if additional_data: return CQS_Specification( sd_test.name, Q_a, Q_f, Q_p, Q_g, Q_d, Q_as, (test_vs_colorimetry_data, reference_vs_colorimetry_data)) else: return Q_a
def colour_quality_scale(spd_test, additional_data=False): """ Returns the *Colour Quality Scale* (CQS) of given spectral power distribution. Parameters ---------- spd_test : SpectralPowerDistribution Test spectral power distribution. additional_data : bool, optional Output additional data. Returns ------- numeric or CQS_Specification Color quality scale. Examples -------- >>> from colour import ILLUMINANTS_RELATIVE_SPDS >>> spd = ILLUMINANTS_RELATIVE_SPDS['F2'] >>> colour_quality_scale(spd) # doctest: +ELLIPSIS 64.6864169... """ 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) vs_spds = {spd.name: spd.clone().align(shape) for spd in VS_SPDS.values()} XYZ = spectral_to_XYZ(spd_test, cmfs) uv = UCS_to_uv(XYZ_to_UCS(XYZ)) CCT, _D_uv = uv_to_CCT_Ohno2013(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_vs_colorimetry_data = vs_colorimetry_data(spd_test, spd_reference, vs_spds, cmfs, chromatic_adaptation=True) reference_vs_colorimetry_data = vs_colorimetry_data( spd_reference, spd_reference, vs_spds, cmfs) XYZ_r = spectral_to_XYZ(spd_reference, cmfs) XYZ_r /= XYZ_r[1] CCT_f = CCT_factor(reference_vs_colorimetry_data, XYZ_r) Q_as = colour_quality_scales(test_vs_colorimetry_data, reference_vs_colorimetry_data, CCT_f) D_E_RMS = delta_E_RMS(Q_as, 'D_E_ab') D_Ep_RMS = delta_E_RMS(Q_as, 'D_Ep_ab') Q_a = scale_conversion(D_Ep_RMS, CCT_f) Q_f = scale_conversion(D_E_RMS, CCT_f, 2.928) p_delta_C = np.average( [sample_data.D_C_ab if sample_data.D_C_ab > 0 else 0 for sample_data in Q_as.values()]) # yapf: disable Q_p = 100 - 3.6 * (D_Ep_RMS - p_delta_C) G_t = gamut_area( [vs_CQS_data.Lab for vs_CQS_data in test_vs_colorimetry_data]) G_r = gamut_area( [vs_CQS_data.Lab for vs_CQS_data in reference_vs_colorimetry_data]) Q_g = G_t / D65_GAMUT_AREA * 100 Q_d = G_t / G_r * CCT_f * 100 if additional_data: return CQS_Specification( spd_test.name, Q_a, Q_f, Q_p, Q_g, Q_d, Q_as, (test_vs_colorimetry_data, reference_vs_colorimetry_data)) else: return Q_a
def colour_quality_scale(sd_test, additional_data=False, method='NIST CQS 9.0'): """ Returns the *Colour Quality Scale* (CQS) of given spectral distribution using given method. Parameters ---------- sd_test : SpectralDistribution Test spectral distribution. additional_data : bool, optional Whether to output additional data. method : unicode, optional **{'NIST CQS 9.0', 'NIST CQS 7.4'}**, Computation method. Returns ------- numeric or CQS_Specification Color quality scale. References ---------- :cite:`Davis2010a`, :cite:`Ohno2008a`, :cite:`Ohno2013` Examples -------- >>> from colour import ILLUMINANTS_SDS >>> sd = ILLUMINANTS_SDS['FL2'] >>> colour_quality_scale(sd) # doctest: +ELLIPSIS 64.0172835... """ method = method.lower() assert method.lower() in [ m.lower() for m in COLOUR_QUALITY_SCALE_METHODS ], ('"{0}" method is invalid, must be one of {1}!'.format( method, COLOUR_QUALITY_SCALE_METHODS)) 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) vs_sds = { sd.name: sd.copy().align(shape) for sd in VS_SDS[method].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_Ohno2013(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_vs_colorimetry_data = vs_colorimetry_data( sd_test, sd_reference, vs_sds, cmfs, chromatic_adaptation=True) reference_vs_colorimetry_data = vs_colorimetry_data( sd_reference, sd_reference, vs_sds, cmfs) if method == 'nist cqs 9.0': CCT_f = 1 scaling_f = 3.2 else: XYZ_r = sd_to_XYZ(sd_reference, cmfs) XYZ_r /= XYZ_r[1] CCT_f = CCT_factor(reference_vs_colorimetry_data, XYZ_r) scaling_f = 3.104 Q_as = colour_quality_scales(test_vs_colorimetry_data, reference_vs_colorimetry_data, scaling_f, CCT_f) D_E_RMS = delta_E_RMS(Q_as, 'D_E_ab') D_Ep_RMS = delta_E_RMS(Q_as, 'D_Ep_ab') Q_a = scale_conversion(D_Ep_RMS, CCT_f, scaling_f) if method == 'nist cqs 9.0': scaling_f = 2.93 * 1.0343 else: scaling_f = 2.928 Q_f = scale_conversion(D_E_RMS, CCT_f, scaling_f) G_t = gamut_area( [vs_CQS_data.Lab for vs_CQS_data in test_vs_colorimetry_data]) G_r = gamut_area( [vs_CQS_data.Lab for vs_CQS_data in reference_vs_colorimetry_data]) Q_g = G_t / D65_GAMUT_AREA * 100 if method == 'nist cqs 9.0': Q_d = Q_p = None else: p_delta_C = np.average([ sample_data.D_C_ab if sample_data.D_C_ab > 0 else 0 for sample_data in Q_as.values() ]) Q_p = 100 - 3.6 * (D_Ep_RMS - p_delta_C) Q_d = G_t / G_r * CCT_f * 100 if additional_data: return CQS_Specification( sd_test.name, Q_a, Q_f, Q_p, Q_g, Q_d, Q_as, (test_vs_colorimetry_data, reference_vs_colorimetry_data)) else: return Q_a
def colour_quality_scale( sd_test: SpectralDistribution, additional_data: Boolean = False, method: Union[Literal["NIST CQS 7.4", "NIST CQS 9.0"], str] = "NIST CQS 9.0", ) -> Union[Floating, ColourRendering_Specification_CQS]: """ Return the *Colour Quality Scale* (CQS) of given spectral distribution using given method. Parameters ---------- sd_test Test spectral distribution. additional_data Whether to output additional data. method Computation method. Returns ------- :class:`numpy.floating` or \ :class:`colour.quality.ColourRendering_Specification_CQS` *Colour Quality Scale* (CQS). References ---------- :cite:`Davis2010a`, :cite:`Ohno2008a`, :cite:`Ohno2013` Examples -------- >>> from colour import SDS_ILLUMINANTS >>> sd = SDS_ILLUMINANTS['FL2'] >>> colour_quality_scale(sd) # doctest: +ELLIPSIS 64.1117031... """ method = validate_method(method, COLOUR_QUALITY_SCALE_METHODS) # 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) vs_sds = {sd.name: reshape_sd(sd, shape) for sd in SDS_VS[method].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_Ohno2013(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_vs_colorimetry_data = vs_colorimetry_data(sd_test, sd_reference, vs_sds, cmfs, chromatic_adaptation=True) reference_vs_colorimetry_data = vs_colorimetry_data( sd_reference, sd_reference, vs_sds, cmfs) CCT_f: Floating if method == "nist cqs 9.0": CCT_f = 1 scaling_f = 3.2 else: XYZ_r = sd_to_XYZ(sd_reference, cmfs) XYZ_r /= XYZ_r[1] CCT_f = CCT_factor(reference_vs_colorimetry_data, XYZ_r) scaling_f = 3.104 Q_as = colour_quality_scales( test_vs_colorimetry_data, reference_vs_colorimetry_data, scaling_f, CCT_f, ) D_E_RMS = delta_E_RMS(Q_as, "D_E_ab") D_Ep_RMS = delta_E_RMS(Q_as, "D_Ep_ab") Q_a = scale_conversion(D_Ep_RMS, CCT_f, scaling_f) if method == "nist cqs 9.0": scaling_f = 2.93 * 1.0343 else: scaling_f = 2.928 Q_f = scale_conversion(D_E_RMS, CCT_f, scaling_f) G_t = gamut_area( [vs_CQS_data.Lab for vs_CQS_data in test_vs_colorimetry_data]) G_r = gamut_area( [vs_CQS_data.Lab for vs_CQS_data in reference_vs_colorimetry_data]) Q_g = G_t / GAMUT_AREA_D65 * 100 if method == "nist cqs 9.0": Q_p = Q_d = None else: p_delta_C = np.average([ sample_data.D_C_ab if sample_data.D_C_ab > 0 else 0 for sample_data in Q_as.values() ]) Q_p = as_float_scalar(100 - 3.6 * (D_Ep_RMS - p_delta_C)) Q_d = as_float_scalar(G_t / G_r * CCT_f * 100) if additional_data: return ColourRendering_Specification_CQS( sd_test.name, Q_a, Q_f, Q_p, Q_g, Q_d, Q_as, (test_vs_colorimetry_data, reference_vs_colorimetry_data), ) else: return Q_a