def XYZ_to_sd_Otsu2018( XYZ, cmfs=STANDARD_OBSERVER_CMFS['CIE 1931 2 Degree Standard Observer']. copy().align(OTSU_2018_SPECTRAL_SHAPE), illuminant=ILLUMINANT_SDS['D65'].copy().align( OTSU_2018_SPECTRAL_SHAPE), clip=True): XYZ = as_float_array(XYZ) xy = XYZ_to_xy(XYZ) cluster = select_cluster_Otsu2018(xy) basis_functions = OTSU_2018_BASIS_FUNCTIONS[cluster] mean = OTSU_2018_MEANS[cluster] M = np.empty((3, 3)) for i in range(3): sd = SpectralDistribution( basis_functions[i, :], OTSU_2018_SPECTRAL_SHAPE.range(), ) M[:, i] = sd_to_XYZ(sd, illuminant=illuminant) / 100 M_inverse = np.linalg.inv(M) sd = SpectralDistribution(mean, OTSU_2018_SPECTRAL_SHAPE.range()) XYZ_mu = sd_to_XYZ(sd, illuminant=illuminant) / 100 weights = np.dot(M_inverse, XYZ - XYZ_mu) recovered_sd = np.dot(weights, basis_functions) + mean if clip: recovered_sd = np.clip(recovered_sd, 0, 1) return SpectralDistribution(recovered_sd, OTSU_2018_SPECTRAL_SHAPE.range())
def luminance_sd(spectrum, colourspace=RGB_COLOURSPACES['sRGB']): """ Returns the luminance spectral distribution of given RGB spectrum. Parameters ---------- spectrum : RGB_Spectrum RGB spectrum to retrieve the luminance from. colourspace : RGB_Colourspace *RGB* Colourspace. Returns ------- SpectralDistribution RGB spectrum luminance spectral distribution, units are arbitrary and normalised to [0, 100] domain. """ spectrum = spectrum.copy().normalise(100) luminance = lambda x: RGB_luminance(x, colourspace.primaries, colourspace. whitepoint) return SpectralDistribution( dict(zip(spectrum.wavelengths, luminance(spectrum.values))), name='calibrated_RGB_spectrum')
def load(self): """ Syncs, parses, converts and returns the *Labsphere (2019)* *Labsphere SRS-99-020* dataset content. Returns ------- OrderedDict *Labsphere (2019)* *Labsphere SRS-99-020* dataset content. Examples -------- >>> from colour_datasets.utilities import suppress_stdout >>> dataset = DatasetLoader_Labsphere2019() >>> with suppress_stdout(): ... dataset.load() >>> len(dataset.content.keys()) 1 """ super(DatasetLoader_Labsphere2019, self).sync() sd_path = os.path.join(self.record.repository, 'dataset', 'SRS-99-020.txt') values = tsplit(np.loadtxt(sd_path, delimiter='\t', skiprows=2)) self._content = OrderedDict([ ('Labsphere SRS-99-020', SpectralDistribution(values[1], values[0], name='Labsphere SRS-99-020')), ]) return self._content
def _reconstruct_xy(self, XYZ, xy): if not self.leaf: if xy[self.partition_axis.direction] <= self.partition_axis.origin: return self.children[0]._reconstruct_xy(XYZ, xy) else: return self.children[1]._reconstruct_xy(XYZ, xy) weights = np.dot(self.M_inverse, XYZ - self.XYZ_mu) reflectance = np.dot(weights, self.basis_functions) + self.mean reflectance = np.clip(reflectance, 0, 1) return SpectralDistribution(reflectance, self.tree.wl)
def spectrum_to_XYZ( wavelength, spectrum, # cmfs=None, illuminant=None, ): """ Calculate the rgb color given a wavelength and spectrum Parameters ---------- wavelength spectrum cmfs illuminant Returns ------- """ # if cmfs is None: # cmfs = colour.STANDARD_OBSERVERS_CMFS['CIE 1931 2 Degree Standard Observer'] if illuminant is None: # illuminant = ILLUMINANTS_SDS['CIE 1931 2 Degree Standard Observer']['D65'] illuminant = sd_ones() elif type(illuminant) == type(''): illuminant = SDS_ILLUMINANTS[illuminant] # # Get illuminant # if type(illuminant) == type(''): # illuminant = colour.ILLUMINANTS_SDS[illuminant] # Build spectral distribution object sd = SpectralDistribution(pd.Series(spectrum, index=wavelength), interpolator=CubicSplineInterpolator, extrapolator=Extrapolator) # Calculate xyz color coordinates. xyz = sd_to_XYZ(sd=sd, illuminant=illuminant) return xyz
def load(self): """ Syncs, parses, converts and returns the *Brendel (2020)* *Measured Commercial LED Spectra* dataset content. Returns ------- OrderedDict *Brendel (2020)* *Measured Commercial LED Spectra* dataset content. Examples -------- >>> from colour_datasets.utilities import suppress_stdout >>> dataset = DatasetLoader_Brendel2020() >>> with suppress_stdout(): ... dataset.load() >>> len(dataset.content.keys()) 29 """ super(DatasetLoader_Brendel2020, self).sync() self._content = OrderedDict() wavelengths = SpectralShape(350, 700, 2).range() csv_path = os.path.join(self.record.repository, 'dataset', 'led_spd_350_700.csv') for i, values in enumerate( np.loadtxt(csv_path, delimiter=',', skiprows=1)): peak = as_int(wavelengths[np.argmax(values)]) name = '{0}nm - LED {1} - Brendel (2020)'.format(peak, i) self._content[name] = SpectralDistribution( values, wavelengths, name=name, interpolator=LinearInterpolator) return self._content
def read_sds_from_mat_file_KuopioUniversity(mat_file, metadata): """ Reads the spectral distributions from given *University of Kuopio* *Matlab* *.mat* file. Parameters ---------- mat_file : unicode *Matlab* *.mat* file. metadata : MatFileMetadata_KuopioUniversity Metadata required to read the spectral distributions in the *Matlab* *.mat* file. Returns ------- OrderedDict Spectral distributions from the *Matlab* *.mat* file. """ matlab_data = scipy.io.loadmat(mat_file) sds = OrderedDict() table = matlab_data[metadata.key] wavelengths = metadata.shape.range() if metadata.transpose: table = np.transpose(table) for i, data in enumerate(table): identifier = six.text_type(i + 1 if metadata.identifiers is None else matlab_data[metadata.identifiers][ i].strip()) if identifier in sds: identifier = '{0} ({1})'.format(identifier, i) sds[identifier] = SpectralDistribution( dict(zip(wavelengths, data)), name=identifier) return sds
def __init__(self, tree, reflectances): """ Parameters ========== tree : tree The parent tree. This determines what cmfs and illuminant are used in colourimetric calculations. reflectances : ndarray (n,m) Reflectances of the ``n`` colours to be stored in this class. The shape must match ``tree.shape`` with ``m`` points for each colour. """ self.reflectances = reflectances self.XYZ = np.empty((reflectances.shape[0], 3)) self.xy = np.empty((reflectances.shape[0], 2)) for i in range(len(self)): sd = SpectralDistribution(reflectances[i, :], tree.wl) XYZ = sd_to_XYZ(sd, illuminant=tree.illuminant) / 100 self.XYZ[i, :] = XYZ self.xy[i, :] = XYZ_to_xy(XYZ)
weights = np.dot(M_inverse, XYZ - XYZ_mu) recovered_sd = np.dot(weights, basis_functions) + mean if clip: recovered_sd = np.clip(recovered_sd, 0, 1) return SpectralDistribution(recovered_sd, OTSU_2018_SPECTRAL_SHAPE.range()) if __name__ == '__main__': print('Loading spectral data...') data = load_Otsu2018_spectra('CommonData/spectrum_m.csv') shape = SpectralShape(380, 730, 10) sds = [ SpectralDistribution(data[i, :], shape.range()) for i in range(data.shape[0]) ] for name, colourchecker in COLOURCHECKER_SDS.items(): print('Adding %s...' % name) sds += colourchecker.values() D65 = ILLUMINANT_SDS['D65'] xy_w = ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65'] x = [] y = [] errors = [] above_JND = 0 for i, sd in tqdm.tqdm(enumerate(sds), total=len(sds)):