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

1"""Define the unit tests for the :mod:`colour.recovery.jiang2013` module.""" 

2 

3from __future__ import annotations 

4 

5import platform 

6 

7import numpy as np 

8import pytest 

9 

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 

30 

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" 

37 

38__all__ = [ 

39 "TestPCA_Jiang2013", 

40 "FixtureJiang2013", 

41 "TestRGB_to_sd_camera_sensitivity_Jiang2013", 

42 "TestRGB_to_msds_camera_sensitivities_Jiang2013", 

43] 

44 

45 

46class TestPCA_Jiang2013: 

47 """ 

48 Define :func:`colour.recovery.jiang2013.PCA_Jiang2013` definition unit 

49 tests methods. 

50 """ 

51 

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.""" 

58 

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 ) 

69 

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 ) 

188 

189 

190class FixtureJiang2013: 

191 """A fixture for testing the :mod:`colour.recovery.jiang2013` module.""" 

192 

193 @pytest.fixture(autouse=True) 

194 def setup_fixture_jiang_2013(self) -> None: 

195 """Configure the class instance.""" 

196 

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 ) 

204 

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 ) 

217 

218 

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 """ 

224 

225 def setup_method(self) -> None: 

226 """Initialise the common tests attributes.""" 

227 

228 FixtureJiang2013.__init__(self) 

229 

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 """ 

235 

236 R_w, _G_w, _B_w = tsplit(np.moveaxis(BASIS_FUNCTIONS_DYER2017, 0, 1)) 

237 

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 ) 

283 

284 

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 """ 

290 

291 def setup_method(self) -> None: 

292 """Initialise the common tests attributes.""" 

293 

294 FixtureJiang2013.__init__(self) 

295 

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 """ 

301 

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 )