Coverage for colour/quality/tests/test_cfi2017.py: 100%
55 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"""
2Define the unit tests for the :mod:`colour.quality.CIE2017` module.
4Notes
5-----
6- Reference data was created using the official Excel spreadsheet, published
7 by the CIE at this URL: http://files.cie.co.at/933_TC1-90.zip.
8"""
10from __future__ import annotations
12import numpy as np
13import pytest
15from colour import MSDS_CMFS
16from colour.colorimetry import (
17 SDS_ILLUMINANTS,
18 SpectralDistribution,
19 SpectralShape,
20 reshape_sd,
21 sd_blackbody,
22)
23from colour.quality.cfi2017 import (
24 CCT_reference_illuminant,
25 colour_fidelity_index_CIE2017,
26 load_TCS_CIE2017,
27 sd_reference_illuminant,
28 tcs_colorimetry_data,
29)
30from colour.utilities import ColourUsageWarning
32__author__ = "Colour Developers"
33__copyright__ = "Copyright 2013 Colour Developers"
34__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
35__maintainer__ = "Colour Developers"
36__email__ = "colour-developers@colour-science.org"
37__status__ = "Production"
39__all__ = [
40 "DATA_SD_SAMPLE_5NM",
41 "SD_SAMPLE_5NM",
42 "DATA_SD_SAMPLE_1NM",
43 "SD_SAMPLE_1NM",
44 "TestColourFidelityIndexCIE2017",
45 "TestCctReferenceIlluminant",
46 "TestSdReferenceIlluminant",
47 "TestTcsColorimetryData",
48]
50DATA_SD_SAMPLE_5NM: dict = {
51 380: 0.000,
52 385: 0.000,
53 390: 0.001,
54 395: 0.001,
55 400: 0.002,
56 405: 0.005,
57 410: 0.010,
58 415: 0.021,
59 420: 0.042,
60 425: 0.080,
61 430: 0.140,
62 435: 0.225,
63 440: 0.337,
64 445: 0.479,
65 450: 0.604,
66 455: 0.633,
67 460: 0.551,
68 465: 0.436,
69 470: 0.346,
70 475: 0.282,
71 480: 0.237,
72 485: 0.213,
73 490: 0.210,
74 495: 0.226,
75 500: 0.260,
76 505: 0.311,
77 510: 0.372,
78 515: 0.436,
79 520: 0.499,
80 525: 0.559,
81 530: 0.612,
82 535: 0.658,
83 540: 0.698,
84 545: 0.735,
85 550: 0.771,
86 555: 0.804,
87 560: 0.836,
88 565: 0.868,
89 570: 0.898,
90 575: 0.926,
91 580: 0.952,
92 585: 0.974,
93 590: 0.989,
94 595: 0.998,
95 600: 1.000,
96 605: 0.992,
97 610: 0.978,
98 615: 0.957,
99 620: 0.927,
100 625: 0.888,
101 630: 0.844,
102 635: 0.799,
103 640: 0.750,
104 645: 0.698,
105 650: 0.644,
106 655: 0.591,
107 660: 0.539,
108 665: 0.488,
109 670: 0.440,
110 675: 0.395,
111 680: 0.354,
112 685: 0.316,
113 690: 0.281,
114 695: 0.249,
115 700: 0.220,
116 705: 0.194,
117 710: 0.171,
118 715: 0.150,
119 720: 0.131,
120 725: 0.115,
121 730: 0.100,
122 735: 0.088,
123 740: 0.077,
124 745: 0.067,
125 750: 0.059,
126 755: 0.052,
127 760: 0.046,
128 765: 0.040,
129 770: 0.035,
130 775: 0.031,
131 780: 0.027,
132}
134SD_SAMPLE_5NM: SpectralDistribution = SpectralDistribution(DATA_SD_SAMPLE_5NM)
136DATA_SD_SAMPLE_1NM: dict = {
137 370: 0.000,
138 371: 0.000,
139 372: 0.000,
140 373: 0.000,
141 374: 0.000,
142 375: 0.000,
143 376: 0.000,
144 377: 0.000,
145 378: 0.000,
146 379: 0.000,
147 380: 0.000,
148 381: 0.000,
149 382: 0.000,
150 383: 0.000,
151 384: 0.000,
152 385: 0.000,
153 386: 0.000,
154 387: 0.000,
155 388: 0.000,
156 389: 0.001,
157 390: 0.001,
158 391: 0.001,
159 392: 0.001,
160 393: 0.001,
161 394: 0.001,
162 395: 0.001,
163 396: 0.001,
164 397: 0.002,
165 398: 0.002,
166 399: 0.002,
167 400: 0.002,
168 401: 0.003,
169 402: 0.003,
170 403: 0.004,
171 404: 0.004,
172 405: 0.005,
173 406: 0.006,
174 407: 0.007,
175 408: 0.008,
176 409: 0.009,
177 410: 0.010,
178 411: 0.012,
179 412: 0.014,
180 413: 0.016,
181 414: 0.018,
182 415: 0.021,
183 416: 0.024,
184 417: 0.028,
185 418: 0.032,
186 419: 0.037,
187 420: 0.042,
188 421: 0.048,
189 422: 0.055,
190 423: 0.063,
191 424: 0.071,
192 425: 0.080,
193 426: 0.091,
194 427: 0.102,
195 428: 0.114,
196 429: 0.127,
197 430: 0.140,
198 431: 0.155,
199 432: 0.171,
200 433: 0.188,
201 434: 0.206,
202 435: 0.225,
203 436: 0.245,
204 437: 0.266,
205 438: 0.289,
206 439: 0.312,
207 440: 0.337,
208 441: 0.364,
209 442: 0.391,
210 443: 0.420,
211 444: 0.449,
212 445: 0.479,
213 446: 0.508,
214 447: 0.535,
215 448: 0.561,
216 449: 0.585,
217 450: 0.604,
218 451: 0.620,
219 452: 0.631,
220 453: 0.636,
221 454: 0.637,
222 455: 0.633,
223 456: 0.623,
224 457: 0.610,
225 458: 0.593,
226 459: 0.573,
227 460: 0.551,
228 461: 0.528,
229 462: 0.504,
230 463: 0.481,
231 464: 0.458,
232 465: 0.436,
233 466: 0.415,
234 467: 0.396,
235 468: 0.378,
236 469: 0.361,
237 470: 0.346,
238 471: 0.331,
239 472: 0.318,
240 473: 0.305,
241 474: 0.293,
242 475: 0.282,
243 476: 0.271,
244 477: 0.261,
245 478: 0.252,
246 479: 0.244,
247 480: 0.237,
248 481: 0.230,
249 482: 0.225,
250 483: 0.220,
251 484: 0.216,
252 485: 0.213,
253 486: 0.211,
254 487: 0.209,
255 488: 0.209,
256 489: 0.209,
257 490: 0.210,
258 491: 0.212,
259 492: 0.214,
260 493: 0.217,
261 494: 0.221,
262 495: 0.226,
263 496: 0.231,
264 497: 0.237,
265 498: 0.244,
266 499: 0.252,
267 500: 0.260,
268 501: 0.269,
269 502: 0.279,
270 503: 0.289,
271 504: 0.300,
272 505: 0.311,
273 506: 0.322,
274 507: 0.334,
275 508: 0.347,
276 509: 0.359,
277 510: 0.372,
278 511: 0.384,
279 512: 0.397,
280 513: 0.410,
281 514: 0.423,
282 515: 0.436,
283 516: 0.449,
284 517: 0.462,
285 518: 0.474,
286 519: 0.487,
287 520: 0.499,
288 521: 0.512,
289 522: 0.524,
290 523: 0.536,
291 524: 0.548,
292 525: 0.559,
293 526: 0.570,
294 527: 0.581,
295 528: 0.592,
296 529: 0.602,
297 530: 0.612,
298 531: 0.622,
299 532: 0.632,
300 533: 0.641,
301 534: 0.650,
302 535: 0.658,
303 536: 0.667,
304 537: 0.675,
305 538: 0.683,
306 539: 0.691,
307 540: 0.698,
308 541: 0.706,
309 542: 0.714,
310 543: 0.721,
311 544: 0.728,
312 545: 0.735,
313 546: 0.743,
314 547: 0.750,
315 548: 0.757,
316 549: 0.764,
317 550: 0.771,
318 551: 0.777,
319 552: 0.784,
320 553: 0.791,
321 554: 0.798,
322 555: 0.804,
323 556: 0.811,
324 557: 0.817,
325 558: 0.824,
326 559: 0.830,
327 560: 0.836,
328 561: 0.843,
329 562: 0.849,
330 563: 0.855,
331 564: 0.861,
332 565: 0.868,
333 566: 0.874,
334 567: 0.880,
335 568: 0.886,
336 569: 0.892,
337 570: 0.898,
338 571: 0.904,
339 572: 0.909,
340 573: 0.915,
341 574: 0.921,
342 575: 0.926,
343 576: 0.931,
344 577: 0.937,
345 578: 0.942,
346 579: 0.947,
347 580: 0.952,
348 581: 0.956,
349 582: 0.961,
350 583: 0.965,
351 584: 0.970,
352 585: 0.974,
353 586: 0.977,
354 587: 0.981,
355 588: 0.984,
356 589: 0.986,
357 590: 0.989,
358 591: 0.991,
359 592: 0.993,
360 593: 0.995,
361 594: 0.996,
362 595: 0.998,
363 596: 0.999,
364 597: 1.000,
365 598: 1.000,
366 599: 1.000,
367 600: 1.000,
368 601: 0.999,
369 602: 0.998,
370 603: 0.996,
371 604: 0.995,
372 605: 0.992,
373 606: 0.990,
374 607: 0.988,
375 608: 0.985,
376 609: 0.981,
377 610: 0.978,
378 611: 0.974,
379 612: 0.970,
380 613: 0.966,
381 614: 0.962,
382 615: 0.957,
383 616: 0.952,
384 617: 0.946,
385 618: 0.940,
386 619: 0.934,
387 620: 0.927,
388 621: 0.920,
389 622: 0.912,
390 623: 0.904,
391 624: 0.896,
392 625: 0.888,
393 626: 0.880,
394 627: 0.871,
395 628: 0.862,
396 629: 0.853,
397 630: 0.844,
398 631: 0.835,
399 632: 0.826,
400 633: 0.817,
401 634: 0.808,
402 635: 0.799,
403 636: 0.789,
404 637: 0.780,
405 638: 0.770,
406 639: 0.760,
407 640: 0.750,
408 641: 0.740,
409 642: 0.730,
410 643: 0.719,
411 644: 0.709,
412 645: 0.698,
413 646: 0.687,
414 647: 0.677,
415 648: 0.666,
416 649: 0.655,
417 650: 0.644,
418 651: 0.634,
419 652: 0.623,
420 653: 0.612,
421 654: 0.602,
422 655: 0.591,
423 656: 0.581,
424 657: 0.570,
425 658: 0.560,
426 659: 0.549,
427 660: 0.539,
428 661: 0.529,
429 662: 0.518,
430 663: 0.508,
431 664: 0.498,
432 665: 0.488,
433 666: 0.478,
434 667: 0.468,
435 668: 0.459,
436 669: 0.449,
437 670: 0.440,
438 671: 0.430,
439 672: 0.421,
440 673: 0.412,
441 674: 0.403,
442 675: 0.395,
443 676: 0.386,
444 677: 0.378,
445 678: 0.370,
446 679: 0.361,
447 680: 0.354,
448 681: 0.346,
449 682: 0.338,
450 683: 0.331,
451 684: 0.323,
452 685: 0.316,
453 686: 0.309,
454 687: 0.302,
455 688: 0.295,
456 689: 0.288,
457 690: 0.281,
458 691: 0.275,
459 692: 0.268,
460 693: 0.262,
461 694: 0.255,
462 695: 0.249,
463 696: 0.243,
464 697: 0.237,
465 698: 0.231,
466 699: 0.225,
467 700: 0.220,
468 701: 0.214,
469 702: 0.209,
470 703: 0.204,
471 704: 0.199,
472 705: 0.194,
473 706: 0.189,
474 707: 0.184,
475 708: 0.180,
476 709: 0.175,
477 710: 0.171,
478 711: 0.166,
479 712: 0.162,
480 713: 0.158,
481 714: 0.154,
482 715: 0.150,
483 716: 0.146,
484 717: 0.142,
485 718: 0.138,
486 719: 0.135,
487 720: 0.131,
488 721: 0.128,
489 722: 0.124,
490 723: 0.121,
491 724: 0.118,
492 725: 0.115,
493 726: 0.111,
494 727: 0.108,
495 728: 0.106,
496 729: 0.103,
497 730: 0.100,
498 731: 0.098,
499 732: 0.095,
500 733: 0.092,
501 734: 0.090,
502 735: 0.088,
503 736: 0.085,
504 737: 0.083,
505 738: 0.081,
506 739: 0.079,
507 740: 0.077,
508 741: 0.075,
509 742: 0.073,
510 743: 0.071,
511 744: 0.069,
512 745: 0.067,
513 746: 0.066,
514 747: 0.064,
515 748: 0.062,
516 749: 0.061,
517 750: 0.059,
518 751: 0.058,
519 752: 0.056,
520 753: 0.055,
521 754: 0.053,
522 755: 0.052,
523 756: 0.051,
524 757: 0.049,
525 758: 0.048,
526 759: 0.047,
527 760: 0.046,
528 761: 0.045,
529 762: 0.043,
530 763: 0.042,
531 764: 0.041,
532 765: 0.040,
533 766: 0.039,
534 767: 0.038,
535 768: 0.037,
536 769: 0.036,
537 770: 0.035,
538 771: 0.034,
539 772: 0.033,
540 773: 0.032,
541 774: 0.031,
542 775: 0.031,
543 776: 0.030,
544 777: 0.029,
545 778: 0.028,
546 779: 0.028,
547 780: 0.027,
548}
550SD_SAMPLE_1NM: SpectralDistribution = SpectralDistribution(DATA_SD_SAMPLE_1NM)
553class TestColourFidelityIndexCIE2017:
554 """
555 Define :func:`colour.quality.CIE2017.colour_fidelity_index_CIE2017`
556 definition unit tests methods.
557 """
559 def test_colour_fidelity_index_CIE2017(self) -> None:
560 """
561 Test :func:`colour.quality.CIE2017.colour_fidelity_index_CIE2017`
562 definition.
563 """
565 for sd in [SD_SAMPLE_5NM, SD_SAMPLE_1NM]:
566 specification = colour_fidelity_index_CIE2017(sd, additional_data=True)
567 np.testing.assert_allclose(specification.R_f, 81.6, atol=0.1)
568 np.testing.assert_allclose(
569 specification.R_s,
570 [
571 89.5,
572 80.5,
573 81.5,
574 79.4,
575 65.9,
576 79.4,
577 73.2,
578 68.5,
579 95.9,
580 76.3,
581 71.9,
582 71.8,
583 83.3,
584 93.0,
585 89.2,
586 72.9,
587 75.1,
588 85.8,
589 75.1,
590 63.4,
591 69.4,
592 71.4,
593 89.7,
594 76.8,
595 67.6,
596 75.5,
597 92.7,
598 87.7,
599 81.1,
600 95.0,
601 83.3,
602 74.4,
603 90.4,
604 80.4,
605 89.0,
606 86.9,
607 85.0,
608 95.7,
609 98.5,
610 96.3,
611 98.7,
612 88.4,
613 85.2,
614 99.6,
615 90.4,
616 88.6,
617 94.3,
618 85.3,
619 86.4,
620 90.0,
621 89.3,
622 88.0,
623 83.6,
624 89.6,
625 86.7,
626 81.4,
627 80.2,
628 80.6,
629 88.5,
630 89.7,
631 84.2,
632 84.2,
633 79.4,
634 71.3,
635 72.8,
636 65.8,
637 64.1,
638 71.7,
639 77.4,
640 68.0,
641 63.2,
642 87.1,
643 62.4,
644 92.7,
645 67.3,
646 67.6,
647 80.0,
648 70.4,
649 89.0,
650 87.0,
651 81.5,
652 94.2,
653 94.3,
654 89.4,
655 79.3,
656 76.6,
657 83.7,
658 87.7,
659 76.7,
660 88.6,
661 76.2,
662 68.5,
663 80.1,
664 65.3,
665 74.9,
666 83.9,
667 88.6,
668 84.2,
669 77.4,
670 ],
671 atol=0.1,
672 )
674 specification = colour_fidelity_index_CIE2017(
675 SDS_ILLUMINANTS["FL1"], additional_data=True
676 )
677 np.testing.assert_allclose(specification.R_f, 80.6, atol=0.1)
678 np.testing.assert_allclose(
679 specification.R_s,
680 [
681 85.1,
682 68.9,
683 73.9,
684 79.7,
685 51.6,
686 77.8,
687 52.1,
688 47.8,
689 95.3,
690 68.9,
691 67.3,
692 63.6,
693 71.3,
694 91.1,
695 79.0,
696 63.2,
697 72.8,
698 78.4,
699 75.2,
700 60.4,
701 68.0,
702 67.3,
703 88.6,
704 78.4,
705 68.7,
706 75.7,
707 91.0,
708 91.5,
709 78.3,
710 83.0,
711 82.3,
712 78.7,
713 85.8,
714 85.6,
715 92.3,
716 94.6,
717 88.3,
718 87.8,
719 97.4,
720 94.4,
721 95.4,
722 93.3,
723 90.5,
724 99.5,
725 88.9,
726 87.6,
727 94.3,
728 77.7,
729 88.0,
730 89.6,
731 91.0,
732 87.3,
733 81.3,
734 83.8,
735 85.2,
736 78.1,
737 78.2,
738 79.5,
739 86.9,
740 94.4,
741 87.4,
742 93.7,
743 88.6,
744 77.9,
745 74.5,
746 78.2,
747 77.2,
748 79.7,
749 86.3,
750 76.3,
751 81.6,
752 91.0,
753 73.3,
754 98.1,
755 81.9,
756 77.4,
757 86.9,
758 79.4,
759 90.2,
760 91.1,
761 80.6,
762 96.6,
763 95.1,
764 89.3,
765 84.2,
766 72.5,
767 78.6,
768 75.5,
769 74.4,
770 75.3,
771 91.4,
772 58.2,
773 74.6,
774 52.6,
775 67.0,
776 76.2,
777 88.9,
778 75.2,
779 55.5,
780 ],
781 atol=0.1,
782 )
784 specification = colour_fidelity_index_CIE2017(
785 SDS_ILLUMINANTS["FL2"], additional_data=True
786 )
787 np.testing.assert_allclose(specification.R_f, 70.1, atol=0.1)
788 np.testing.assert_allclose(
789 specification.R_s,
790 [
791 78.9,
792 59.0,
793 66.9,
794 65.7,
795 35.8,
796 66.1,
797 40.4,
798 34.7,
799 95.1,
800 53.5,
801 47.4,
802 44.6,
803 64.1,
804 86.6,
805 71.6,
806 48.8,
807 56.1,
808 68.9,
809 56.8,
810 43.9,
811 46.9,
812 46.5,
813 80.0,
814 62.6,
815 48.1,
816 58.4,
817 82.0,
818 84.6,
819 61.5,
820 69.6,
821 67.5,
822 62.3,
823 73.9,
824 73.6,
825 85.9,
826 87.5,
827 79.4,
828 76.0,
829 96.6,
830 92.8,
831 90.5,
832 89.1,
833 83.0,
834 99.4,
835 83.1,
836 80.7,
837 86.8,
838 66.1,
839 79.6,
840 80.7,
841 81.3,
842 76.1,
843 68.7,
844 76.8,
845 77.0,
846 66.1,
847 65.5,
848 67.4,
849 78.8,
850 90.1,
851 77.5,
852 86.9,
853 76.8,
854 59.7,
855 61.2,
856 57.9,
857 56.2,
858 62.0,
859 72.9,
860 57.7,
861 63.7,
862 84.0,
863 52.7,
864 96.2,
865 66.6,
866 56.6,
867 76.2,
868 63.3,
869 81.8,
870 84.5,
871 73.5,
872 93.9,
873 90.9,
874 85.7,
875 80.5,
876 63.5,
877 73.7,
878 69.0,
879 66.1,
880 67.5,
881 92.6,
882 51.3,
883 69.5,
884 40.7,
885 61.5,
886 70.2,
887 80.0,
888 67.0,
889 45.0,
890 ],
891 atol=0.1,
892 )
894 def test_raise_exception_colour_fidelity_index_CFI2017(self) -> None:
895 """
896 Test :func:`colour.quality.CIE2017.colour_fidelity_index_CFI2017`
897 definition raised exception.
898 """
900 sd = reshape_sd(SDS_ILLUMINANTS["FL2"], SpectralShape(400, 700, 5))
901 pytest.warns(ColourUsageWarning, colour_fidelity_index_CIE2017, sd)
903 sd = reshape_sd(SDS_ILLUMINANTS["FL2"], SpectralShape(380, 780, 10))
904 pytest.raises(ValueError, colour_fidelity_index_CIE2017, sd)
907class TestCctReferenceIlluminant:
908 """
909 Define :func:`colour.quality.CIE2017.CCT_reference_illuminant`
910 definition unit tests methods.
911 """
913 def test_CCT_reference_illuminant(self) -> None:
914 """
915 Test :func:`colour.quality.CIE2017.CCT_reference_illuminant`
916 definition.
917 """
919 for sd in [SD_SAMPLE_5NM, SD_SAMPLE_1NM]:
920 CCT, D_uv = CCT_reference_illuminant(sd)
921 np.testing.assert_allclose(CCT, 3287.5, atol=0.5)
922 np.testing.assert_allclose(D_uv, -0.000300000000000, atol=0.0005)
925class TestSdReferenceIlluminant:
926 """
927 Define :func:`colour.quality.CIE2017.sd_reference_illuminant`
928 definition unit tests methods.
929 """
931 def test_sd_reference_illuminant(self) -> None:
932 """
933 Test :func:`colour.quality.CIE2017.sd_reference_illuminant`
934 definition.
935 """
937 for sd, shape in [
938 (SD_SAMPLE_5NM, SD_SAMPLE_5NM.shape),
939 (SD_SAMPLE_1NM, SD_SAMPLE_1NM.shape),
940 ]:
941 CCT, _D_uv = CCT_reference_illuminant(sd)
942 sd_reference = sd_reference_illuminant(CCT, shape)
944 np.testing.assert_allclose(
945 sd_reference.values,
946 sd_blackbody(3288, shape).values,
947 atol=1.75,
948 )
951class TestTcsColorimetryData:
952 """
953 Define :func:`colour.quality.cfi2017.tcs_colorimetry_data`
954 definition unit tests methods.
955 """
957 def test_tcs_colorimetry_data_single_sd(self) -> None:
958 """
959 Test :func:`colour.quality.cfi2017.tcs_colorimetry_data` definition
960 with a single spectral distribution (not a list).
961 """
963 shape = SpectralShape(380, 780, 5)
964 sd = SD_SAMPLE_5NM.copy().align(shape)
965 cmfs = MSDS_CMFS["CIE 1964 10 Degree Standard Observer"].copy().align(shape)
966 test_sds = load_TCS_CIE2017(shape)
968 result = tcs_colorimetry_data(sd, test_sds, cmfs)
969 assert len(result) == 1