Coverage for colorimetry/transformations.py: 63%

49 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-16 22:49 +1300

1""" 

2Colour Matching Functions Transformations 

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

4 

5Define educational objects for transformations between colour matching 

6functions in various colour spaces and observer standards. 

7 

8- :func:`colour.colorimetry.RGB_2_degree_cmfs_to_XYZ_2_degree_cmfs` 

9- :func:`colour.colorimetry.RGB_10_degree_cmfs_to_XYZ_10_degree_cmfs` 

10- :func:`colour.colorimetry.RGB_10_degree_cmfs_to_LMS_10_degree_cmfs` 

11- :func:`colour.colorimetry.LMS_2_degree_cmfs_to_XYZ_2_degree_cmfs` 

12- :func:`colour.colorimetry.LMS_10_degree_cmfs_to_XYZ_10_degree_cmfs` 

13 

14References 

15---------- 

16- :cite:`CIETC1-362006a` : CIE TC 1-36. (2006). CIE 170-1:2006 Fundamental 

17 Chromaticity Diagram with Physiological Axes - Part 1. Commission 

18 Internationale de l'Eclairage. ISBN:978-3-901906-46-6 

19- :cite:`CVRLp` : CVRL. (n.d.). CIE (2012) 10-deg XYZ 

20 "physiologically-relevant" colour matching functions. Retrieved June 25, 

21 2014, from http://www.cvrl.org/database/text/cienewxyz/cie2012xyz10.htm 

22- :cite:`CVRLv` : CVRL. (n.d.). CIE (2012) 2-deg XYZ 

23 "physiologically-relevant" colour matching functions. Retrieved June 25, 

24 2014, from http://www.cvrl.org/database/text/cienewxyz/cie2012xyz2.htm 

25- :cite:`Wyszecki2000be` : Wyszecki, Günther, & Stiles, W. S. (2000). The 

26 CIE 1964 Standard Observer. In Color Science: Concepts and Methods, 

27 Quantitative Data and Formulae (p. 141). Wiley. ISBN:978-0-471-39918-6 

28- :cite:`Wyszecki2000bg` : Wyszecki, Günther, & Stiles, W. S. (2000). Table 

29 1(3.3.3). In Color Science: Concepts and Methods, Quantitative Data and 

30 Formulae (pp. 138-139). Wiley. ISBN:978-0-471-39918-6 

31""" 

32 

33from __future__ import annotations 

34 

35import typing 

36 

37import numpy as np 

38 

39from colour.algebra import vecmul 

40from colour.colorimetry import ( 

41 MSDS_CMFS_LMS, 

42 MSDS_CMFS_RGB, 

43 SDS_LEFS_PHOTOPIC, 

44 reshape_sd, 

45) 

46 

47if typing.TYPE_CHECKING: 

48 from colour.hints import ArrayLike, NDArrayFloat 

49 

50from colour.utilities import tstack 

51 

52__author__ = "Colour Developers" 

53__copyright__ = "Copyright 2013 Colour Developers" 

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

55__maintainer__ = "Colour Developers" 

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

57__status__ = "Production" 

58 

59__all__ = [ 

60 "RGB_2_degree_cmfs_to_XYZ_2_degree_cmfs", 

61 "RGB_10_degree_cmfs_to_XYZ_10_degree_cmfs", 

62 "RGB_10_degree_cmfs_to_LMS_10_degree_cmfs", 

63 "LMS_2_degree_cmfs_to_XYZ_2_degree_cmfs", 

64 "LMS_10_degree_cmfs_to_XYZ_10_degree_cmfs", 

65] 

66 

67 

68def RGB_2_degree_cmfs_to_XYZ_2_degree_cmfs( 

69 wavelength: ArrayLike, 

70) -> NDArrayFloat: 

71 """ 

72 Convert the *Wright & Guild 1931 2 Degree RGB CMFs* colour matching 

73 functions to the *CIE 1931 2 Degree Standard Observer* colour matching 

74 functions. 

75 

76 Parameters 

77 ---------- 

78 wavelength 

79 Wavelength :math:`\\lambda` in nm. 

80 

81 Returns 

82 ------- 

83 :class:`numpy.ndarray` 

84 *CIE 1931 2 Degree Standard Observer* spectral tristimulus values. 

85 

86 Notes 

87 ----- 

88 - Data for the *CIE 1931 2 Degree Standard Observer* already exists, 

89 this definition is intended for educational purpose. 

90 

91 References 

92 ---------- 

93 :cite:`Wyszecki2000bg` 

94 

95 Examples 

96 -------- 

97 >>> from colour.utilities import numpy_print_options 

98 >>> with numpy_print_options(suppress=True): 

99 ... RGB_2_degree_cmfs_to_XYZ_2_degree_cmfs(700) # doctest: +ELLIPSIS 

100 array([ 0.0113577..., 0.004102 , 0. ]) 

101 """ 

