Beispiel #1
0
    def load(self):
        """
        Syncs, parses, converts and returns the *Jiang et al. (2013)*
        *Camera Spectral Sensitivity Database* dataset content.

        Returns
        -------
        OrderedDict
            *Jiang et al. (2013)* *Camera Spectral Sensitivity Database*
            dataset content.

        Examples
        --------
        >>> from colour_datasets.utilities import suppress_stdout
        >>> dataset = DatasetLoader_Jiang2013()
        >>> with suppress_stdout():
        ...     dataset.load()
        >>> len(dataset.content.keys())
        28
        """

        super(DatasetLoader_Jiang2013, self).sync()

        shape = SpectralShape(400, 720, 10)

        self._content = OrderedDict()
        database_path = os.path.join(self.record.repository, 'dataset',
                                     'camspec_database.txt')
        with codecs.open(database_path, encoding='utf-8') as database_file:
            lines = filter(None, (line.strip()
                                  for line in database_file.readlines()))
            camera = None
            for line in lines:
                if re.match('[a-zA-Z]+', line):
                    camera = line
                    self._content[camera] = []
                    continue

                self._content[camera].extend(
                    [float(value) for value in line.split('\t')])

        for camera, values in self._content.items():
            self._content[camera] = RGB_CameraSensitivities(np.transpose(
                as_float_array(values).reshape([3, 33])),
                                                            shape.range(),
                                                            name=camera)

        return self._content
Beispiel #2
0
    def from_file(self, path):
        """
        Loads a dataset from an .npz file.

        Parameters
        ==========
        path : unicode
            Path to file.

        Raises
        ======
        ValueError, KeyError
            Raised when loading the file succeeded but it did not contain the
            expected data.
        """

        npz = np.load(path, allow_pickle=False)
        if not isinstance(npz, np.lib.npyio.NpzFile):
            raise ValueError('the loaded file is not an .npz file')

        start, end, interval = npz['shape']
        self.shape = SpectralShape(start, end, interval)
        self.basis_functions = npz['basis_functions']
        self.means = npz['means']
        self.selector_array = npz['selector_array']

        n, three, m = self.basis_functions.shape
        if (three != 3 or self.means.shape != (n, m)
                or self.selector_array.shape[1] != 4):
            raise ValueError('array shapes are not correct, the file could be '
                             'corrupted or in a wrong format')
Beispiel #3
0
    def test_load(self):
        """
        Tests :func:`colour_datasets.loaders.labsphere2019.\
DatasetLoader_Labsphere2019.load` method.
        """

        dataset = DatasetLoader_Labsphere2019()
        self.assertEqual(sorted(dataset.load().keys()),
                         ['Labsphere SRS-99-020'])
        self.assertEqual(dataset.content['Labsphere SRS-99-020'].shape,
                         SpectralShape(250, 2500, 1))
Beispiel #4
0
    def test_load(self):
        """
        Tests :func:`colour_datasets.loaders.brendel2020.\
DatasetLoader_Brendel2020.load` method.
        """

        dataset = DatasetLoader_Brendel2020()

        self.assertEqual(len(dataset.load()), 29)

        self.assertEqual(
            dataset.content['556nm - LED 11 - Brendel (2020)'].shape,
            SpectralShape(350, 700, 2))
    def test_load(self):
        """
        Tests :func:`colour_datasets.loaders.jiang2013.\
DatasetLoader_Jiang2013.load` method.
        """

        dataset = DatasetLoader_Jiang2013()
        self.assertEqual(sorted(dataset.load().keys()), [
            'Canon 1DMarkIII', 'Canon 20D', 'Canon 300D', 'Canon 40D',
            'Canon 500D', 'Canon 50D', 'Canon 5DMarkII', 'Canon 600D',
            'Canon 60D', 'Hasselblad H2', 'Nikon D200', 'Nikon D3',
            'Nikon D300s', 'Nikon D3X', 'Nikon D40', 'Nikon D50',
            'Nikon D5100', 'Nikon D700', 'Nikon D80', 'Nikon D90',
            'Nokia N900', 'Olympus E-PL2', 'Pentax K-5', 'Pentax Q',
            'Phase One', 'Point Grey Grasshopper 50S5C',
            'Point Grey Grasshopper2 14S5C', 'SONY NEX-5N'
        ])
        self.assertEqual(dataset.content['Canon 1DMarkIII'].shape,
                         SpectralShape(400, 720, 10))
    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
Beispiel #7
0
        setattr(module, dataset_loader_attribute, dataset_loader_class())
        if load:
            getattr(module, dataset_loader_attribute).load()

    return getattr(module, dataset_loader_attribute)


