def planckian_table(uv, cmfs, start, end, count): """ Returns a planckian table from given *CIE UCS* colourspace *uv* chromaticity coordinates, colour matching functions and temperature range using Ohno (2013) method. Parameters ---------- uv : array_like *uv* chromaticity coordinates. cmfs : XYZ_ColourMatchingFunctions Standard observer colour matching functions. start : numeric Temperature range start in kelvins. end : numeric Temperature range end in kelvins. count : int Temperatures count in the planckian table. Returns ------- list Planckian table. Examples -------- >>> from colour import STANDARD_OBSERVERS_CMFS >>> from pprint import pprint >>> cmfs = 'CIE 1931 2 Degree Standard Observer' >>> cmfs = STANDARD_OBSERVERS_CMFS.get(cmfs) >>> uv = np.array([0.1978, 0.3122]) >>> pprint(planckian_table(uv, cmfs, 1000, 1010, 10)) # noqa # doctest: +ELLIPSIS [PlanckianTable_Tuvdi(Ti=1000.0, ui=0.4480108..., vi=0.3546249..., di=0.2537821...), PlanckianTable_Tuvdi(Ti=1001.1111111..., ui=0.4477508..., vi=0.3546475..., di=0.2535294...), PlanckianTable_Tuvdi(Ti=1002.2222222..., ui=0.4474910..., vi=0.3546700..., di=0.2532771...), PlanckianTable_Tuvdi(Ti=1003.3333333..., ui=0.4472316..., vi=0.3546924..., di=0.2530251...), PlanckianTable_Tuvdi(Ti=1004.4444444..., ui=0.4469724..., vi=0.3547148..., di=0.2527734...), PlanckianTable_Tuvdi(Ti=1005.5555555..., ui=0.4467136..., vi=0.3547372..., di=0.2525220...), PlanckianTable_Tuvdi(Ti=1006.6666666..., ui=0.4464550..., vi=0.3547595..., di=0.2522710...), PlanckianTable_Tuvdi(Ti=1007.7777777..., ui=0.4461968..., vi=0.3547817..., di=0.2520202...), PlanckianTable_Tuvdi(Ti=1008.8888888..., ui=0.4459389..., vi=0.3548040..., di=0.2517697...), PlanckianTable_Tuvdi(Ti=1010.0, ui=0.4456812..., vi=0.3548261..., di=0.2515196...)] """ ux, vx = uv shape = cmfs.shape table = [] for Ti in np.linspace(start, end, count): spd = blackbody_spd(Ti, shape) XYZ = spectral_to_XYZ(spd, cmfs) XYZ *= 1 / np.max(XYZ) UVW = XYZ_to_UCS(XYZ) ui, vi = UCS_to_uv(UVW) di = np.sqrt((ux - ui) ** 2 + (vx - vi) ** 2) table.append(PLANCKIAN_TABLE_TUVD(Ti, ui, vi, di)) return table
def planckian_table(uv, cmfs, start, end, count): """ Returns a planckian table from given *CIE UCS* colourspace *uv* chromaticity coordinates, colour matching functions and temperature range using *Yoshi Ohno (2013)* method. Parameters ---------- uv : array_like *uv* chromaticity coordinates. cmfs : XYZ_ColourMatchingFunctions Standard observer colour matching functions. start : numeric Temperature range start in kelvins. end : numeric Temperature range end in kelvins. count : int Temperatures count in the planckian table. Returns ------- list Planckian table. Examples -------- >>> from colour import STANDARD_OBSERVERS_CMFS >>> from pprint import pprint >>> cmfs = 'CIE 1931 2 Degree Standard Observer' >>> cmfs = STANDARD_OBSERVERS_CMFS.get(cmfs) >>> pprint(planckian_table((0.1978, 0.3122), cmfs, 1000, 1010, 10)) # noqa # doctest: +ELLIPSIS [PlanckianTable_Tuvdi(Ti=1000.0, ui=0.4480108..., vi=0.3546249..., di=0.2537821...), PlanckianTable_Tuvdi(Ti=1001.1111111..., ui=0.4477508..., vi=0.3546475..., di=0.2535294...), PlanckianTable_Tuvdi(Ti=1002.2222222..., ui=0.4474910..., vi=0.3546700..., di=0.2532771...), PlanckianTable_Tuvdi(Ti=1003.3333333..., ui=0.4472316..., vi=0.3546924..., di=0.2530251...), PlanckianTable_Tuvdi(Ti=1004.4444444..., ui=0.4469724..., vi=0.3547148..., di=0.2527734...), PlanckianTable_Tuvdi(Ti=1005.5555555..., ui=0.4467136..., vi=0.3547372..., di=0.2525220...), PlanckianTable_Tuvdi(Ti=1006.6666666..., ui=0.4464550..., vi=0.3547595..., di=0.2522710...), PlanckianTable_Tuvdi(Ti=1007.7777777..., ui=0.4461968..., vi=0.3547817..., di=0.2520202...), PlanckianTable_Tuvdi(Ti=1008.8888888..., ui=0.4459389..., vi=0.3548040..., di=0.2517697...), PlanckianTable_Tuvdi(Ti=1010.0, ui=0.4456812..., vi=0.3548261..., di=0.2515196...)] """ ux, vx = uv shape = cmfs.shape table = [] for Ti in np.linspace(start, end, count): spd = blackbody_spd(Ti, shape) XYZ = spectral_to_XYZ(spd, cmfs) XYZ *= 1 / np.max(XYZ) UVW = XYZ_to_UCS(XYZ) ui, vi = UCS_to_uv(UVW) di = math.sqrt((ux - ui)**2 + (vx - vi)**2) table.append(PLANCKIAN_TABLE_TUVD(Ti, ui, vi, di)) return table
def colour_quality_scale(spd_test, T, additional_data=False): cmfs = STANDARD_OBSERVERS_CMFS.get('CIE 1931 2 Degree Standard Observer') shape = cmfs.shape CCT, _D_uv = T 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 blackbody_colours_plot(shape=SpectralShape(150, 12500, 50), cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots blackbody colours. Parameters ---------- shape : SpectralShape, optional Spectral shape to use as plot boundaries. cmfs : unicode, optional Standard observer colour matching functions. \*\*kwargs : \*\* Keywords arguments. Returns ------- bool Definition success. Examples -------- >>> blackbody_colours_plot() # doctest: +SKIP True """ cmfs, name = get_cmfs(cmfs), cmfs colours = [] temperatures = [] for temperature in shape: spd = blackbody_spd(temperature, cmfs.shape) XYZ = spectral_to_XYZ(spd, cmfs) RGB = normalise(XYZ_to_sRGB(XYZ / 100)) colours.append(RGB) temperatures.append(temperature) settings = { 'title': 'Blackbody Colours', 'x_label': 'Temperature K', 'y_label': '', 'x_tighten': True, 'x_ticker': True, 'y_ticker': False } settings.update(kwargs) return colour_parameters_plot([ colour_parameter(x=x[0], RGB=x[1]) for x in tuple(zip(temperatures, colours)) ], **settings)
def blackbody_colours_plot(shape=SpectralShape(150, 12500, 50), cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots blackbody colours. Parameters ---------- shape : SpectralShape, optional Spectral shape to use as plot boundaries. cmfs : unicode, optional Standard observer colour matching functions. \*\*kwargs : \*\* Keywords arguments. Returns ------- bool Definition success. Examples -------- >>> blackbody_colours_plot() # doctest: +SKIP True """ cmfs = get_cmfs(cmfs) colours = [] temperatures = [] for temperature in shape: spd = blackbody_spd(temperature, cmfs.shape) XYZ = spectral_to_XYZ(spd, cmfs) RGB = normalise(XYZ_to_sRGB(XYZ / 100)) colours.append(RGB) temperatures.append(temperature) settings = { 'title': 'Blackbody Colours', 'x_label': 'Temperature K', 'y_label': '', 'x_tighten': True, 'x_ticker': True, 'y_ticker': False} settings.update(kwargs) return colour_parameters_plot([colour_parameter(x=x[0], RGB=x[1]) for x in tuple(zip(temperatures, colours))], **settings)
def planckian_table(uv, cmfs, start, end, count): """ Returns a planckian table from given *CIE UCS* colourspace *uv* chromaticity coordinates, colour matching functions and temperature range using *Ohno (2013)* method. Parameters ---------- uv : array_like *uv* chromaticity coordinates. cmfs : XYZ_ColourMatchingFunctions Standard observer colour matching functions. start : numeric Temperature range start in kelvins. end : numeric Temperature range end in kelvins. count : int Temperatures count in the planckian table. Returns ------- list Planckian table. Examples -------- >>> from colour import STANDARD_OBSERVERS_CMFS >>> from pprint import pprint >>> cmfs = STANDARD_OBSERVERS_CMFS['CIE 1931 2 Degree Standard Observer'] >>> uv = np.array([0.1978, 0.3122]) >>> pprint(planckian_table(uv, cmfs, 1000, 1010, 10)) ... # doctest: +ELLIPSIS [PlanckianTable_Tuvdi(Ti=1000.0, \ ui=0.4479628..., vi=0.3546296..., di=0.2537355...), PlanckianTable_Tuvdi(Ti=1001.1111111..., \ ui=0.4477030..., vi=0.3546521..., di=0.2534831...), PlanckianTable_Tuvdi(Ti=1002.2222222..., \ ui=0.4474434..., vi=0.3546746..., di=0.2532310...), PlanckianTable_Tuvdi(Ti=1003.3333333..., \ ui=0.4471842..., vi=0.3546970..., di=0.2529792...), PlanckianTable_Tuvdi(Ti=1004.4444444..., \ ui=0.4469252..., vi=0.3547194..., di=0.2527277...), PlanckianTable_Tuvdi(Ti=1005.5555555..., \ ui=0.4466666..., vi=0.3547417..., di=0.2524765...), PlanckianTable_Tuvdi(Ti=1006.6666666..., \ ui=0.4464083..., vi=0.3547640..., di=0.2522256...), PlanckianTable_Tuvdi(Ti=1007.7777777..., \ ui=0.4461502..., vi=0.3547862..., di=0.2519751...), PlanckianTable_Tuvdi(Ti=1008.8888888..., \ ui=0.4458925..., vi=0.3548084..., di=0.2517248...), PlanckianTable_Tuvdi(Ti=1010.0, \ ui=0.4456351..., vi=0.3548306..., di=0.2514749...)] """ ux, vx = uv cmfs = cmfs.copy().trim(ASTME30815_PRACTISE_SHAPE) shape = cmfs.shape table = [] for Ti in np.linspace(start, end, count): spd = blackbody_spd(Ti, shape) XYZ = spectral_to_XYZ(spd, cmfs) XYZ /= np.max(XYZ) UVW = XYZ_to_UCS(XYZ) ui, vi = UCS_to_uv(UVW) di = np.hypot(ux - ui, vx - vi) table.append(PLANCKIAN_TABLE_TUVD(Ti, ui, vi, di)) return table
def blackbody_spectral_radiance_plot( temperature=3500, cmfs='CIE 1931 2 Degree Standard Observer', blackbody='VY Canis Major', **kwargs): """ Plots given blackbody spectral radiance. Parameters ---------- temperature : numeric, optional Blackbody temperature. cmfs : unicode, optional Standard observer colour matching functions. blackbody : unicode, optional Blackbody name. \**kwargs : dict, optional Keywords arguments. Returns ------- Figure Current figure or None. Examples -------- >>> blackbody_spectral_radiance_plot() # doctest: +SKIP """ canvas(**kwargs) cmfs = get_cmfs(cmfs) matplotlib.pyplot.subplots_adjust(hspace=0.4) spd = blackbody_spd(temperature, cmfs.shape) matplotlib.pyplot.figure(1) matplotlib.pyplot.subplot(211) settings = { 'title': '{0} - Spectral Radiance'.format(blackbody), 'y_label': 'W / (sr m$^2$) / m', 'standalone': False } settings.update(kwargs) single_spd_plot(spd, cmfs.name, **settings) XYZ = spectral_to_XYZ(spd, cmfs) RGB = normalise_maximum(XYZ_to_sRGB(XYZ / 100)) matplotlib.pyplot.subplot(212) settings = { 'title': '{0} - Colour'.format(blackbody), 'x_label': '{0}K'.format(temperature), 'y_label': '', 'aspect': None, 'standalone': False } single_colour_plot(ColourParameter(name='', RGB=RGB), **settings) settings = {'standalone': True} settings.update(kwargs) boundaries(**settings) decorate(**settings) return display(**settings)
def blackbody_spectral_radiance_plot( temperature=3500, cmfs='CIE 1931 2 Degree Standard Observer', blackbody='VY Canis Major', **kwargs): """ Plots given blackbody spectral radiance. Parameters ---------- temperature : numeric, optional Blackbody temperature. cmfs : unicode, optional Standard observer colour matching functions. blackbody : unicode, optional Blackbody name. \**kwargs : dict, optional Keywords arguments. Returns ------- bool Definition success. Examples -------- >>> blackbody_spectral_radiance_plot() # doctest: +SKIP True """ canvas(**kwargs) cmfs = get_cmfs(cmfs) matplotlib.pyplot.subplots_adjust(hspace=0.4) spd = blackbody_spd(temperature, cmfs.shape) matplotlib.pyplot.figure(1) matplotlib.pyplot.subplot(211) settings = { 'title': '{0} - Spectral Radiance'.format(blackbody), 'y_label': 'W / (sr m$^2$) / m', 'standalone': False} settings.update(kwargs) single_spd_plot(spd, cmfs.name, **settings) XYZ = spectral_to_XYZ(spd, cmfs) RGB = normalise(XYZ_to_sRGB(XYZ / 100)) matplotlib.pyplot.subplot(212) settings = {'title': '{0} - Colour'.format(blackbody), 'x_label': '{0}K'.format(temperature), 'y_label': '', 'aspect': None, 'standalone': False} single_colour_plot(ColourParameter(name='', RGB=RGB), **settings) settings = { 'standalone': True} settings.update(kwargs) boundaries(**settings) decorate(**settings) return display(**settings)
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_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 colour_rendering_index(test_spd, additional_data=False): """ Returns the *colour rendering index* of given spectral power distribution. Parameters ---------- test_spd : SpectralPowerDistribution Test spectral power distribution. additional_data : bool, optional Output additional data. Returns ------- numeric or (numeric, dict) Colour rendering index, Tsc data. 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 test_spd = test_spd.clone().align(shape) tcs_spds = {} for index, tcs_spd in sorted(TCS_SPDS.items()): tcs_spds[index] = tcs_spd.clone().align(shape) XYZ = spectral_to_XYZ(test_spd, cmfs) uv = UCS_to_uv(XYZ_to_UCS(XYZ)) CCT, Duv = uv_to_CCT_robertson1968(uv) if CCT < 5000: reference_spd = blackbody_spd(CCT, shape) else: xy = CCT_to_xy_illuminant_D(CCT) reference_spd = D_illuminant_relative_spd(xy) reference_spd.align(shape) test_tcs_colorimetry_data = _tcs_colorimetry_data( test_spd, reference_spd, tcs_spds, cmfs, chromatic_adaptation=True) reference_tcs_colorimetry_data = _tcs_colorimetry_data( reference_spd, reference_spd, tcs_spds, cmfs) colour_rendering_indexes = _colour_rendering_indexes( test_tcs_colorimetry_data, reference_tcs_colorimetry_data) colour_rendering_index = np.average([ v for k, v in colour_rendering_indexes.items() if k in (1, 2, 3, 4, 5, 6, 7, 8) ]) if additional_data: return (colour_rendering_index, colour_rendering_indexes, [test_tcs_colorimetry_data, reference_tcs_colorimetry_data]) else: return colour_rendering_index
def planckian_table(uv, cmfs, start, end, count): """ Returns a planckian table from given *CIE UCS* colourspace *uv* chromaticity coordinates, colour matching functions and temperature range using Ohno (2013) method. Parameters ---------- uv : array_like *uv* chromaticity coordinates. cmfs : XYZ_ColourMatchingFunctions Standard observer colour matching functions. start : numeric Temperature range start in kelvins. end : numeric Temperature range end in kelvins. count : int Temperatures count in the planckian table. Returns ------- list Planckian table. Examples -------- >>> from colour import STANDARD_OBSERVERS_CMFS >>> from pprint import pprint >>> cmfs = 'CIE 1931 2 Degree Standard Observer' >>> cmfs = STANDARD_OBSERVERS_CMFS.get(cmfs) >>> uv = np.array([0.1978, 0.3122]) >>> pprint(planckian_table( # doctest: +ELLIPSIS ... uv, cmfs, 1000, 1010, 10)) [PlanckianTable_Tuvdi(Ti=1000.0, \ ui=0.4479628..., vi=0.3546296..., di=0.2537355...), PlanckianTable_Tuvdi(Ti=1001.1111111..., \ ui=0.4477030..., vi=0.3546521..., di=0.2534831...), PlanckianTable_Tuvdi(Ti=1002.2222222..., \ ui=0.4474434..., vi=0.3546746..., di=0.2532310...), PlanckianTable_Tuvdi(Ti=1003.3333333..., \ ui=0.4471842..., vi=0.3546970..., di=0.2529792...), PlanckianTable_Tuvdi(Ti=1004.4444444..., \ ui=0.4469252..., vi=0.3547194..., di=0.2527277...), PlanckianTable_Tuvdi(Ti=1005.5555555..., \ ui=0.4466666..., vi=0.3547417..., di=0.2524765...), PlanckianTable_Tuvdi(Ti=1006.6666666..., \ ui=0.4464083..., vi=0.3547640..., di=0.2522256...), PlanckianTable_Tuvdi(Ti=1007.7777777..., \ ui=0.4461502..., vi=0.3547862..., di=0.2519751...), PlanckianTable_Tuvdi(Ti=1008.8888888..., \ ui=0.4458925..., vi=0.3548084..., di=0.2517248...), PlanckianTable_Tuvdi(Ti=1010.0, \ ui=0.4456351..., vi=0.3548306..., di=0.2514749...)] """ ux, vx = uv shape = cmfs.shape table = [] for Ti in np.linspace(start, end, count): spd = blackbody_spd(Ti, shape) XYZ = spectral_to_XYZ(spd, cmfs) XYZ *= 1 / np.max(XYZ) UVW = XYZ_to_UCS(XYZ) ui, vi = UCS_to_uv(UVW) di = np.sqrt((ux - ui) ** 2 + (vx - vi) ** 2) table.append(PLANCKIAN_TABLE_TUVD(Ti, ui, vi, di)) return table
def colour_rendering_index(spd_test,T, 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.1495478... """ cmfs = STANDARD_OBSERVERS_CMFS.get('CIE 1931 2 Degree Standard Observer') shape = cmfs.shape CCT, _D_uv = T[0],T[1] 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 blackbody_colours_plot(shape=SpectralShape(150, 12500, 50), cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots blackbody colours. Parameters ---------- shape : SpectralShape, optional Spectral shape to use as plot boundaries. cmfs : unicode, optional Standard observer colour matching functions. Other Parameters ---------------- \**kwargs : dict, optional {:func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definition. Returns ------- Figure Current figure or None. Examples -------- >>> blackbody_colours_plot() # doctest: +SKIP """ axes = canvas(**kwargs).gca() cmfs = get_cmfs(cmfs) colours = [] temperatures = [] with suppress_warnings(): for temperature in shape: spd = blackbody_spd(temperature, cmfs.shape) XYZ = spectral_to_XYZ(spd, cmfs) RGB = normalise_maximum(XYZ_to_sRGB(XYZ / 100)) colours.append(RGB) temperatures.append(temperature) x_min, x_max = min(temperatures), max(temperatures) y_min, y_max = 0, 1 axes.bar(x=temperatures, height=1, width=shape.interval, color=colours, align='edge') settings = { 'title': 'Blackbody Colours', 'x_label': 'Temperature K', 'y_label': None, 'limits': (x_min, x_max, y_min, y_max), 'x_tighten': True, 'y_tighten': True, 'y_ticker': False } settings.update(kwargs) return render(**settings)
def CCT_to_uv_Ohno2013( CCT, D_uv=0, cmfs=STANDARD_OBSERVERS_CMFS['CIE 1931 2 Degree Standard Observer']): """ Returns the *CIE UCS* colourspace *uv* chromaticity coordinates from given correlated colour temperature :math:`T_{cp}`, :math:`\Delta_{uv}` and colour matching functions using *Ohno (2013)* method. Parameters ---------- CCT : numeric Correlated colour temperature :math:`T_{cp}`. D_uv : numeric, optional :math:`\Delta_{uv}`. cmfs : XYZ_ColourMatchingFunctions, optional Standard observer colour matching functions. Returns ------- ndarray *CIE UCS* colourspace *uv* chromaticity coordinates. References ---------- - :cite:`Ohno2014a` Examples -------- >>> from colour import STANDARD_OBSERVERS_CMFS >>> cmfs = STANDARD_OBSERVERS_CMFS['CIE 1931 2 Degree Standard Observer'] >>> CCT = 6507.4342201047066 >>> D_uv = 0.003223690901513 >>> CCT_to_uv_Ohno2013(CCT, D_uv, cmfs) # doctest: +ELLIPSIS array([ 0.1977999..., 0.3122004...]) """ cmfs = cmfs.copy().trim(ASTME30815_PRACTISE_SHAPE) shape = cmfs.shape delta = 0.01 spd = blackbody_spd(CCT, shape) XYZ = spectral_to_XYZ(spd, cmfs) XYZ *= 1 / np.max(XYZ) UVW = XYZ_to_UCS(XYZ) u0, v0 = UCS_to_uv(UVW) if D_uv == 0: return np.array([u0, v0]) else: spd = blackbody_spd(CCT + delta, shape) XYZ = spectral_to_XYZ(spd, cmfs) XYZ *= 1 / np.max(XYZ) UVW = XYZ_to_UCS(XYZ) u1, v1 = UCS_to_uv(UVW) du = u0 - u1 dv = v0 - v1 u = u0 - D_uv * (dv / np.hypot(du, dv)) v = v0 + D_uv * (du / np.hypot(du, dv)) return np.array([u, v])
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 CCT_to_uv_Ohno2013( CCT, D_uv=0, cmfs=STANDARD_OBSERVERS_CMFS.get('CIE 1931 2 Degree Standard Observer')): """ Returns the *CIE UCS* colourspace *uv* chromaticity coordinates from given correlated colour temperature :math:`T_{cp}`, :math:`\Delta_{uv}` and colour matching functions using Ohno (2013) method. Parameters ---------- CCT : numeric Correlated colour temperature :math:`T_{cp}`. D_uv : numeric, optional :math:`\Delta_{uv}`. cmfs : XYZ_ColourMatchingFunctions, optional Standard observer colour matching functions. Returns ------- ndarray *CIE UCS* colourspace *uv* chromaticity coordinates. References ---------- .. [4] Ohno, Y. (2014). Practical Use and Calculation of CCT and Duv. LEUKOS, 10(1), 47–55. doi:10.1080/15502724.2014.839020 Examples -------- >>> from colour import STANDARD_OBSERVERS_CMFS >>> cmfs = 'CIE 1931 2 Degree Standard Observer' >>> cmfs = STANDARD_OBSERVERS_CMFS.get(cmfs) >>> CCT = 6507.4342201047066 >>> D_uv = 0.003223690901512735 >>> CCT_to_uv_Ohno2013(CCT, D_uv, cmfs) # doctest: +ELLIPSIS array([ 0.1978003..., 0.3122005...]) """ shape = cmfs.shape delta = 0.01 spd = blackbody_spd(CCT, shape) XYZ = spectral_to_XYZ(spd, cmfs) XYZ *= 1 / np.max(XYZ) UVW = XYZ_to_UCS(XYZ) u0, v0 = UCS_to_uv(UVW) if D_uv == 0: return np.array([u0, v0]) else: spd = blackbody_spd(CCT + delta, shape) XYZ = spectral_to_XYZ(spd, cmfs) XYZ *= 1 / np.max(XYZ) UVW = XYZ_to_UCS(XYZ) u1, v1 = UCS_to_uv(UVW) du = u0 - u1 dv = v0 - v1 u = u0 - D_uv * (dv / np.sqrt(du**2 + dv**2)) v = v0 + D_uv * (du / np.sqrt(du**2 + dv**2)) return np.array([u, v])
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(test_spd, additional_data=False): """ Returns the *colour rendering index* of given spectral power distribution. Parameters ---------- test_spd : SpectralPowerDistribution Test spectral power distribution. additional_data : bool, optional Output additional data. Returns ------- numeric or (numeric, dict) Colour rendering index, Tsc data. 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 test_spd = test_spd.clone().align(shape) tcs_spds = {} for index, tcs_spd in sorted(TCS_SPDS.items()): tcs_spds[index] = tcs_spd.clone().align(shape) XYZ = spectral_to_XYZ(test_spd, cmfs) uv = UCS_to_uv(XYZ_to_UCS(XYZ)) CCT, Duv = uv_to_CCT_robertson1968(uv) if CCT < 5000: reference_spd = blackbody_spd(CCT, shape) else: xy = CCT_to_xy_illuminant_D(CCT) reference_spd = D_illuminant_relative_spd(xy) reference_spd.align(shape) test_tcs_colorimetry_data = _tcs_colorimetry_data( test_spd, reference_spd, tcs_spds, cmfs, chromatic_adaptation=True) reference_tcs_colorimetry_data = _tcs_colorimetry_data( reference_spd, reference_spd, tcs_spds, cmfs) colour_rendering_indexes = _colour_rendering_indexes( test_tcs_colorimetry_data, reference_tcs_colorimetry_data) colour_rendering_index = np.average( [v for k, v in colour_rendering_indexes.items() if k in (1, 2, 3, 4, 5, 6, 7, 8)]) if additional_data: return (colour_rendering_index, colour_rendering_indexes, [test_tcs_colorimetry_data, reference_tcs_colorimetry_data]) else: return colour_rendering_index
def CCT_to_uv_Ohno2013(CCT, D_uv=0, cmfs=STANDARD_OBSERVERS_CMFS.get( 'CIE 1931 2 Degree Standard Observer')): """ Returns the *CIE UCS* colourspace *uv* chromaticity coordinates from given correlated colour temperature :math:`T_{cp}`, :math:`\Delta_{uv}` and colour matching functions using Ohno (2013) method. Parameters ---------- CCT : numeric Correlated colour temperature :math:`T_{cp}`. D_uv : numeric, optional :math:`\Delta_{uv}`. cmfs : XYZ_ColourMatchingFunctions, optional Standard observer colour matching functions. Returns ------- ndarray *CIE UCS* colourspace *uv* chromaticity coordinates. References ---------- .. [4] Ohno, Y. (2014). Practical Use and Calculation of CCT and Duv. LEUKOS, 10(1), 47–55. doi:10.1080/15502724.2014.839020 Examples -------- >>> from colour import STANDARD_OBSERVERS_CMFS >>> cmfs = 'CIE 1931 2 Degree Standard Observer' >>> cmfs = STANDARD_OBSERVERS_CMFS.get(cmfs) >>> CCT = 6507.4342201047066 >>> D_uv = 0.003223690901512735 >>> CCT_to_uv_Ohno2013(CCT, D_uv, cmfs) # doctest: +ELLIPSIS array([ 0.1978003..., 0.3122005...]) """ shape = cmfs.shape delta = 0.01 spd = blackbody_spd(CCT, shape) XYZ = spectral_to_XYZ(spd, cmfs) XYZ *= 1 / np.max(XYZ) UVW = XYZ_to_UCS(XYZ) u0, v0 = UCS_to_uv(UVW) if D_uv == 0: return np.array([u0, v0]) else: spd = blackbody_spd(CCT + delta, shape) XYZ = spectral_to_XYZ(spd, cmfs) XYZ *= 1 / np.max(XYZ) UVW = XYZ_to_UCS(XYZ) u1, v1 = UCS_to_uv(UVW) du = u0 - u1 dv = v0 - v1 u = u0 - D_uv * (dv / np.sqrt(du ** 2 + dv ** 2)) v = v0 + D_uv * (du / np.sqrt(du ** 2 + dv ** 2)) return np.array([u, v])
def blackbody_colours_plot(shape=SpectralShape(150, 12500, 50), cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots blackbody colours. Parameters ---------- shape : SpectralShape, optional Spectral shape to use as plot boundaries. cmfs : unicode, optional Standard observer colour matching functions. Other Parameters ---------------- \**kwargs : dict, optional {:func:`boundaries`, :func:`canvas`, :func:`decorate`, :func:`display`}, Please refer to the documentation of the previously listed definitions. y0_plot : bool, optional {:func:`colour_parameters_plot`}, Whether to plot *y0* line. y1_plot : bool, optional {:func:`colour_parameters_plot`}, Whether to plot *y1* line. Returns ------- Figure Current figure or None. Examples -------- >>> blackbody_colours_plot() # doctest: +SKIP """ cmfs = get_cmfs(cmfs) colours = [] temperatures = [] for temperature in shape: spd = blackbody_spd(temperature, cmfs.shape) XYZ = spectral_to_XYZ(spd, cmfs) RGB = normalise_maximum(XYZ_to_sRGB(XYZ / 100)) colours.append(RGB) temperatures.append(temperature) settings = { 'title': 'Blackbody Colours', 'x_label': 'Temperature K', 'y_label': '', 'x_tighten': True, 'y_tighten': True, 'y_ticker': False } settings.update(kwargs) return colour_parameters_plot([ ColourParameter(x=x[0], RGB=x[1]) for x in tuple(zip(temperatures, colours)) ], **settings)