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

1""" 

2Spectral Uniformity 

3=================== 

4 

5Define objects to compute the *spectral uniformity* (or *spectral flatness*) 

6of spectral distributions. 

7 

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""" 

15 

16from __future__ import annotations 

17 

18import typing 

19 

20if typing.TYPE_CHECKING: 

21 from collections.abc import ValuesView 

22 

23import numpy as np 

24 

25from colour.colorimetry import ( 

26 MultiSpectralDistributions, 

27 SpectralDistribution, 

28 sds_and_msds_to_msds, 

29) 

30 

31if typing.TYPE_CHECKING: 

32 from colour.hints import NDArrayFloat, Sequence 

33 

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" 

40 

41__all__ = [ 

42 "spectral_uniformity", 

43] 

44 

45 

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. 

58 

59 Spectral uniformity :math:`(r')^2` is computed as follows: 

60 

61 :math:`\\text{mean}((r'_1)^2, (r'_2)^2, ..., (r'_n)^2)` 

62 

63 where :math:`(r'_i)^2` is the first-order derivative, squared, of the 

64 reflectance :math:`r_i` of a test sample. 

65 

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. 

76 

77 Returns 

78 ------- 

79 :class:`numpy.ndarray` 

80 Spectral uniformity. 

81 

82 Warnings 

83 -------- 

84 The spectral distributions must have the same spectral shape. 

85 

86 References 

87 ---------- 

88 :cite:`David2015` 

89 

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 """ 

127 

128 msds = sds_and_msds_to_msds(sds) 

129 

130 interval = msds.shape.interval 

131 

132 r_i = np.gradient(np.transpose(msds.values), axis=1) / interval 

133 

134 if use_second_order_derivatives: 

135 r_i = np.gradient(r_i, axis=1) / interval 

136 

137 return np.mean(r_i**2, axis=0)