# TODO: Implement support for *Natural Colors*:
# https://sandbox.zenodo.org/record/315640
# http://www.uef.fi/web/spectral/natural-colors
DATA_KUOPIO_UNIVERSITY = {
    '3269912': [
        'Munsell Colors Matt (Spectrofotometer Measured)', 'Hauta-Kasari', {
            ('munsell380_800_1_mat', 'munsell380_800_1.mat'):
                MatFileMetadata_KuopioUniversity('munsell',
                                                 SpectralShape(380, 800, 1),
                                                 True, 'S')
        }
    ],
    '3269914': [
        'Munsell Colors Matt (AOTF Measured)', 'Hauta-Kasaria', {
            ('munsell400_700_5_mat', 'munsell400_700_5.mat'):
                MatFileMetadata_KuopioUniversity('munsell',
                                                 SpectralShape(400, 700, 5),
                                                 True, 'S')
        }
    ],
    '3269916': [
        'Munsell Colors Glossy (Spectrofotometer Measured)', 'Haanpalo', {
            ('munsell400_700_10_mat', 'munsell400_700_10.mat'):
                MatFileMetadata_KuopioUniversity('munsell',
Beispiel #8
0
import os
import matplotlib.pyplot as plt
import tqdm

from colour import SpectralShape, COLOURCHECKER_SDS, sd_to_XYZ

from otsu2018 import load_Otsu2018_spectra, Otsu2018Tree

if __name__ == '__main__':
    print('Loading spectral data...')
    sds = load_Otsu2018_spectra('CommonData/spectrum_m.csv', every_nth=100)
    shape = SpectralShape(380, 730, 10)

    print('Initializing the tree...')
    tree = Otsu2018Tree(sds, shape)

    print('Clustering...')
    before = tree.total_reconstruction_error()
    tree.optimise(progress_bar=tqdm.tqdm)
    after = tree.total_reconstruction_error()

    print('Error before: %g' % before)
    print('Error after:  %g' % after)

    print('Saving the dataset...')
    if not os.path.exists('datasets'):
        os.makedirs('datasets')
    data = tree.to_dataset()
    data.to_file('datasets/otsu2018.npz')
    data.to_Python_file('datasets/otsu2018.py')
def reshape(spd, min=360, max=780, interval=1):
    spd = spd.extrapolate(SpectralShape(start=min, end=max))
    spd = spd.interpolate(SpectralShape(interval=interval))
    return spd
Beispiel #10
0
    def test_load(self):
        """
        Tests :func:`colour_datasets.loaders.asano2015.\
DatasetLoader_Asano2015.load` method.
        """

        dataset = DatasetLoader_Asano2015()
        self.assertEqual(sorted(dataset.load().keys()),
                         ['Categorical Observers', 'Colour Normal Observers'])

        self.assertEqual(
            dataset.content['Categorical Observers'][1].XYZ_2.shape,
            SpectralShape(390, 780, 5))

        np.testing.assert_almost_equal(
            dataset.content['Categorical Observers'][1].XYZ_2[390],
            np.array([
                0.003774670254076,
                0.000033807427536,
                0.017705556255144,
            ]),
            decimal=7)

        np.testing.assert_almost_equal(
            dataset.content['Categorical Observers'][10].LMS_10[780],
            np.array([
                0.000101460310461,
                9.67131698024335e-06,
                0.000000000000000,
            ]),
            decimal=7)

        self.assertAlmostEqual(dataset.content['Categorical Observers']
                               [5].parameters['Shift in S [nm]'],
                               0.233255808,
                               places=7)

        self.assertEqual(
            dataset.content['Colour Normal Observers'][1].XYZ_2.shape,
            SpectralShape(390, 780, 5))

        np.testing.assert_almost_equal(
            dataset.content['Colour Normal Observers'][1].XYZ_2[390],
            np.array([
                0.001627436785620,
                0.000021871064674,
                0.007492391403616,
            ]),
            decimal=7)

        np.testing.assert_almost_equal(
            dataset.content['Colour Normal Observers'][10].LMS_10[780],
            np.array([
                0.000092440377130,
                6.93870146211108e-06,
                0.000000000000000,
            ]),
            decimal=7)

        self.assertAlmostEqual(dataset.content['Colour Normal Observers']
                               [5].parameters['Shift in S [nm]'],
                               0.000649602695013,
                               places=7)

        self.assertEqual(
            dataset.content['Colour Normal Observers'][151].others['Location'],
            'Darmstadt')
    def parse_workbook_Asano2015(workbook, template, observers=(1, 10)):
        """
        Parses given *Asano (2015)* *Observer Function Database* workbook.

        Parameters
        ----------
        workbook : unicode
            *Asano (2015)* *Observer Function Database* workbook path.
        template : unicode
            Template used to create the *CMFS* names.
        observers : tuple, optional
            Observers range.

        Returns
        -------
        OrderedDict
            *Asano (2015)* *Observer Function Database* workbook observer data.
        """

        workbook = xlrd.open_workbook(workbook)

        # "CIE XYZ" and "LMS" CMFS.
        column_in, column_out = (index_to_column(observers[0] + 1),
                                 index_to_column(observers[1] + 1))

        shape = SpectralShape(390, 780, 5)
        wavelengths = shape.range()
        data = OrderedDict()

        for i, cmfs in enumerate([(XYZ_ColourMatchingFunctions, 'XYZ'),
                                  (LMS_ConeFundamentals, 'LMS')]):

            for j, degree in enumerate([(2, '2$^\\circ$'),
                                        (10, '10$^\\circ$')]):

                sheet = workbook.sheet_by_index(j + (i * 2))

                x = np.transpose(
                    cell_range_values(
                        sheet, '{0}3:{1}81'.format(column_in, column_out)))
                y = np.transpose(
                    cell_range_values(
                        sheet, '{0}82:{1}160'.format(column_in, column_out)))
                z = np.transpose(
                    cell_range_values(
                        sheet, '{0}161:{1}239'.format(column_in, column_out)))

                for k in range(observers[1]):
                    observer = k + 1
                    rgb = tstack([x[k], y[k], z[k]])
                    if data.get(observer) is None:
                        data[observer] = OrderedDict()

                    key = '{0}_{1}'.format(cmfs[1], degree[0])
                    data[observer][key] = cmfs[0](
                        rgb,
                        domain=wavelengths,
                        name=template.format(degree[0], observer, cmfs[1]),
                        strict_name=template.format(degree[0], observer,
                                                    cmfs[1]))

        # Parameters
        column_in, column_out = (index_to_column(observers[0] - 1),
                                 index_to_column(observers[1]))

        values = np.transpose(
            cell_range_values(workbook.sheet_by_index(4),
                              '{0}2:{1}10'.format(column_in, column_out)))
        header, values = values[0], values[1:]

        for i in range(observers[1]):
            observer = i + 1
            data[observer]['parameters'] = OrderedDict(
                zip(header, as_float_array(values[i])))

        return data
Beispiel #12
0
    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())


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 = []
Beispiel #13
0
def XYZ_to_spectral_Meng2015(
        XYZ,
        cmfs=STANDARD_OBSERVERS_CMFS['CIE 1931 2 Degree Standard Observer'],
        interval=5,
        tolerance=1e-10,
        maximum_iterations=2000):
    """
    Recovers the spectral power distribution of given *CIE XYZ* tristimulus
    values using *Meng et al. (2015)* method.

    Parameters
    ----------
    XYZ : array_like, (3,)
        *CIE XYZ* tristimulus values.
    cmfs : XYZ_ColourMatchingFunctions
        Standard observer colour matching functions.
    interval : numeric, optional
        Wavelength :math:`\lambda_{i}` range interval in nm. The smaller
        `interval` is, the longer the computations will be.
    tolerance : numeric, optional
        Tolerance for termination. The lower `tolerance` is, the smoother
        the recovered spectral power distribution will be.
    maximum_iterations : int, optional
        Maximum number of iterations to perform.

    Returns
    -------
    SpectralPowerDistribution
        Recovered spectral power distribution.

    Notes
    -----
    -   The definition used to convert spectrum to *CIE XYZ* tristimulus
        values is :func:`colour.spectral_to_XYZ_integration` definition
        because it processes any measurement interval opposed to
        :func:`colour.spectral_to_XYZ_ASTME30815` definition that handles only
        measurement interval of 1, 5, 10 or 20nm.

    Examples
    --------
    >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313])
    >>> spd = XYZ_to_spectral_Meng2015(XYZ)
    >>> print(spd)
    SpectralPowerDistribution('Meng (2015) - \
[ 0.07049534  0.1008      0.09558313]', (360.0, 830.0, 5.0))
    >>> spectral_to_XYZ_integration(spd)  # doctest: +ELLIPSIS
    array([ 0.0704952...,  0.1007999...,  0.0955824...])
    """

    XYZ = np.asarray(XYZ)
    shape = SpectralShape(cmfs.shape.start, cmfs.shape.end, interval)
    cmfs = cmfs.clone().align(shape)
    illuminant = ones_spd(shape)
    spd = ones_spd(shape)

    def function_objective(a):
        """
        Objective function.
        """

        return np.sum(np.diff(a)**2)

    def function_constraint(a):
        """
        Function defining the constraint.
        """

        spd[:] = a
        return spectral_to_XYZ_integration(
            spd, cmfs=cmfs, illuminant=illuminant) - XYZ

    wavelengths = spd.wavelengths
    bins = wavelengths.size

    constraints = {'type': 'eq', 'fun': function_constraint}

    bounds = np.tile(np.array([0, 1000]), (bins, 1))

    result = minimize(function_objective,
                      spd.values,
                      method='SLSQP',
                      constraints=constraints,
                      bounds=bounds,
                      options={
                          'ftol': tolerance,
                          'maxiter': maximum_iterations
                      })

    if not result.success:
        raise RuntimeError(
            'Optimization failed for {0} after {1} iterations: "{2}".'.format(
                XYZ, result.nit, result.message))

    return SpectralPowerDistribution('Meng (2015) - {0}'.format(XYZ),
                                     dict(zip(wavelengths, result.x)))