102 

103 cmfs = MSDS_CMFS_RGB["Wright & Guild 1931 2 Degree RGB CMFs"] 

104 

105 rgb_bar = cmfs[wavelength] 

106 

107 rgb = rgb_bar / np.sum(rgb_bar) 

108 

109 M1 = np.array( 

110 [ 

111 [0.49000, 0.31000, 0.20000], 

112 [0.17697, 0.81240, 0.01063], 

113 [0.00000, 0.01000, 0.99000], 

114 ] 

115 ) 

116 

117 M2 = np.array( 

118 [ 

119 [0.66697, 1.13240, 1.20063], 

120 [0.66697, 1.13240, 1.20063], 

121 [0.66697, 1.13240, 1.20063], 

122 ] 

123 ) 

124 

125 xyz = vecmul(M1, rgb) / vecmul(M2, rgb) 

126 

127 x, y, z = xyz[..., 0], xyz[..., 1], xyz[..., 2] 

128 

129 V = reshape_sd( 

130 SDS_LEFS_PHOTOPIC["CIE 1924 Photopic Standard Observer"], 

131 cmfs.shape, 

132 copy=False, 

133 ) 

134 L = V[wavelength] 

135 

136 x_bar = x / y * L 

137 y_bar = L 

138 z_bar = z / y * L 

139 

140 return tstack([x_bar, y_bar, z_bar]) 

141 

142 

143def RGB_10_degree_cmfs_to_XYZ_10_degree_cmfs( 

144 wavelength: ArrayLike, 

145) -> NDArrayFloat: 

146 """ 

147 Convert the *Stiles & Burch 1959 10 Degree RGB CMFs* colour matching 

148 functions to the *CIE 1964 10 Degree Standard Observer* colour matching 

149 functions. 

150 

151 Parameters 

152 ---------- 

153 wavelength 

154 Wavelength :math:`\\lambda` in nm. 

155 

156 Returns 

157 ------- 

158 :class:`numpy.ndarray` 

159 *CIE 1964 10 Degree Standard Observer* spectral tristimulus 

160 values. 

161 

162 Notes 

163 ----- 

164 - Data for the *CIE 1964 10 Degree Standard Observer* already 

165 exists, this definition is intended for educational purpose. 

166 

167 References 

168 ---------- 

169 :cite:`Wyszecki2000be` 

170 

171 Examples 

172 -------- 

173 >>> from colour.utilities import numpy_print_options 

174 >>> with numpy_print_options(suppress=True): 

175 ... RGB_10_degree_cmfs_to_XYZ_10_degree_cmfs(700) # doctest: +ELLIPSIS 

176 array([ 0.0096432..., 0.0037526..., -0.0000041...]) 

177 """ 

178 

179 cmfs = MSDS_CMFS_RGB["Stiles & Burch 1959 10 Degree RGB CMFs"] 

180 

181 rgb_bar = cmfs[wavelength] 

182 

183 M = np.array( 

184 [ 

185 [0.341080, 0.189145, 0.387529], 

186 [0.139058, 0.837460, 0.073316], 

187 [0.000000, 0.039553, 2.026200], 

188 ] 

189 ) 

190 

191 return vecmul(M, rgb_bar) 

192 

193 

194def RGB_10_degree_cmfs_to_LMS_10_degree_cmfs( 

195 wavelength: ArrayLike, 

196) -> NDArrayFloat: 

197 """ 

198 Convert the *Stiles & Burch 1959 10 Degree RGB CMFs* colour matching 

199 functions to the *Stockman & Sharpe 10 Degree Cone Fundamentals* 

200 spectral sensitivity functions. 

201 

202 Parameters 

203 ---------- 

204 wavelength 

205 Wavelength :math:`\\lambda` in nm. 

206 

207 Returns 

208 ------- 

209 :class:`numpy.ndarray` 

210 *Stockman & Sharpe 10 Degree Cone Fundamentals* spectral 

211 tristimulus values. 

212 

213 Notes 

214 ----- 

215 - Data for the *Stockman & Sharpe 10 Degree Cone Fundamentals* 

216 already exists, this definition is intended for educational 

217 purpose. 

218 

219 References 

220 ---------- 

221 :cite:`CIETC1-362006a` 

222 

223 Examples 

224 -------- 

225 >>> from colour.utilities import numpy_print_options 

226 >>> with numpy_print_options(suppress=True): 

227 ... RGB_10_degree_cmfs_to_LMS_10_degree_cmfs(700) # doctest: +ELLIPSIS 

228 array([ 0.0052860..., 0.0003252..., 0. ]) 

229 """ 

