Coverage for models/rgb/tests/test_derivation.py: 100%

109 statements  

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

1"""Define the unit tests for the :mod:`colour.models.rgb.derivation` module.""" 

2 

3from __future__ import annotations 

4 

5import contextlib 

6import re 

7from itertools import product 

8 

9import numpy as np 

10from numpy.linalg import LinAlgError 

11 

12from colour.constants import TOLERANCE_ABSOLUTE_TESTS 

13from colour.models import ( 

14 RGB_luminance, 

15 RGB_luminance_equation, 

16 chromatically_adapted_primaries, 

17 normalised_primary_matrix, 

18 primaries_whitepoint, 

19) 

20from colour.models.rgb.derivation import xy_to_z 

21from colour.utilities import ignore_numpy_errors 

22 

23__author__ = "Colour Developers" 

24__copyright__ = "Copyright 2013 Colour Developers" 

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

26__maintainer__ = "Colour Developers" 

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

28__status__ = "Production" 

29 

30__all__ = [ 

31 "Testxy_to_z", 

32 "TestNormalisedPrimaryMatrix", 

33 "TestChromaticallyAdaptedPrimaries", 

34 "TestPrimariesWhitepoint", 

35 "TestRGBLuminanceEquation", 

36 "TestRGBLuminance", 

37] 

38 

39 

40class Testxy_to_z: 

41 """ 

42 Define :func:`colour.models.rgb.derivation.xy_to_z` definition unit 

43 tests methods. 

44 """ 

45 

46 def test_xy_to_z(self) -> None: 

47 """Test :func:`colour.models.rgb.derivation.xy_to_z` definition.""" 

48 

49 np.testing.assert_allclose( 

50 xy_to_z(np.array([0.2500, 0.2500])), 

51 0.50000000, 

52 atol=TOLERANCE_ABSOLUTE_TESTS, 

53 ) 

54 

55 np.testing.assert_allclose( 

56 xy_to_z(np.array([0.0001, -0.0770])), 

57 1.07690000, 

58 atol=TOLERANCE_ABSOLUTE_TESTS, 

59 ) 

60 

61 np.testing.assert_allclose( 

62 xy_to_z(np.array([0.0000, 1.0000])), 

63 0.00000000, 

64 atol=TOLERANCE_ABSOLUTE_TESTS, 

65 ) 

66 

67 def test_n_dimensional_xy_to_z(self) -> None: 

68 """ 

69 Test :func:`colour.models.rgb.derivation.xy_to_z` definition 

70 n-dimensional arrays support. 

71 """ 

72 

73 xy = np.array([0.25, 0.25]) 

74 z = xy_to_z(xy) 

75 

76 xy = np.tile(xy, (6, 1)) 

77 z = np.tile( 

78 z, 

79 6, 

80 ) 

81 np.testing.assert_allclose(xy_to_z(xy), z, atol=TOLERANCE_ABSOLUTE_TESTS) 

82 

83 xy = np.reshape(xy, (2, 3, 2)) 

84 z = np.reshape(z, (2, 3)) 

85 np.testing.assert_allclose(xy_to_z(xy), z, atol=TOLERANCE_ABSOLUTE_TESTS) 

86 

87 @ignore_numpy_errors 

88 def test_nan_xy_to_z(self) -> None: 

89 """ 

90 Test :func:`colour.models.rgb.derivation.xy_to_z` definition nan 

91 support. 

92 """ 

93 

94 cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] 

95 cases = np.array(list(set(product(cases, repeat=2)))) 

96 xy_to_z(cases) 

97 

98 

99class TestNormalisedPrimaryMatrix: 

100 """ 

101 Define :func:`colour.models.rgb.derivation.normalised_primary_matrix` 

102 definition unit tests methods. 

103 """ 

104 

105 def test_normalised_primary_matrix(self) -> None: 

106 """ 

107 Test :func:`colour.models.rgb.derivation.normalised_primary_matrix` 

108 definition. 

109 """ 

