Coverage for recovery/tests/test_jiang2013.py: 100%
44 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 22:49 +1300
« 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.recovery.jiang2013` module."""
3from __future__ import annotations
5import platform
7import numpy as np
8import pytest
10from colour.characterisation import MSDS_CAMERA_SENSITIVITIES, SDS_COLOURCHECKERS
11from colour.colorimetry import (
12 SDS_ILLUMINANTS,
13 SpectralDistribution,
14 SpectralShape,
15 msds_to_XYZ,
16 reshape_msds,
17 reshape_sd,
18 sds_and_msds_to_msds,
19)
20from colour.constants import TOLERANCE_ABSOLUTE_TESTS
21from colour.hints import cast
22from colour.recovery import (
23 BASIS_FUNCTIONS_DYER2017,
24 SPECTRAL_SHAPE_BASIS_FUNCTIONS_DYER2017,
25 PCA_Jiang2013,
26 RGB_to_msds_camera_sensitivities_Jiang2013,
27 RGB_to_sd_camera_sensitivity_Jiang2013,
28)
29from colour.utilities import tsplit
31__author__ = "Colour Developers"
32__copyright__ = "Copyright 2013 Colour Developers"
33__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
34__maintainer__ = "Colour Developers"
35__email__ = "colour-developers@colour-science.org"
36__status__ = "Production"
38__all__ = [
39 "TestPCA_Jiang2013",
40 "FixtureJiang2013",
41 "TestRGB_to_sd_camera_sensitivity_Jiang2013",
42 "TestRGB_to_msds_camera_sensitivities_Jiang2013",
43]
46class TestPCA_Jiang2013:
47 """
48 Define :func:`colour.recovery.jiang2013.PCA_Jiang2013` definition unit
49 tests methods.
50 """
52 @pytest.mark.skipif(
53 platform.system() in ("Windows", "Microsoft", "Linux"),
54 reason="PCA tests only run on macOS",
55 )
56 def test_PCA_Jiang2013(self) -> None:
57 """Test :func:`colour.recovery.jiang2013.PCA_Jiang2013` definition."""
59 shape = SpectralShape(400, 700, 10)
60 camera_sensitivities = {
61 camera: msds.copy().align(shape)
62 for camera, msds in MSDS_CAMERA_SENSITIVITIES.items()
63 }
64 w, v = PCA_Jiang2013(
65 camera_sensitivities,
66 3,
67 additional_data=True,
68 )
70 np.testing.assert_allclose(
71 np.abs(np.array(w)),
72 np.array(
73 [
74 [
75 [0.00137594, 0.00399416, 0.00074515],
76 [0.00214835, 0.00184422, 0.85753040],
77 [0.02757181, 0.00553587, 0.02033235],
78 [0.02510621, 0.04216468, 0.01860012],
79 [0.02011623, 0.03371162, 0.01474896],
80 [0.01392282, 0.03297985, 0.00645105],
81 [0.00944513, 0.03300938, 0.00649418],
82 [0.02019958, 0.01289400, 0.01138365],
83 [0.02394423, 0.00980934, 0.00348705],
84 [0.04196326, 0.04987050, 0.00462977],
85 [0.04988732, 0.06936603, 0.01299320],
86 [0.06527141, 0.09378614, 0.00320186],
87 [0.09412575, 0.12244081, 0.02936062],
88 [0.10915913, 0.13119983, 0.02403866],
89 [0.12314840, 0.24280936, 0.03433110],
90 [0.11673941, 0.27700737, 0.11678028],
91 [0.12534133, 0.29994127, 0.11683063],
92 [0.14599255, 0.25586532, 0.04332511],
93 [0.25249090, 0.11499750, 0.04112949],
94 [0.35163407, 0.45286818, 0.04259130],
95 [0.35805737, 0.40724252, 0.24276366],
96 [0.36927899, 0.18120838, 0.28042101],
97 [0.35374885, 0.03010008, 0.05772918],
98 [0.35340909, 0.16847527, 0.23388908],
99 [0.32696116, 0.29068981, 0.09224334],
100 [0.29067354, 0.32862702, 0.14708450],
101 [0.08964758, 0.09682656, 0.04541265],
102 [0.01891664, 0.08221113, 0.01157780],
103 [0.00521149, 0.01578907, 0.00133064],
104 [0.00232366, 0.00137751, 0.00139661],
105 [0.00153787, 0.00254398, 0.00042512],
106 ],
107 [
108 [0.00119598, 0.00267792, 0.00026101],
109 [0.00200327, 0.00322983, 0.62788798],
110 [0.01247816, 0.03313976, 0.01072884],
111 [0.03207685, 0.05703294, 0.03730884],
112 [0.04715050, 0.05296451, 0.02043038],
113 [0.05794010, 0.05455737, 0.01279190],
114 [0.10745571, 0.00158911, 0.03200481],
115 [0.14178525, 0.03362764, 0.15020663],
116 [0.16811402, 0.05569833, 0.00844788],
117 [0.18463716, 0.04615404, 0.03103250],
118 [0.21531623, 0.09745078, 0.39693604],
119 [0.25442570, 0.18330481, 0.14940077],
120 [0.28168018, 0.25193267, 0.00347081],
121 [0.29237178, 0.28545428, 0.03254141],
122 [0.29693117, 0.23909467, 0.00779634],
123 [0.28631319, 0.19476441, 0.31698680],
124 [0.27195968, 0.12087420, 0.28305850],
125 [0.25988140, 0.01581316, 0.04130875],
126 [0.24222660, 0.07912972, 0.18481425],
127 [0.23069698, 0.18583667, 0.18113417],
128 [0.20831983, 0.26745561, 0.13793240],
129 [0.19437168, 0.32425009, 0.20908259],
130 [0.18470894, 0.34768079, 0.15013614],
131 [0.18056180, 0.35983221, 0.24060984],
132 [0.17141337, 0.35067306, 0.04478566],
133 [0.14712541, 0.30423172, 0.05583266],
134 [0.02897026, 0.04573993, 0.02137366],
135 [0.00190228, 0.00461591, 0.00240276],
136 [0.00069122, 0.00118817, 0.00011696],
137 [0.00045559, 0.00015286, 0.00075939],
138 [0.00039509, 0.00049719, 0.00104581],
139 ],
140 [
141 [0.03283371, 0.04707162, 0.99591944],
142 [0.05932690, 0.07529740, 0.06152683],
143 [0.11947381, 0.07977219, 0.00156116],
144 [0.18492233, 0.26127374, 0.00717981],
145 [0.22091564, 0.29279976, 0.00487132],
146 [0.25377875, 0.30677709, 0.00614140],
147 [0.29969822, 0.26541777, 0.00429149],
148 [0.30232755, 0.25378622, 0.00354243],
149 [0.30031732, 0.19751184, 0.00199307],
150 [0.28072276, 0.11804285, 0.00591452],
151 [0.26005747, 0.01836333, 0.00698676],
152 [0.23839367, 0.07182421, 0.01904751],
153 [0.21721831, 0.14245410, 0.00452400],
154 [0.19828405, 0.17684950, 0.01371456],
155 [0.19018451, 0.20137781, 0.01184653],
156 [0.18196762, 0.22086321, 0.01434790],
157 [0.17168644, 0.22771873, 0.02205056],
158 [0.16977073, 0.23504018, 0.01730589],
159 [0.16277670, 0.22897797, 0.02229014],
160 [0.15880423, 0.22583675, 0.02123217],
161 [0.14966812, 0.21494312, 0.01417066],
162 [0.13480155, 0.19511162, 0.01901915],
163 [0.12541764, 0.18113238, 0.01413883],
164 [0.12355731, 0.17835150, 0.01809536],
165 [0.11175064, 0.15997651, 0.01436804],
166 [0.09440304, 0.13423453, 0.01316519],
167 [0.01670581, 0.02019670, 0.00202853],
168 [0.00045002, 0.00147362, 0.00007713],
169 [0.00102919, 0.00095904, 0.00008866],
170 [0.00097397, 0.00123434, 0.00011166],
171 [0.00097116, 0.00124835, 0.00014463],
172 ],
173 ]
174 ),
175 atol=TOLERANCE_ABSOLUTE_TESTS,
176 )
177 np.testing.assert_allclose(
178 np.array(v),
179 np.array(
180 [
181 [10.55160659, 0.72837380, 0.00000000],
182 [20.09177982, 1.57662524, 0.00000000],
183 [19.04142816, 2.60426480, 0.00000000],
184 ]
185 ),
186 atol=TOLERANCE_ABSOLUTE_TESTS,
187 )
190class FixtureJiang2013:
191 """A fixture for testing the :mod:`colour.recovery.jiang2013` module."""
193 @pytest.fixture(autouse=True)
194 def setup_fixture_jiang_2013(self) -> None:
195 """Configure the class instance."""
197 self._sensitivities = reshape_msds(
198 MSDS_CAMERA_SENSITIVITIES["Nikon 5100 (NPL)"],
199 SPECTRAL_SHAPE_BASIS_FUNCTIONS_DYER2017,
200 )
201 self._sd_D65 = reshape_sd(
202 SDS_ILLUMINANTS["D65"], SPECTRAL_SHAPE_BASIS_FUNCTIONS_DYER2017
203 )
205 reflectances = list(SDS_COLOURCHECKERS["BabelColor Average"].values())
206 self._reflectances = sds_and_msds_to_msds(reflectances)
207 self._RGB = msds_to_XYZ(
208 cast("SpectralDistribution", self._reflectances.copy()).align(
209 SPECTRAL_SHAPE_BASIS_FUNCTIONS_DYER2017
210 ),
211 method="Integration",
212 cmfs=self._sensitivities,
213 illuminant=self._sd_D65,
214 k=1,
215 shape=SPECTRAL_SHAPE_BASIS_FUNCTIONS_DYER2017,
216 )
219class TestRGB_to_sd_camera_sensitivity_Jiang2013(FixtureJiang2013):
220 """
221 Define :func:`colour.recovery.jiang2013.RGB_to_sd_camera_sensitivity_Jiang2013`
222 definition unit tests methods.
223 """
225 def setup_method(self) -> None:
226 """Initialise the common tests attributes."""
228 FixtureJiang2013.__init__(self)
230 def test_RGB_to_sd_camera_sensitivity_Jiang2013(self) -> None:
231 """
232 Test :func:`colour.recovery.jiang2013.\
233RGB_to_sd_camera_sensitivity_Jiang2013` definition.
234 """
236 R_w, _G_w, _B_w = tsplit(np.moveaxis(BASIS_FUNCTIONS_DYER2017, 0, 1))
238 np.testing.assert_allclose(
239 RGB_to_sd_camera_sensitivity_Jiang2013(
240 self._RGB[..., 0],
241 self._sd_D65,
242 self._reflectances,
243 R_w,
244 SPECTRAL_SHAPE_BASIS_FUNCTIONS_DYER2017,
245 ).values,
246 np.array(
247 [
248 0.00072067,
249 -0.00089699,
250 0.0046872,
251 0.0077695,
252 0.00693355,
253 0.00531349,
254 0.004482,
255 0.00463938,
256 0.00518667,
257 0.00438283,
258 0.00420012,
259 0.00540655,
260 0.00964451,
261 0.01427711,
262 0.00799507,
263 0.00464298,
264 0.00534238,
265 0.01051938,
266 0.05288944,
267 0.09785117,
268 0.09960038,
269 0.08384089,
270 0.06918086,
271 0.05696785,
272 0.04293031,
273 0.03024127,
274 0.02323005,
275 0.01372194,
276 0.00409449,
277 -0.00044223,
278 -0.00061428,
279 ]
280 ),
281 atol=TOLERANCE_ABSOLUTE_TESTS,
282 )
285class TestRGB_to_msds_camera_sensitivities_Jiang2013(FixtureJiang2013):
286 """
287 Define :func:`colour.recovery.jiang2013.\
288RGB_to_msds_camera_sensitivities_Jiang2013` definition unit tests methods.
289 """
291 def setup_method(self) -> None:
292 """Initialise the common tests attributes."""
294 FixtureJiang2013.__init__(self)
296 def test_RGB_to_msds_camera_sensitivities_Jiang2013(self) -> None:
297 """
298 Test :func:`colour.recovery.jiang2013.\
299RGB_to_msds_camera_sensitivities_Jiang2013` definition.
300 """
302 np.testing.assert_allclose(
303 RGB_to_msds_camera_sensitivities_Jiang2013(
304 self._RGB,
305 self._sd_D65,
306 self._reflectances,
307 BASIS_FUNCTIONS_DYER2017,
308 SPECTRAL_SHAPE_BASIS_FUNCTIONS_DYER2017,
309 ).values,
310 np.array(
311 [
312 [7.04378461e-03, 9.21260449e-03, -7.64080878e-03],
313 [-8.76715607e-03, 1.12726694e-02, 6.37434190e-03],
314 [4.58126856e-02, 7.18000418e-02, 4.00001696e-01],
315 [7.59391152e-02, 1.15620933e-01, 7.11521550e-01],
316 [6.77685732e-02, 1.53406449e-01, 8.52668310e-01],
317 [5.19341313e-02, 1.88575472e-01, 9.38957846e-01],
318 [4.38070562e-02, 2.61086603e-01, 9.72130729e-01],
319 [4.53453213e-02, 3.75440392e-01, 9.61450686e-01],
320 [5.06945146e-02, 4.47658155e-01, 8.86481146e-01],
321 [4.28378252e-02, 4.50713447e-01, 7.51770770e-01],
322 [4.10520309e-02, 6.16577286e-01, 5.52730730e-01],
323 [5.28436974e-02, 7.80199548e-01, 3.82269175e-01],
324 [9.42655432e-02, 9.17674257e-01, 2.40354614e-01],
325 [1.39544593e-01, 1.00000000e00, 1.55374812e-01],
326 [7.81438836e-02, 9.27720273e-01, 1.04409358e-01],
327 [4.53805297e-02, 8.56701565e-01, 6.51222854e-02],
328 [5.22164960e-02, 7.52322921e-01, 3.42954473e-02],
329 [1.02816526e-01, 6.25809730e-01, 2.09495104e-02],
330 [5.16941760e-01, 4.92746166e-01, 1.48524616e-02],
331 [9.56397935e-01, 3.43364817e-01, 1.08983186e-02],
332 [9.73494777e-01, 2.08587708e-01, 7.00494396e-03],
333 [8.19461415e-01, 1.11784838e-01, 4.47180002e-03],
334 [6.76174158e-01, 6.59071962e-02, 4.10135388e-03],
335 [5.56804177e-01, 4.46268353e-02, 4.18528982e-03],
336 [4.19601114e-01, 3.33671033e-02, 4.49165886e-03],
337 [2.95578342e-01, 2.39487762e-02, 4.45932739e-03],
338 [2.27050628e-01, 1.87787770e-02, 4.31697313e-03],
339 [1.34118359e-01, 1.06954985e-02, 3.41192651e-03],
340 [4.00195568e-02, 5.55512389e-03, 1.36794925e-03],
341 [-4.32240535e-03, 2.49731193e-03, 3.80303275e-04],
342 [-6.00395414e-03, 1.54678227e-03, 5.40394352e-04],
343 ]
344 ),
345 atol=TOLERANCE_ABSOLUTE_TESTS,
346 )