Coverage for quality/tests/test_cri.py: 100%

44 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.quality.cri` module.""" 

2 

3from __future__ import annotations 

4 

5import numpy as np 

6 

7from colour.colorimetry import ( 

8 MSDS_CMFS, 

9 SDS_ILLUMINANTS, 

10 SPECTRAL_SHAPE_DEFAULT, 

11 SpectralDistribution, 

12 reshape_msds, 

13 reshape_sd, 

14) 

15from colour.constants import TOLERANCE_ABSOLUTE_TESTS 

16from colour.quality import ColourRendering_Specification_CRI, colour_rendering_index 

17from colour.quality.cri import ( 

18 DataColorimetry_TCS, 

19 DataColourQualityScale_TCS, 

20 tcs_colorimetry_data, 

21) 

22from colour.quality.datasets.tcs import SDS_TCS 

23 

24__author__ = "Colour Developers" 

25__copyright__ = "Copyright 2013 Colour Developers" 

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

27__maintainer__ = "Colour Developers" 

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

29__status__ = "Production" 

30 

31__all__ = [ 

32 "TestColourRenderingIndex", 

33] 

34 

35DATA_SAMPLE: dict = { 

36 380: 0.00588346, 

37 385: 0.00315377, 

38 390: 0.00242868, 

39 395: 0.00508709, 

40 400: 0.00323282, 

41 405: 0.00348764, 

42 410: 0.00369248, 

43 415: 0.00520924, 

44 420: 0.00747913, 

45 425: 0.01309795, 

46 430: 0.02397167, 

47 435: 0.04330206, 

48 440: 0.08272117, 

49 445: 0.14123187, 

50 450: 0.23400416, 

51 455: 0.34205230, 

52 460: 0.43912850, 

53 465: 0.44869766, 

54 470: 0.37549764, 

55 475: 0.27829316, 

56 480: 0.19453198, 

57 485: 0.14168353, 

58 490: 0.11233585, 

59 495: 0.10301871, 

60 500: 0.11438976, 

61 505: 0.14553810, 

62 510: 0.18971677, 

63 515: 0.25189581, 

64 520: 0.31072378, 

65 525: 0.35998103, 

66 530: 0.38208860, 

67 535: 0.37610602, 

68 540: 0.34653432, 

69 545: 0.30803672, 

70 550: 0.26015946, 

71 555: 0.21622002, 

72 560: 0.17448497, 

73 565: 0.13561398, 

74 570: 0.10873008, 

75 575: 0.08599236, 

76 580: 0.06863164, 

77 585: 0.05875286, 

78 590: 0.05276579, 

79 595: 0.05548599, 

80 600: 0.07291154, 

81 605: 0.15319944, 

82 610: 0.38753740, 

83 615: 0.81754322, 

84 620: 1.00000000, 

85 625: 0.64794360, 

86 630: 0.21375526, 

87 635: 0.03710525, 

88 640: 0.01761510, 

89 645: 0.01465312, 

90 650: 0.01384908, 

91 655: 0.01465716, 

92 660: 0.01347059, 

93 665: 0.01424768, 

94 670: 0.01215791, 

95 675: 0.01209338, 

96 680: 0.01155313, 

97 685: 0.01061995, 

98 690: 0.01014779, 

99 695: 0.00864212, 

100 700: 0.00951386, 

101 705: 0.00786982, 

102 710: 0.00841476, 

103 715: 0.00741868, 

104 720: 0.00637711, 

105 725: 0.00556483, 

106 730: 0.00590016, 

107 735: 0.00416819, 

108 740: 0.00422222, 

109 745: 0.00345776, 

110 750: 0.00336879, 

111 755: 0.00298999, 

112 760: 0.00367047, 

113 765: 0.00340568, 

114 770: 0.00261153, 

115 775: 0.00258850, 

116 780: 0.00293663, 

117} 

118 

119 

120class TestColourRenderingIndex: 

121 """ 

122 Define :func:`colour.quality.cri.colour_rendering_index` 

123 definition unit tests methods. 

124 """ 

125 

126 def test_colour_rendering_index(self) -> None: 

127 """Test :func:`colour.quality.cri.colour_rendering_index` definition.""" 

128 

129 np.testing.assert_allclose( 

130 colour_rendering_index(SDS_ILLUMINANTS["FL1"], additional_data=False), 

131 75.852827992149358, 

132 atol=TOLERANCE_ABSOLUTE_TESTS, 

133 ) 

134 

135 np.testing.assert_allclose( 

136 colour_rendering_index(SDS_ILLUMINANTS["FL2"], additional_data=False), 

137 64.233724121664778, 

138 atol=TOLERANCE_ABSOLUTE_TESTS, 

139 ) 

140 

141 np.testing.assert_allclose( 

142 colour_rendering_index(SDS_ILLUMINANTS["A"], additional_data=False), 

143 99.996230290506887, 

144 atol=TOLERANCE_ABSOLUTE_TESTS, 

145 ) 

146 

147 np.testing.assert_allclose( 

148 colour_rendering_index( 

149 SpectralDistribution(DATA_SAMPLE), additional_data=False 

150 ), 

151 70.815265381660197, 

152 atol=TOLERANCE_ABSOLUTE_TESTS, 

153 ) 

154 

155 specification_r = ColourRendering_Specification_CRI( 

156 name="FL1", 

157 Q_a=75.852827992149358, 

158 Q_as={ 

159 1: DataColourQualityScale_TCS(name="TCS01", Q_a=69.196992839933557), 

160 2: DataColourQualityScale_TCS(name="TCS02", Q_a=83.650754065677816), 

161 3: DataColourQualityScale_TCS(name="TCS03", Q_a=92.136090764490675), 

162 4: DataColourQualityScale_TCS(name="TCS04", Q_a=72.665649420972784), 

163 5: DataColourQualityScale_TCS(name="TCS05", Q_a=73.890734513517486), 

164 6: DataColourQualityScale_TCS(name="TCS06", Q_a=79.619188860052745), 

165 7: DataColourQualityScale_TCS(name="TCS07", Q_a=82.272569853644669), 

166 8: DataColourQualityScale_TCS(name="TCS08", Q_a=53.390643618905109), 

167 9: DataColourQualityScale_TCS(name="TCS09", Q_a=-47.284477750225903), 

168 10: DataColourQualityScale_TCS(name="TCS10", Q_a=61.568336431199967), 

169 11: DataColourQualityScale_TCS(name="TCS11", Q_a=67.522241168172485), 

170 12: DataColourQualityScale_TCS(name="TCS12", Q_a=74.890093866757994), 

171 13: DataColourQualityScale_TCS(name="TCS13", Q_a=72.771930354944615), 

172 14: DataColourQualityScale_TCS(name="TCS14", Q_a=94.884867470552663), 

173 15: DataColourQualityScale_TCS(name="TCS15", Q_a=59.613744524909143), 

174 }, 

175 colorimetry_data=( 

176 ( 

177 DataColorimetry_TCS( 

178 name="TCS01", 

179 XYZ=np.array([31.19561134, 29.74560797, 23.44190201]), 

180 uv=np.array([0.22782766, 0.32585700]), 

181 UVW=np.array([25.43090825, 8.72673714, 60.46061819]), 

182 ), 

183 DataColorimetry_TCS( 

184 name="TCS02", 

185 XYZ=np.array([26.70829694, 29.25797165, 13.98804447]), 

186 uv=np.array([0.21049132, 0.34587843]), 

187 UVW=np.array([11.90704877, 24.68727835, 60.03499882]), 

188 ), 

189 DataColorimetry_TCS( 

190 name="TCS03", 

191 XYZ=np.array([24.20150315, 31.45341032, 9.19170689]), 

192 uv=np.array([0.18489328, 0.36044399]), 

193 UVW=np.array([-8.11343024, 37.47469142, 61.91555021]), 

194 ), 

195 DataColorimetry_TCS( 

196 name="TCS04", 

197 XYZ=np.array([20.74577359, 29.44046997, 19.40749007]), 

198 uv=np.array([0.15940652, 0.33932233]), 

199 UVW=np.array([-27.55686536, 19.30727375, 60.19483706]), 

200 ), 

201 DataColorimetry_TCS( 

202 name="TCS05", 

203 XYZ=np.array([25.09405566, 30.60912259, 37.93634878]), 

204 uv=np.array([0.16784200, 0.30709443]), 

205 UVW=np.array([-21.30541564, -6.63859760, 61.20303996]), 

206 ), 

207 DataColorimetry_TCS( 

208 name="TCS06", 

209 XYZ=np.array([27.43598853, 28.84467787, 55.15209308]), 

210 uv=np.array([0.17543246, 0.27665994]), 

211 UVW=np.array([-14.91500194, -30.51166823, 59.67054901]), 

212 ), 

213 DataColorimetry_TCS( 

214 name="TCS07", 

215 XYZ=np.array([31.30354023, 28.49931283, 51.55875721]), 

216 uv=np.array([0.20410821, 0.27873574]), 

217 UVW=np.array([6.88826195, -28.65430811, 59.36332055]), 

218 ), 

219 DataColorimetry_TCS( 

220 name="TCS08", 

221 XYZ=np.array([33.81156122, 29.92921717, 44.07459562]), 

222 uv=np.array([0.21992203, 0.29200489]), 

223 UVW=np.array([19.29699368, -18.57115711, 60.61967045]), 

224 ), 

225 DataColorimetry_TCS( 

226 name="TCS09", 

227 XYZ=np.array([14.75210654, 9.07663825, 4.24056478]), 

228 uv=np.array([0.36063567, 0.33283649]), 

229 UVW=np.array([74.85972274, 8.59043120, 35.14928413]), 

230 ), 

231 DataColorimetry_TCS( 

232 name="TCS10", 

233 XYZ=np.array([53.37923227, 60.57123196, 10.90035400]), 

234 uv=np.array([0.21466565, 0.36538264]), 

235 UVW=np.array([20.48612095, 54.66177264, 81.18130740]), 

236 ), 

237 DataColorimetry_TCS( 

238 name="TCS11", 

239 XYZ=np.array([12.25313424, 19.77564573, 14.04738059]), 

240 uv=np.array([0.13962494, 0.33801637]), 

241 UVW=np.array([-36.00690822, 15.29571595, 50.60573931]), 

242 ), 

243 DataColorimetry_TCS( 

244 name="TCS12", 

245 XYZ=np.array([5.77964943, 5.69096075, 24.73530409]), 

246 uv=np.array([0.13981616, 0.20650602]), 

247 UVW=np.array([-19.30689974, -39.58762581, 27.63428055]), 

248 ), 

249 DataColorimetry_TCS( 

250 name="TCS13", 

251 XYZ=np.array([56.62340157, 57.50304691, 39.13768236]), 

252 uv=np.array([0.21850039, 0.33284220]), 

253 UVW=np.array([23.93135946, 18.85365757, 79.49473722]), 

254 ), 

255 DataColorimetry_TCS( 

256 name="TCS14", 

257 XYZ=np.array([9.42270977, 12.06929274, 5.06066928]), 

258 uv=np.array([0.18328188, 0.35214117]), 

259 UVW=np.array([-6.11563143, 19.91896684, 40.34566797]), 

260 ), 

261 DataColorimetry_TCS( 

262 name="TCS15", 

263 XYZ=np.array([31.87001132, 31.71897232, 22.84936407]), 

264 uv=np.array([0.22124167, 0.33028974]), 

265 UVW=np.array([20.88976213, 12.62627126, 62.13702346]), 

266 ), 

267 ), 

268 ( 

269 DataColorimetry_TCS( 

270 name="TCS01", 

271 XYZ=np.array([33.04774537, 29.80902109, 24.23929188]), 

272 uv=np.array([0.23908620, 0.32348313]), 

273 UVW=np.array([32.11891091, 8.39794012, 60.51562388]), 

274 ), 

275 DataColorimetry_TCS( 

276 name="TCS02", 

277 XYZ=np.array([27.53677515, 28.90913487, 14.75211494]), 

278 uv=np.array([0.21792745, 0.34318256]), 

279 UVW=np.array([15.27177183, 23.58438306, 59.72761646]), 

280 ), 

281 DataColorimetry_TCS( 

282 name="TCS03", 

283 XYZ=np.array([23.95706051, 30.44569936, 9.79977770]), 

284 uv=np.array([0.18788308, 0.35815528]), 

285 UVW=np.array([-8.23665275, 35.99767796, 61.06361523]), 

286 ), 

287 DataColorimetry_TCS( 

288 name="TCS04", 

289 XYZ=np.array([20.43647757, 29.46748627, 21.03631859]), 

290 uv=np.array([0.15554126, 0.33641389]), 

291 UVW=np.array([-33.44111710, 18.47940853, 60.21844268]), 

292 ), 

293 DataColorimetry_TCS( 

294 name="TCS05", 

295 XYZ=np.array([24.95511680, 30.81953457, 39.91407614]), 

296 uv=np.array([0.16445149, 0.30464603]), 

297 UVW=np.array([-26.97713986, -6.51317420, 61.38182431]), 

298 ), 

299 DataColorimetry_TCS( 

300 name="TCS06", 

301 XYZ=np.array([28.14601546, 29.75632189, 57.16886797]), 

302 uv=np.array([0.17427942, 0.27637560]), 

303 UVW=np.array([-18.85053083, -28.64005452, 60.46991712]), 

304 ), 

305 DataColorimetry_TCS( 

306 name="TCS07", 

307 XYZ=np.array([33.29720901, 29.36938555, 52.53803430]), 

308 uv=np.array([0.21092469, 0.27906521]), 

309 UVW=np.array([9.90110830, -26.37778265, 60.13265766]), 

310 ), 

311 DataColorimetry_TCS( 

312 name="TCS08", 

313 XYZ=np.array([37.64974363, 31.35401774, 44.84930911]), 

314 uv=np.array([0.23439240, 0.29279655]), 

315 UVW=np.array([29.04479043, -16.08583648, 61.83233828]), 

316 ), 

317 DataColorimetry_TCS( 

318 name="TCS09", 

319 XYZ=np.array([20.69443384, 11.28822434, 4.28723010]), 

320 uv=np.array([0.40801431, 0.33384028]), 

321 UVW=np.array([106.56664825, 10.68535426, 39.08093160]), 

322 ), 

323 DataColorimetry_TCS( 

324 name="TCS10", 

325 XYZ=np.array([55.04099876, 59.04719161, 11.86354410]), 

326 uv=np.array([0.22549942, 0.36286881]), 

327 UVW=np.array([28.45432459, 52.29127793, 80.35085218]), 

328 ), 

329 DataColorimetry_TCS( 

330 name="TCS11", 

331 XYZ=np.array([12.13069359, 20.35272336, 15.17132466]), 

332 uv=np.array([0.13369530, 0.33646842]), 

333 UVW=np.array([-43.02145539, 15.76573781, 51.25705062]), 

334 ), 

335 DataColorimetry_TCS( 

336 name="TCS12", 

337 XYZ=np.array([6.18799870, 6.41132549, 27.28158667]), 

338 uv=np.array([0.13437372, 0.20883497]), 

339 UVW=np.array([-24.45285903, -39.79705961, 29.44325151]), 

340 ), 

341 DataColorimetry_TCS( 

342 name="TCS13", 

343 XYZ=np.array([58.97935503, 57.14777525, 40.83450223]), 

344 uv=np.array([0.22712769, 0.33011150]), 

345 UVW=np.array([29.75912462, 17.83690656, 79.29560174]), 

346 ), 

347 DataColorimetry_TCS( 

348 name="TCS14", 

349 XYZ=np.array([9.34469915, 11.70922060, 5.33442353]), 

350 uv=np.array([0.18597686, 0.34955284]), 

351 UVW=np.array([-6.34991066, 18.99712303, 39.76962229]), 

352 ), 

353 DataColorimetry_TCS( 

354 name="TCS15", 

355 XYZ=np.array([35.0651964, 32.69237678, 24.25024725]), 

356 uv=np.array([0.23447077, 0.32790662]), 

357 UVW=np.array([29.62847425, 12.35345214, 62.93841026]), 

358 ), 

359 ), 

360 ), 

361 ) 

362 

363 specification_t = colour_rendering_index( 

364 SDS_ILLUMINANTS["FL1"], additional_data=True, method="CIE 2024" 

365 ) 

366 

367 np.testing.assert_allclose( 

368 [data.Q_a for _index, data in sorted(specification_r.Q_as.items())], 

369 [data.Q_a for _index, data in sorted(specification_t.Q_as.items())], 

370 atol=TOLERANCE_ABSOLUTE_TESTS, 

371 ) 

372 

373 specification_r.Q_as.pop(15) 

374 test_col_data = specification_r.colorimetry_data[0][:-1] 

375 ref_col_data = specification_r.colorimetry_data[1][:-1] 

376 specification_r.colorimetry_data = (test_col_data, ref_col_data) 

377 

378 specification_t = colour_rendering_index( 

379 SDS_ILLUMINANTS["FL1"], additional_data=True, method="CIE 1995" 

380 ) 

381 

382 np.testing.assert_allclose( 

383 [data.Q_a for _index, data in sorted(specification_r.Q_as.items())], 

384 [data.Q_a for _index, data in sorted(specification_t.Q_as.items())], 

385 atol=TOLERANCE_ABSOLUTE_TESTS, 

386 ) 

387 

388 specification_t = colour_rendering_index( 

389 SDS_ILLUMINANTS["FL1"], additional_data=True 

390 ) 

391 

392 np.testing.assert_allclose( 

393 specification_r.Q_a, specification_t.Q_a, atol=TOLERANCE_ABSOLUTE_TESTS 

394 ) 

395 

396 np.testing.assert_allclose( 

397 [data.Q_a for _index, data in sorted(specification_r.Q_as.items())], 

398 [data.Q_a for _index, data in sorted(specification_t.Q_as.items())], 

399 atol=TOLERANCE_ABSOLUTE_TESTS, 

400 ) 

401 

402 for data in ["XYZ", "uv", "UVW"]: 

403 np.testing.assert_allclose( 

404 [ 

405 getattr(tcs, data) 

406 for colorimetry_data in specification_r.colorimetry_data 

407 for tcs in colorimetry_data 

408 ], 

409 [ 

410 getattr(tcs, data) 

411 for colorimetry_data in specification_t.colorimetry_data 

412 for tcs in colorimetry_data 

413 ], 

414 atol=TOLERANCE_ABSOLUTE_TESTS, 

415 ) 

416 

417 # Test with missing TCS data 

418 sd_test = SDS_ILLUMINANTS["FL1"] 

419 cmfs = reshape_msds( 

420 MSDS_CMFS["CIE 1931 2 Degree Standard Observer"], 

421 SPECTRAL_SHAPE_DEFAULT, 

422 copy=False, 

423 ) 

424 shape = cmfs.shape 

425 sd_test = reshape_sd(sd_test, shape, copy=False) 

426 

427 sds_tcs_full = SDS_TCS["CIE 1995"] 

428 tcs_dict_full = { 

429 sd.name: reshape_sd(sd, shape, copy=False) for sd in sds_tcs_full.values() 

430 } 

431 tcs_dict_partial = {k: v for k, v in tcs_dict_full.items() if k != "TCS09"} 

432 

433 result = tcs_colorimetry_data( 

434 sd_test, sd_test, tcs_dict_partial, cmfs, method="CIE 1995" 

435 ) 

436 assert len(result) == 13