110 

111 np.testing.assert_allclose( 

112 normalised_primary_matrix( 

113 np.array([0.73470, 0.26530, 0.00000, 1.00000, 0.00010, -0.07700]), 

114 np.array([0.32168, 0.33767]), 

115 ), 

116 np.array( 

117 [ 

118 [0.95255240, 0.00000000, 0.00009368], 

119 [0.34396645, 0.72816610, -0.07213255], 

120 [0.00000000, 0.00000000, 1.00882518], 

121 ] 

122 ), 

123 atol=TOLERANCE_ABSOLUTE_TESTS, 

124 ) 

125 

126 np.testing.assert_allclose( 

127 normalised_primary_matrix( 

128 np.array([0.640, 0.330, 0.300, 0.600, 0.150, 0.060]), 

129 np.array([0.3127, 0.3290]), 

130 ), 

131 np.array( 

132 [ 

133 [0.41239080, 0.35758434, 0.18048079], 

134 [0.21263901, 0.71516868, 0.07219232], 

135 [0.01933082, 0.11919478, 0.95053215], 

136 ] 

137 ), 

138 atol=TOLERANCE_ABSOLUTE_TESTS, 

139 ) 

140 

141 @ignore_numpy_errors 

142 def test_nan_normalised_primary_matrix(self) -> None: 

143 """ 

144 Test :func:`colour.models.rgb.derivation.normalised_primary_matrix` 

145 definition nan support. 

146 """ 

147 

148 cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] 

149 cases = np.array(list(set(product(cases, repeat=2)))) 

150 for case in cases: 

151 P = np.array(np.vstack([case, case, case])) 

152 W = case 

153 with contextlib.suppress(LinAlgError): 

154 normalised_primary_matrix(P, W) 

155 

156 

157class TestChromaticallyAdaptedPrimaries: 

158 """ 

159 Define :func:`colour.models.rgb.derivation.\ 

160chromatically_adapted_primaries` definition unit tests methods. 

161 """ 

162 

163 def test_chromatically_adapted_primaries(self) -> None: 

164 """ 

165 Test :func:`colour.models.rgb.derivation.\ 

166chromatically_adapted_primaries` definition. 

167 """ 

168 

169 np.testing.assert_allclose( 

170 chromatically_adapted_primaries( 

171 np.array([0.73470, 0.26530, 0.00000, 1.00000, 0.00010, -0.07700]), 

172 np.array([0.32168, 0.33767]), 

173 np.array([0.34570, 0.35850]), 

174 ), 

175 np.array( 

176 [ 

177 [0.73431182, 0.26694964], 

178 [0.02211963, 0.98038009], 

179 [-0.05880375, -0.12573056], 

180 ] 

181 ), 

182 atol=TOLERANCE_ABSOLUTE_TESTS, 

183 ) 

184 

185 np.testing.assert_allclose( 

186 chromatically_adapted_primaries( 

187 np.array([0.640, 0.330, 0.300, 0.600, 0.150, 0.060]), 

188 np.array([0.31270, 0.32900]), 

189 np.array([0.34570, 0.35850]), 

190 ), 

191 np.array( 

192 [ 

193 [0.64922534, 0.33062196], 

194 [0.32425276, 0.60237128], 

195 [0.15236177, 0.06118676], 

196 ] 

197 ), 

198 atol=TOLERANCE_ABSOLUTE_TESTS, 

199 ) 

200 

201 np.testing.assert_allclose( 

202 chromatically_adapted_primaries( 

203 np.array([0.640, 0.330, 0.300, 0.600, 0.150, 0.060]), 

204 np.array([0.31270, 0.32900]), 

205 np.array([0.34570, 0.35850]), 

206 "Bradford", 

207 ), 

208 np.array( 

209 [ 

210 [0.64844144, 0.33085331], 

211 [0.32119518, 0.59784434], 

212 [0.15589322, 0.06604921], 

213 ] 

214 ), 

215 atol=TOLERANCE_ABSOLUTE_TESTS, 

216 ) 

