Coverage for colour/quality/tests/test_cri.py: 100%
44 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 23:01 +1300
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 23:01 +1300
1"""Define the unit tests for the :mod:`colour.quality.cri` module."""
3from __future__ import annotations
5import numpy as np
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
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"
31__all__ = [
32 "TestColourRenderingIndex",
33]
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}
120class TestColourRenderingIndex:
121 """
122 Define :func:`colour.quality.cri.colour_rendering_index`
123 definition unit tests methods.
124 """
126 def test_colour_rendering_index(self) -> None:
127 """Test :func:`colour.quality.cri.colour_rendering_index` definition."""
129 np.testing.assert_allclose(
130 colour_rendering_index(SDS_ILLUMINANTS["FL1"], additional_data=False),
131 75.852827992149358,
132 atol=TOLERANCE_ABSOLUTE_TESTS,
133 )
135 np.testing.assert_allclose(
136 colour_rendering_index(SDS_ILLUMINANTS["FL2"], additional_data=False),
137 64.233724121664778,
138 atol=TOLERANCE_ABSOLUTE_TESTS,
139 )
141 np.testing.assert_allclose(
142 colour_rendering_index(SDS_ILLUMINANTS["A"], additional_data=False),
143 99.996230290506887,
144 atol=TOLERANCE_ABSOLUTE_TESTS,
145 )
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 )
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 )
363 specification_t = colour_rendering_index(
364 SDS_ILLUMINANTS["FL1"], additional_data=True, method="CIE 2024"
365 )
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 )
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)
378 specification_t = colour_rendering_index(
379 SDS_ILLUMINANTS["FL1"], additional_data=True, method="CIE 1995"
380 )
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 )
388 specification_t = colour_rendering_index(
389 SDS_ILLUMINANTS["FL1"], additional_data=True
390 )
392 np.testing.assert_allclose(
393 specification_r.Q_a, specification_t.Q_a, atol=TOLERANCE_ABSOLUTE_TESTS
394 )
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 )
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 )
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)
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"}
433 result = tcs_colorimetry_data(
434 sd_test, sd_test, tcs_dict_partial, cmfs, method="CIE 1995"
435 )
436 assert len(result) == 13