Coverage for colour/colorimetry/uniformity.py: 100%
18 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-15 19:01 +1300
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-15 19:01 +1300
1"""
2Spectral Uniformity
3===================
5Define objects to compute the *spectral uniformity* (or *spectral flatness*)
6of spectral distributions.
8References
9----------
10- :cite:`David2015` : David, A., Fini, P. T., Houser, K. W., Ohno, Y.,
11 Royer, M. P., Smet, K. A. G., Wei, M., & Whitehead, L. (2015). Development
12 of the IES method for evaluating the color rendition of light sources.
13 Optics Express, 23(12), 15888. doi:10.1364/OE.23.015888
14"""
16from __future__ import annotations
18import typing
20if typing.TYPE_CHECKING:
21 from collections.abc import ValuesView
23import numpy as np
25from colour.colorimetry import (
26 MultiSpectralDistributions,
27 SpectralDistribution,
28 sds_and_msds_to_msds,
29)
31if typing.TYPE_CHECKING:
32 from colour.hints import NDArrayFloat, Sequence
34__author__ = "Colour Developers"
35__copyright__ = "Copyright 2013 Colour Developers"
36__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
37__maintainer__ = "Colour Developers"
38__email__ = "colour-developers@colour-science.org"
39__status__ = "Production"
41__all__ = [
42 "spectral_uniformity",
43]
46def spectral_uniformity(
47 sds: (
48 Sequence[SpectralDistribution | MultiSpectralDistributions]
49 | SpectralDistribution
50 | MultiSpectralDistributions
51 | ValuesView
52 ),
53 use_second_order_derivatives: bool = False,
54) -> NDArrayFloat:
55 """
56 Compute the *spectral uniformity* (or *spectral flatness*) of the specified
57 spectral distributions.
59 Spectral uniformity :math:`(r')^2` is computed as follows:
61 :math:`\\text{mean}((r'_1)^2, (r'_2)^2, ..., (r'_n)^2)`
63 where :math:`(r'_i)^2` is the first-order derivative, squared, of the
64 reflectance :math:`r_i` of a test sample.
66 Parameters
67 ----------
68 sds
69 Spectral distributions or multi-spectral distributions to compute
70 the spectral uniformity of. `sds` can be a single
71 :class:`colour.MultiSpectralDistributions` class instance, a list
72 of :class:`colour.MultiSpectralDistributions` class instances or
73 a list of :class:`colour.SpectralDistribution` class instances.
74 use_second_order_derivatives
75 Whether to use the second-order derivatives in the computations.
77 Returns
78 -------
79 :class:`numpy.ndarray`
80 Spectral uniformity.
82 Warnings
83 --------
84 The spectral distributions must have the same spectral shape.
86 References
87 ----------
88 :cite:`David2015`
90 Examples
91 --------
92 >>> from colour.quality.datasets import SDS_TCS
93 >>> spectral_uniformity(SDS_TCS["CIE 1995"].values()) # doctest: +ELLIPSIS
94 array([ 9.5514285...e-06, 1.1482142...e-05, 1.8784285...e-05,
95 2.8711428...e-05, 3.1971428...e-05, 3.2342857...e-05,
96 3.3850000...e-05, 3.9925714...e-05, 4.1333571...e-05,
97 2.4002142...e-05, 5.7621428...e-06, 1.4757142...e-06,
98 9.7928571...e-07, 2.0057142...e-06, 3.7157142...e-06,
99 5.7678571...e-06, 7.5557142...e-06, 7.4635714...e-06,
100 5.7492857...e-06, 3.8692857...e-06, 3.5407142...e-06,
101 4.4742857...e-06, 5.6435714...e-06, 7.6371428...e-06,
102 1.0171428...e-05, 1.2254285...e-05, 1.4810000...e-05,
103 1.6517142...e-05, 1.5430714...e-05, 1.4536428...e-05,
104 1.4037857...e-05, 1.1587857...e-05, 1.0743571...e-05,
105 1.0979285...e-05, 1.0398571...e-05, 8.2971428...e-06,
106 6.3057142...e-06, 5.0942857...e-06, 4.8500000...e-06,
107 5.5371428...e-06, 6.4128571...e-06, 7.2592857...e-06,
108 7.7750000...e-06, 7.1607142...e-06, 6.6635714...e-06,
109 6.7328571...e-06, 7.5307142...e-06, 1.0733571...e-05,
110 1.6234285...e-05, 2.2570714...e-05, 2.7056428...e-05,
111 2.7781428...e-05, 2.5025714...e-05, 1.7966428...e-05,
112 1.0505000...e-05, 5.9657142...e-06, 3.6421428...e-06,
113 2.1664285...e-06, 1.2935714...e-06, 8.3642857...e-07,
114 7.2500000...e-07, 6.3928571...e-07, 6.6285714...e-07,
115 8.5571428...e-07, 1.4507142...e-06, 2.2542857...e-06,
116 3.4142857...e-06, 4.9864285...e-06, 6.4907142...e-06,
117 7.8928571...e-06, 9.1664285...e-06, 9.9521428...e-06,
118 9.7664285...e-06, 9.3150000...e-06, 8.9092857...e-06,
119 8.1578571...e-06, 6.8935714...e-06, 5.5721428...e-06,
120 4.4592857...e-06, 3.4778571...e-06, 2.7650000...e-06,
121 2.3114285...e-06, 1.7092857...e-06, 1.1771428...e-06,
122 9.8428571...e-07, 8.8285714...e-07, 7.4142857...e-07,
123 7.0142857...e-07, 7.0857142...e-07, 6.6642857...e-07,
124 7.5928571...e-07, 8.7000000...e-07, 8.2714285...e-07,
125 7.1714285...e-07, 6.6000000...e-07])
126 """
128 msds = sds_and_msds_to_msds(sds)
130 interval = msds.shape.interval
132 r_i = np.gradient(np.transpose(msds.values), axis=1) / interval
134 if use_second_order_derivatives:
135 r_i = np.gradient(r_i, axis=1) / interval
137 return np.mean(r_i**2, axis=0)