217 

218 @ignore_numpy_errors 

219 def test_nan_chromatically_adapted_primaries(self) -> None: 

220 """ 

221 Test :func:`colour.models.rgb.derivation.\ 

222chromatically_adapted_primaries` definition nan support. 

223 """ 

224 

225 cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] 

226 cases = np.array(list(set(product(cases, repeat=2)))) 

227 for case in cases: 

228 P = np.array(np.vstack([case, case, case])) 

229 W = case 

230 chromatically_adapted_primaries(P, W, W) 

231 

232 

233class TestPrimariesWhitepoint: 

234 """ 

235 Define :func:`colour.models.rgb.derivation.primaries_whitepoint` 

236 definition unit tests methods. 

237 """ 

238 

239 def test_primaries_whitepoint(self) -> None: 

240 """ 

241 Test :func:`colour.models.rgb.derivation.primaries_whitepoint` 

242 definition. 

243 """ 

244 

245 P, W = primaries_whitepoint( 

246 np.array( 

247 [ 

248 [0.95255240, 0.00000000, 0.00009368], 

249 [0.34396645, 0.72816610, -0.07213255], 

250 [0.00000000, 0.00000000, 1.00882518], 

251 ] 

252 ) 

253 ) 

254 np.testing.assert_allclose( 

255 P, 

256 np.array( 

257 [ 

258 [0.73470, 0.26530], 

259 [0.00000, 1.00000], 

260 [0.00010, -0.07700], 

261 ] 

262 ), 

263 atol=TOLERANCE_ABSOLUTE_TESTS, 

264 ) 

265 np.testing.assert_allclose( 

266 W, np.array([0.32168, 0.33767]), atol=TOLERANCE_ABSOLUTE_TESTS 

267 ) 

268 

269 P, W = primaries_whitepoint( 

270 np.array( 

271 [ 

272 [0.41240000, 0.35760000, 0.18050000], 

273 [0.21260000, 0.71520000, 0.07220000], 

274 [0.01930000, 0.11920000, 0.95050000], 

275 ] 

276 ) 

277 ) 

278 np.testing.assert_allclose( 

279 P, 

280 np.array( 

281 [ 

282 [0.64007450, 0.32997051], 

283 [0.30000000, 0.60000000], 

284 [0.15001662, 0.06000665], 

285 ] 

286 ), 

287 atol=TOLERANCE_ABSOLUTE_TESTS, 

288 ) 

289 np.testing.assert_allclose( 

290 W, 

291 np.array([0.31271591, 0.32900148]), 

292 atol=TOLERANCE_ABSOLUTE_TESTS, 

293 ) 

294 

295 @ignore_numpy_errors 

296 def test_nan_primaries_whitepoint(self) -> None: 

297 """ 

298 Test :func:`colour.models.rgb.derivation.primaries_whitepoint` 

299 definition nan support. 

300 """ 

301 

302 cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] 

303 cases = np.array(list(set(product(cases, repeat=3)))) 

304 for case in cases: 

305 M = np.array(np.vstack([case, case, case])) 

306 primaries_whitepoint(M) 

307 

308 

309class TestRGBLuminanceEquation: 

310 """ 

311 Define :func:`colour.models.rgb.derivation.RGB_luminance_equation` 

312 definition unit tests methods. 

313 """ 

314 

315 def test_RGB_luminance_equation(self) -> None: 

316 """ 

317 Test :func:`colour.models.rgb.derivation.RGB_luminance_equation` 

318 definition. 

319 """ 

320 

321 assert isinstance( 

322 RGB_luminance_equation( 

323 np.array([0.73470, 0.26530, 0.00000, 1.00000, 0.00010, -0.07700]), 

324 np.array([0.32168, 0.33767]), 

325 ), 

326 str, 

327 ) 

328 

329 # TODO: Simplify that monster. 