230 

231 cmfs = MSDS_CMFS_RGB["Stiles & Burch 1959 10 Degree RGB CMFs"] 

232 

233 rgb_bar = cmfs[wavelength] 

234 

235 M = np.array( 

236 [ 

237 [0.1923252690, 0.749548882, 0.0675726702], 

238 [0.0192290085, 0.940908496, 0.113830196], 

239 [0.0000000000, 0.0105107859, 0.991427669], 

240 ] 

241 ) 

242 

243 lms_bar = vecmul(M, rgb_bar) 

244 lms_bar[..., -1][np.asarray(np.asarray(wavelength) > 505)] = 0 

245 

246 return lms_bar 

247 

248 

249def LMS_2_degree_cmfs_to_XYZ_2_degree_cmfs( 

250 wavelength: ArrayLike, 

251) -> NDArrayFloat: 

252 """ 

253 Convert the *Stockman & Sharpe 2 Degree Cone Fundamentals* colour matching 

254 functions to the *CIE 2015 2 Degree Standard Observer* colour matching 

255 functions. 

256 

257 Parameters 

258 ---------- 

259 wavelength 

260 Wavelength :math:`\\lambda` in nm. 

261 

262 Returns 

263 ------- 

264 :class:`numpy.ndarray` 

265 *CIE 2015 2 Degree Standard Observer* spectral tristimulus values. 

266 

267 Notes 

268 ----- 

269 - Data for the *CIE 2015 2 Degree Standard Observer* already exists, 

270 this definition is intended for educational purpose. 

271 

272 References 

273 ---------- 

274 :cite:`CVRLv` 

275 

276 Examples 

277 -------- 

278 >>> from colour.utilities import numpy_print_options 

279 >>> with numpy_print_options(suppress=True): 

280 ... LMS_2_degree_cmfs_to_XYZ_2_degree_cmfs(700) # doctest: +ELLIPSIS 

281 array([ 0.0109677..., 0.0041959..., 0. ]) 

282 """ 

283 

284 cmfs = MSDS_CMFS_LMS["Stockman & Sharpe 2 Degree Cone Fundamentals"] 

285 

286 lms_bar = cmfs[wavelength] 

287 

288 M = np.array( 

289 [ 

290 [1.94735469, -1.41445123, 0.36476327], 

291 [0.68990272, 0.34832189, 0.00000000], 

292 [0.00000000, 0.00000000, 1.93485343], 

293 ] 

294 ) 

295 

296 return vecmul(M, lms_bar) 

297 

298 

299def LMS_10_degree_cmfs_to_XYZ_10_degree_cmfs( 

300 wavelength: ArrayLike, 

301) -> NDArrayFloat: 

302 """ 

303 Convert the *Stockman & Sharpe 10 Degree Cone Fundamentals* colour matching 

304 functions to the *CIE 2015 10 Degree Standard Observer* colour matching 

305 functions. 

306 

307 Parameters 

308 ---------- 

309 wavelength 

310 Wavelength :math:`\\lambda` in nm. 

311 

312 Returns 

313 ------- 

314 :class:`numpy.ndarray` 

315 *CIE 2015 10 Degree Standard Observer* spectral tristimulus values. 

316 

317 Notes 

318 ----- 

319 - Data for the *CIE 2015 10 Degree Standard Observer* already exists, 

320 this definition is intended for educational purpose. 

321 

322 References 

323 ---------- 

324 :cite:`CVRLp` 

325 

326 Examples 

327 -------- 

328 >>> from colour.utilities import numpy_print_options 

329 >>> with numpy_print_options(suppress=True): 

330 ... LMS_10_degree_cmfs_to_XYZ_10_degree_cmfs(700) # doctest: +ELLIPSIS 

331 array([ 0.0098162..., 0.0037761..., 0. ]) 

332 """ 

333 

334 cmfs = MSDS_CMFS_LMS["Stockman & Sharpe 10 Degree Cone Fundamentals"] 

335 

336 lms_bar = cmfs[wavelength] 

337 

338 M = np.array( 

339 [ 

340 [1.93986443, -1.34664359, 0.43044935], 

341 [0.69283932, 0.34967567, 0.00000000], 

342 [0.00000000, 0.00000000, 2.14687945], 

343 ] 

344 ) 

345 

346 return vecmul(M, lms_bar)