Coverage for colour/temperature/cie_d.py: 100%

35 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-15 19:01 +1300

1""" 

2CIE Illuminant D Series Correlated Colour Temperature 

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

4 

5Define the *CIE Illuminant D Series* correlated colour temperature 

6:math:`T_{cp}` computation objects. 

7 

8- :func:`colour.temperature.xy_to_CCT_CIE_D`: Compute correlated colour 

9 temperature :math:`T_{cp}` of a *CIE Illuminant D Series* from its 

10 *CIE xy* chromaticity coordinates. 

11- :func:`colour.temperature.CCT_to_xy_CIE_D`: Compute *CIE xy* 

12 chromaticity coordinates of a *CIE Illuminant D Series* from its 

13 correlated colour temperature :math:`T_{cp}`. 

14 

15References 

16---------- 

17- :cite:`Wyszecki2000z` : Wyszecki, Günther, & Stiles, W. S. (2000). CIE 

18 Method of Calculating D-Illuminants. In Color Science: Concepts and 

19 Methods, Quantitative Data and Formulae (pp. 145-146). Wiley. 

20 ISBN:978-0-471-39918-6 

21""" 

22 

23from __future__ import annotations 

24 

25import typing 

26 

27import numpy as np 

28 

29from colour.colorimetry import daylight_locus_function 

30 

31if typing.TYPE_CHECKING: 

32 from colour.hints import ArrayLike, DTypeFloat, NDArrayFloat 

33 

34from colour.utilities import as_float, as_float_array, required, tstack, usage_warning 

35 

36__author__ = "Colour Developers" 

37__copyright__ = "Copyright 2013 Colour Developers" 

38__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause" 

39__maintainer__ = "Colour Developers" 

40__email__ = "colour-developers@colour-science.org" 

41__status__ = "Production" 

42 

43__all__ = [ 

44 "xy_to_CCT_CIE_D", 

45 "CCT_to_xy_CIE_D", 

46] 

47 

48 

49@required("SciPy") 

50def xy_to_CCT_CIE_D( 

51 xy: ArrayLike, optimisation_kwargs: dict | None = None 

52) -> NDArrayFloat: 

53 """ 

54 Compute the correlated colour temperature :math:`T_{cp}` of a 

55 *CIE Illuminant D Series* from the specified *CIE xy* chromaticity 

56 coordinates. 

57 

58 Parameters 

59 ---------- 

60 xy 

61 *CIE xy* chromaticity coordinates. 

62 optimisation_kwargs 

63 Parameters for :func:`scipy.optimize.minimize` definition. 

64 

65 Returns 

66 ------- 

67 :class:`numpy.ndarray` 

68 Correlated colour temperature :math:`T_{cp}`. 

69 

70 Warnings 

71 -------- 

72 The *CIE Illuminant D Series* method does not provide an analytical inverse 

73 transformation to compute the correlated colour temperature :math:`T_{cp}` 

74 from the specified *CIE xy* chromaticity coordinates. The current 

75 implementation relies on optimisation using :func:`scipy.optimize.minimize` 

76 definition and thus has reduced precision and poor performance. 

77 

78 References 

79 ---------- 

80 :cite:`Wyszecki2000z` 

81 

82 Examples 

83 -------- 

84 >>> xy_to_CCT_CIE_D(np.array([0.31270775, 0.32911283])) 

85 ... # doctest: +ELLIPSIS 

86 6504.3895840... 

87 """ 

88 

89 from scipy.optimize import minimize # noqa: PLC0415 

90 

91 xy = as_float_array(xy) 

92 shape = xy.shape 

93 xy = np.atleast_1d(np.reshape(xy, (-1, 2))) 

94 

95 def objective_function(CCT: NDArrayFloat, xy: NDArrayFloat) -> DTypeFloat: 

96 """Objective function.""" 

97 

98 objective = np.linalg.norm(CCT_to_xy_CIE_D(CCT) - xy) 

99 

100 return as_float(objective) 

101 

102 optimisation_settings = { 

103 "method": "Nelder-Mead", 

104 "options": { 

105 "fatol": 1e-10, 

106 }, 

107 } 

108 if optimisation_kwargs is not None: 

109 optimisation_settings.update(optimisation_kwargs) 

110 

111 CCT = as_float_array( 

112 [ 

113 minimize( 

114 objective_function, 

115 x0=[6500], 

116 args=(xy_i,), 

117 **optimisation_settings, 

118 ).x 

119 for xy_i in xy 

120 ] 

121 ) 

122 

123 return as_float(np.reshape(CCT, shape[:-1])) 

124 

125 

126def CCT_to_xy_CIE_D(CCT: ArrayLike) -> NDArrayFloat: 

127 """ 

128 Compute the *CIE xy* chromaticity coordinates of a 

129 *CIE Illuminant D Series* from the specified correlated colour temperature 

130 :math:`T_{cp}`. 

131 

132 Parameters 

133 ---------- 

134 CCT 

135 Correlated colour temperature :math:`T_{cp}`. 

136 

137 Returns 

138 ------- 

139 :class:`numpy.ndarray` 

140 *CIE xy* chromaticity coordinates. 

141 

142 Raises 

143 ------ 

144 ValueError 

145 If the correlated colour temperature is not in the appropriate 

146 domain. 

147 

148 References 

149 ---------- 

150 :cite:`Wyszecki2000z` 

151 

152 Examples 

153 -------- 

154 >>> CCT_to_xy_CIE_D(6504.38938305) # doctest: +ELLIPSIS 

155 array([ 0.3127077..., 0.3291128...]) 

156 """ 

157 

158 CCT = as_float_array(CCT) 

159 

160 if np.any(CCT[np.asarray(np.logical_or(CCT < 4000, CCT > 25000))]): 

161 usage_warning( 

162 "Correlated colour temperature must be in domain " 

163 "[4000, 25000], unpredictable results may occur!" 

164 ) 

165 

166 CCT_3 = CCT**3 

167 CCT_2 = CCT**2 

168 

169 x = as_float( 

170 np.where( 

171 CCT <= 7000, 

172 -4.607 * 10**9 / CCT_3 

173 + 2.9678 * 10**6 / CCT_2 

174 + 0.09911 * 10**3 / CCT 

175 + 0.244063, 

176 -2.0064 * 10**9 / CCT_3 

177 + 1.9018 * 10**6 / CCT_2 

178 + 0.24748 * 10**3 / CCT 

179 + 0.23704, 

180 ) 

181 ) 

182 

183 y = daylight_locus_function(x) 

184 

185 return tstack([x, y])