330 pattern = ( 

331 "Y\\s?=\\s?[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?." 

332 "\\(R\\)\\s?[+-]\\s?[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?." 

333 "\\(G\\)\\s?[+-]\\s?[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?." 

334 "\\(B\\)" 

335 ) 

336 P = np.array([0.73470, 0.26530, 0.00000, 1.00000, 0.00010, -0.07700]) 

337 assert re.match( 

338 pattern, 

339 RGB_luminance_equation(P, np.array([0.32168, 0.33767])), 

340 ) 

341 

342 

343class TestRGBLuminance: 

344 """ 

345 Define :func:`colour.models.rgb.derivation.RGB_luminance` definition 

346 unit tests methods. 

347 """ 

348 

349 def test_RGB_luminance(self) -> None: 

350 """ 

351 Test :func:`colour.models.rgb.derivation.RGB_luminance` 

352 definition. 

353 """ 

354 

355 np.testing.assert_allclose( 

356 RGB_luminance( 

357 np.array([0.18, 0.18, 0.18]), 

358 np.array([0.73470, 0.26530, 0.00000, 1.00000, 0.00010, -0.07700]), 

359 np.array([0.32168, 0.33767]), 

360 ), 

361 0.18000000, 

362 atol=TOLERANCE_ABSOLUTE_TESTS, 

363 ) 

364 

365 np.testing.assert_allclose( 

366 RGB_luminance( 

367 np.array([0.21959402, 0.06986677, 0.04703877]), 

368 np.array([0.73470, 0.26530, 0.00000, 1.00000, 0.00010, -0.07700]), 

369 np.array([0.32168, 0.33767]), 

370 ), 

371 0.123014562384318, 

372 atol=TOLERANCE_ABSOLUTE_TESTS, 

373 ) 

374 

375 np.testing.assert_allclose( 

376 RGB_luminance( 

377 np.array([0.45620519, 0.03081071, 0.04091952]), 

378 np.array([0.6400, 0.3300, 0.3000, 0.6000, 0.1500, 0.0600]), 

379 np.array([0.31270, 0.32900]), 

380 ), 

381 0.121995947729870, 

382 atol=TOLERANCE_ABSOLUTE_TESTS, 

383 ) 

384 

385 def test_n_dimensional_RGB_luminance(self) -> None: 

386 """ 

387 Test :func:`colour.models.rgb.derivation.RGB_luminance` definition 

388 n_dimensional arrays support. 

389 """ 

390 

391 RGB = (np.array([0.18, 0.18, 0.18]),) 

392 P = (np.array([0.73470, 0.26530, 0.00000, 1.00000, 0.00010, -0.07700]),) 

393 W = np.array([0.32168, 0.33767]) 

394 Y = RGB_luminance(RGB, P, W) 

395 

396 RGB = np.tile(RGB, (6, 1)) 

397 Y = np.tile(Y, 6) 

398 np.testing.assert_allclose( 

399 RGB_luminance(RGB, P, W), Y, atol=TOLERANCE_ABSOLUTE_TESTS 

400 ) 

401 

402 RGB = np.reshape(RGB, (2, 3, 3)) 

403 Y = np.reshape(Y, (2, 3)) 

404 np.testing.assert_allclose( 

405 RGB_luminance(RGB, P, W), Y, atol=TOLERANCE_ABSOLUTE_TESTS 

406 ) 

407 

408 @ignore_numpy_errors 

409 def test_nan_RGB_luminance(self) -> None: 

410 """ 

411 Test :func:`colour.models.rgb.derivation.RGB_luminance` 

412 definition nan support. 

413 """ 

414 

415 cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] 

416 cases = np.array(list(set(product(cases, repeat=3)))) 

417 for case in cases: 

418 RGB = case 

419 P = np.array(np.vstack([case[0:2], case[0:2], case[0:2]])) 

420 W = case[0:2] 

421 with contextlib.suppress(LinAlgError): 

422 RGB_luminance(RGB, P, W)