Coverage for colour/models/tests/test_sucs.py: 100%

169 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-15 19:01 +1300

1"""Define the unit tests for the :mod:`colour.models.sucs` module.""" 

2 

3from __future__ import annotations 

4 

5from itertools import product 

6 

7import numpy as np 

8 

9from colour.constants import TOLERANCE_ABSOLUTE_TESTS 

10from colour.models import ( 

11 XYZ_to_sUCS, 

12 sUCS_chroma, 

13 sUCS_hue_angle, 

14 sUCS_Iab_to_sUCS_ICh, 

15 sUCS_ICh_to_sUCS_Iab, 

16 sUCS_to_XYZ, 

17) 

18from colour.utilities import domain_range_scale, ignore_numpy_errors 

19 

20__author__ = "UltraMo114(Molin Li), Colour Developers" 

21__copyright__ = "Copyright 2013 Colour Developers" 

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

23__maintainer__ = "Colour Developers" 

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

25__status__ = "Production" 

26 

27__all__ = [ 

28 "TestXYZ_to_sUCS", 

29 "TestsUCS_to_XYZ", 

30 "TestsUCSChroma", 

31 "TestsUCSHueAngle", 

32 "TestsUCS_Iab_to_sUCS_ICh", 

33 "TestsUCS_ICh_to_sUCS_Iab", 

34] 

35 

36 

37class TestXYZ_to_sUCS: 

38 """Define :func:`colour.models.sucs.XYZ_to_sUCS` definition unit tests methods.""" 

39 

40 def test_XYZ_to_sUCS(self) -> None: 

41 """Test :func:`colour.models.sucs.XYZ_to_sUCS` definition.""" 

42 

43 np.testing.assert_allclose( 

44 XYZ_to_sUCS(np.array([0.20654008, 0.12197225, 0.05136952])), 

45 np.array([42.62923653, 36.97646831, 14.12301358]), 

46 atol=TOLERANCE_ABSOLUTE_TESTS, 

47 ) 

48 

49 np.testing.assert_allclose( 

50 XYZ_to_sUCS(np.array([0.14222010, 0.23042768, 0.10495772])), 

51 np.array([51.93649255, -18.89245582, 15.76112395]), 

52 atol=TOLERANCE_ABSOLUTE_TESTS, 

53 ) 

54 

55 np.testing.assert_allclose( 

56 XYZ_to_sUCS(np.array([0.07818780, 0.06157201, 0.28099326])), 

57 np.array([29.79456846, -6.83806757, -25.33884097]), 

58 atol=TOLERANCE_ABSOLUTE_TESTS, 

59 ) 

60 

61 def test_n_dimensional_XYZ_to_sUCS(self) -> None: 

62 """ 

63 Test :func:`colour.models.sucs.XYZ_to_sUCS` definition n-dimensional 

64 support. 

65 """ 

66 

67 XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) 

68 Iab = XYZ_to_sUCS(XYZ) 

69 

70 XYZ = np.tile(XYZ, (6, 1)) 

71 Iab = np.tile(Iab, (6, 1)) 

72 np.testing.assert_allclose(XYZ_to_sUCS(XYZ), Iab, atol=TOLERANCE_ABSOLUTE_TESTS) 

73 

74 XYZ = np.reshape(XYZ, (2, 3, 3)) 

75 Iab = np.reshape(Iab, (2, 3, 3)) 

76 np.testing.assert_allclose(XYZ_to_sUCS(XYZ), Iab, atol=TOLERANCE_ABSOLUTE_TESTS) 

77 

78 def test_domain_range_scale_XYZ_to_sUCS(self) -> None: 

79 """ 

80 Test :func:`colour.models.sucs.XYZ_to_sUCS` definition domain and 

81 range scale support. 

82 """ 

83 

84 XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) 

85 Iab = XYZ_to_sUCS(XYZ) 

86 

87 d_r = (("reference", 1, 1), ("1", 1, 0.01), ("100", 100, 1)) 

88 for scale, factor_a, factor_b in d_r: 

89 with domain_range_scale(scale): 

90 np.testing.assert_allclose( 

91 XYZ_to_sUCS(XYZ * factor_a), 

92 Iab * factor_b, 

93 atol=TOLERANCE_ABSOLUTE_TESTS, 

94 ) 

95 

96 @ignore_numpy_errors 

97 def test_nan_XYZ_to_sUCS(self) -> None: 

98 """Test :func:`colour.models.sucs.XYZ_to_sUCS` definition nan support.""" 

99 

100 cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] 

101 cases = np.array(list(set(product(cases, repeat=3)))) 

102 XYZ_to_sUCS(cases) 

103 

104 

105class TestsUCS_to_XYZ: 

106 """ 

107 Define :func:`colour.models.sucs.sUCS_to_XYZ` definition unit tests 

108 methods. 

109 """ 

110 

111 def test_sUCS_to_XYZ(self) -> None: 

112 """Test :func:`colour.models.sucs.sUCS_to_XYZ` definition.""" 

113 

114 np.testing.assert_allclose( 

115 sUCS_to_XYZ(np.array([42.62923653, 36.97646831, 14.12301358])), 

116 np.array([0.20654008, 0.12197225, 0.05136952]), 

117 atol=TOLERANCE_ABSOLUTE_TESTS, 

118 ) 

119 

120 np.testing.assert_allclose( 

121 sUCS_to_XYZ(np.array([51.93649255, -18.89245582, 15.76112395])), 

122 np.array([0.14222010, 0.23042768, 0.10495772]), 

123 atol=TOLERANCE_ABSOLUTE_TESTS, 

124 ) 

125 

126 np.testing.assert_allclose( 

127 sUCS_to_XYZ(np.array([29.79456846, -6.83806757, -25.33884097])), 

128 np.array([0.07818780, 0.06157201, 0.28099326]), 

129 atol=TOLERANCE_ABSOLUTE_TESTS, 

130 ) 

131 

132 def test_n_dimensional_sUCS_to_XYZ(self) -> None: 

133 """ 

134 Test :func:`colour.models.sucs.sUCS_to_XYZ` definition n-dimensional 

135 support. 

136 """ 

137 

138 Iab = np.array([42.62923653, 36.97646831, 14.12301358]) 

139 XYZ = sUCS_to_XYZ(Iab) 

140 

141 Iab = np.tile(Iab, (6, 1)) 

142 XYZ = np.tile(XYZ, (6, 1)) 

143 np.testing.assert_allclose(sUCS_to_XYZ(Iab), XYZ, atol=TOLERANCE_ABSOLUTE_TESTS) 

144 

145 Iab = np.reshape(Iab, (2, 3, 3)) 

146 XYZ = np.reshape(XYZ, (2, 3, 3)) 

147 np.testing.assert_allclose(sUCS_to_XYZ(Iab), XYZ, atol=TOLERANCE_ABSOLUTE_TESTS) 

148 

149 def test_domain_range_scale_sUCS_to_XYZ(self) -> None: 

150 """ 

151 Test :func:`colour.models.sucs.sUCS_to_XYZ` definition domain and 

152 range scale support. 

153 """ 

154 

155 Iab = np.array([42.62923653, 36.97646831, 14.12301358]) 

156 XYZ = sUCS_to_XYZ(Iab) 

157 

158 d_r = (("reference", 1, 1), ("1", 0.01, 1), ("100", 1, 100)) 

159 for scale, factor_a, factor_b in d_r: 

160 with domain_range_scale(scale): 

161 np.testing.assert_allclose( 

162 sUCS_to_XYZ(Iab * factor_a), 

163 XYZ * factor_b, 

164 atol=TOLERANCE_ABSOLUTE_TESTS, 

165 ) 

166 

167 @ignore_numpy_errors 

168 def test_nan_sUCS_to_XYZ(self) -> None: 

169 """Test :func:`colour.models.sucs.sUCS_to_XYZ` definition nan support.""" 

170 

171 cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] 

172 cases = np.array(list(set(product(cases, repeat=3)))) 

173 sUCS_to_XYZ(cases) 

174 

175 

176class TestsUCSChroma: 

177 """ 

178 Define :func:`colour.models.sucs.sUCS_chroma` definition unit tests 

179 methods. 

180 """ 

181 

182 def test_sUCS_hue_angle(self) -> None: 

183 """Test :func:`colour.models.sucs.sUCS_chroma` definition.""" 

184 

185 np.testing.assert_allclose( 

186 sUCS_chroma(np.array([42.62923653, 36.97646831, 14.12301358])), 

187 40.420511061137226, 

188 atol=TOLERANCE_ABSOLUTE_TESTS, 

189 ) 

190 

191 np.testing.assert_allclose( 

192 sUCS_chroma(np.array([51.93649255, -18.89245582, 15.76112395])), 

193 29.437831501432590, 

194 atol=TOLERANCE_ABSOLUTE_TESTS, 

195 ) 

196 

197 np.testing.assert_allclose( 

198 sUCS_chroma(np.array([29.79456846, -6.83806757, -25.33884097])), 

199 30.800979756091614, 

200 atol=TOLERANCE_ABSOLUTE_TESTS, 

201 ) 

202 

203 def test_n_dimensional_sUCS_hue_angle(self) -> None: 

204 """ 

205 Test :func:`colour.models.sucs.sUCS_chroma` definition n-dimensional 

206 support. 

207 """ 

208 

209 Iab = np.array([42.62923653, 36.97646831, 14.12301358]) 

210 C = sUCS_chroma(Iab) 

211 

212 Iab = np.tile(Iab, (6, 1)) 

213 C = np.tile(C, 6) 

214 np.testing.assert_allclose(sUCS_chroma(Iab), C, atol=TOLERANCE_ABSOLUTE_TESTS) 

215 

216 Iab = np.reshape(Iab, (2, 3, 3)) 

217 C = np.reshape(C, (2, 3)) 

218 np.testing.assert_allclose(sUCS_chroma(Iab), C, atol=TOLERANCE_ABSOLUTE_TESTS) 

219 

220 def test_domain_range_scale_sUCS_chroma(self) -> None: 

221 """ 

222 Test :func:`colour.models.sucs.sUCS_chroma` definition domain and 

223 range scale support. 

224 """ 

225 

226 Iab = np.array([42.62923653, 36.97646831, 14.12301358]) 

227 C = sUCS_chroma(Iab) 

228 

229 d_r = (("reference", 1, 1), ("1", 0.01, 0.01), ("100", 1, 1)) 

230 for scale, factor_a, factor_b in d_r: 

231 with domain_range_scale(scale): 

232 np.testing.assert_allclose( 

233 sUCS_chroma(Iab * factor_a), 

234 C * factor_b, 

235 atol=TOLERANCE_ABSOLUTE_TESTS, 

236 ) 

237 

238 @ignore_numpy_errors 

239 def test_nan_sUCS_hue_angle(self) -> None: 

240 """Test :func:`colour.models.sucs.sUCS_chroma` definition nan support.""" 

241 

242 cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] 

243 cases = np.array(list(set(product(cases, repeat=3)))) 

244 sUCS_chroma(cases) 

245 

246 

247class TestsUCSHueAngle: 

248 """ 

249 Define :func:`colour.models.sucs.sUCS_hue_angle` definition unit tests 

250 methods. 

251 """ 

252 

253 def test_sUCS_hue_angle(self) -> None: 

254 """Test :func:`colour.models.sucs.sUCS_hue_angle` definition.""" 

255 

256 np.testing.assert_allclose( 

257 sUCS_hue_angle(np.array([42.62923653, 36.97646831, 14.12301358])), 

258 20.904156072136217, 

259 atol=TOLERANCE_ABSOLUTE_TESTS, 

260 ) 

261 

262 np.testing.assert_allclose( 

263 sUCS_hue_angle(np.array([51.93649255, -18.89245582, 15.76112395])), 

264 140.163281067124470, 

265 atol=TOLERANCE_ABSOLUTE_TESTS, 

266 ) 

267 

268 np.testing.assert_allclose( 

269 sUCS_hue_angle(np.array([29.79456846, -6.83806757, -25.33884097])), 

270 254.897631851863850, 

271 atol=TOLERANCE_ABSOLUTE_TESTS, 

272 ) 

273 

274 def test_n_dimensional_sUCS_hue_angle(self) -> None: 

275 """ 

276 Test :func:`colour.models.sucs.sUCS_hue_angle` definition n-dimensional 

277 support. 

278 """ 

279 

280 Iab = np.array([42.62923653, 36.97646831, 14.12301358]) 

281 hue = sUCS_hue_angle(Iab) 

282 

283 Iab = np.tile(Iab, (6, 1)) 

284 hue = np.tile(hue, 6) 

285 np.testing.assert_allclose( 

286 sUCS_hue_angle(Iab), hue, atol=TOLERANCE_ABSOLUTE_TESTS 

287 ) 

288 

289 Iab = np.reshape(Iab, (2, 3, 3)) 

290 hue = np.reshape(hue, (2, 3)) 

291 np.testing.assert_allclose( 

292 sUCS_hue_angle(Iab), hue, atol=TOLERANCE_ABSOLUTE_TESTS 

293 ) 

294 

295 def test_domain_range_scale_sUCS_hue_angle(self) -> None: 

296 """ 

297 Test :func:`colour.models.sucs.sUCS_hue_angle` definition domain and 

298 range scale support. 

299 """ 

300 

301 Iab = np.array([42.62923653, 36.97646831, 14.12301358]) 

302 hue = sUCS_hue_angle(Iab) 

303 

304 d_r = (("reference", 1, 1), ("1", 1, 1 / 360), ("100", 100, 1 / 3.6)) 

305 for scale, factor_a, factor_b in d_r: 

306 with domain_range_scale(scale): 

307 np.testing.assert_allclose( 

308 sUCS_hue_angle(Iab * factor_a), 

309 hue * factor_b, 

310 atol=TOLERANCE_ABSOLUTE_TESTS, 

311 ) 

312 

313 @ignore_numpy_errors 

314 def test_nan_sUCS_hue_angle(self) -> None: 

315 """Test :func:`colour.models.sucs.sUCS_hue_angle` definition nan support.""" 

316 

317 cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] 

318 cases = np.array(list(set(product(cases, repeat=3)))) 

319 sUCS_hue_angle(cases) 

320 

321 

322class TestsUCS_Iab_to_sUCS_ICh: 

323 """ 

324 Define :func:`colour.models.sucs.sUCS_Iab_to_sUCS_ICh` definition unit tests 

325 methods. 

326 """ 

327 

328 def test_sUCS_Iab_to_sUCS_ICh(self) -> None: 

329 """Test :func:`colour.models.sucs.sUCS_Iab_to_sUCS_ICh` definition.""" 

330 

331 np.testing.assert_allclose( 

332 sUCS_Iab_to_sUCS_ICh(np.array([42.62923653, 36.97646831, 14.12301358])), 

333 np.array([42.62923653, 40.42051106, 20.90415607]), 

334 atol=TOLERANCE_ABSOLUTE_TESTS, 

335 ) 

336 

337 np.testing.assert_allclose( 

338 sUCS_Iab_to_sUCS_ICh(np.array([51.93649255, -18.89245582, 15.76112395])), 

339 np.array([51.93649255, 29.43783150, 140.16328107]), 

340 atol=TOLERANCE_ABSOLUTE_TESTS, 

341 ) 

342 

343 np.testing.assert_allclose( 

344 sUCS_Iab_to_sUCS_ICh(np.array([29.79456846, -6.83806757, -25.33884097])), 

345 np.array([29.79456846, 30.80097976, 254.89763185]), 

346 atol=TOLERANCE_ABSOLUTE_TESTS, 

347 ) 

348 

349 def test_n_dimensional_sUCS_Iab_to_sUCS_ICh(self) -> None: 

350 """ 

351 Test :func:`colour.models.sucs.sUCS_Iab_to_sUCS_ICh` definition 

352 n-dimensional support. 

353 """ 

354 

355 Iab = np.array([42.62923653, 36.97646831, 14.12301358]) 

356 ICh = sUCS_Iab_to_sUCS_ICh(Iab) 

357 

358 Iab = np.tile(Iab, (6, 1)) 

359 ICh = np.tile(ICh, (6, 1)) 

360 np.testing.assert_allclose( 

361 sUCS_Iab_to_sUCS_ICh(Iab), ICh, atol=TOLERANCE_ABSOLUTE_TESTS 

362 ) 

363 

364 Iab = np.reshape(Iab, (2, 3, 3)) 

365 ICh = np.reshape(ICh, (2, 3, 3)) 

366 np.testing.assert_allclose( 

367 sUCS_Iab_to_sUCS_ICh(Iab), ICh, atol=TOLERANCE_ABSOLUTE_TESTS 

368 ) 

369 

370 def test_domain_range_scale_sUCS_Iab_to_sUCS_ICh(self) -> None: 

371 """ 

372 Test :func:`colour.models.sucs.sUCS_Iab_to_sUCS_ICh` definition domain 

373 and range scale support. 

374 """ 

375 

376 Iab = np.array([42.62923653, 36.97646831, 14.12301358]) 

377 ICh = sUCS_Iab_to_sUCS_ICh(Iab) 

378 

379 d_r = ( 

380 ("reference", 1, 1), 

381 ("1", 0.01, np.array([0.01, 0.01, 1 / 360])), 

382 ("100", 1, np.array([1, 1, 100 / 360])), 

383 ) 

384 for scale, factor_a, factor_b in d_r: 

385 with domain_range_scale(scale): 

386 np.testing.assert_allclose( 

387 sUCS_Iab_to_sUCS_ICh(Iab * factor_a), 

388 ICh * factor_b, 

389 atol=TOLERANCE_ABSOLUTE_TESTS, 

390 ) 

391 

392 @ignore_numpy_errors 

393 def test_nan_sUCS_Iab_to_sUCS_ICh(self) -> None: 

394 """ 

395 Test :func:`colour.models.sucs.sUCS_Iab_to_sUCS_ICh` definition nan support. 

396 """ 

397 

398 cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] 

399 cases = np.array(list(set(product(cases, repeat=3)))) 

400 sUCS_Iab_to_sUCS_ICh(cases) 

401 

402 

403class TestsUCS_ICh_to_sUCS_Iab: 

404 """ 

405 Define :func:`colour.models.sucs.sUCS_ICh_to_sUCS_Iab` definition unit tests 

406 methods. 

407 """ 

408 

409 def test_sUCS_ICh_to_sUCS_Iab(self) -> None: 

410 """Test :func:`colour.models.sucs.sUCS_ICh_to_sUCS_Iab` definition.""" 

411 

412 np.testing.assert_allclose( 

413 sUCS_ICh_to_sUCS_Iab(np.array([42.62923653, 40.42051106, 20.90415607])), 

414 np.array([42.62923653, 36.97646831, 14.12301358]), 

415 atol=TOLERANCE_ABSOLUTE_TESTS, 

416 ) 

417 

418 np.testing.assert_allclose( 

419 sUCS_ICh_to_sUCS_Iab(np.array([51.93649255, 29.43783150, 140.16328107])), 

420 np.array([51.93649255, -18.89245582, 15.76112395]), 

421 atol=TOLERANCE_ABSOLUTE_TESTS, 

422 ) 

423 

424 np.testing.assert_allclose( 

425 sUCS_ICh_to_sUCS_Iab(np.array([29.79456846, 30.80097976, 254.89763185])), 

426 np.array([29.79456846, -6.83806757, -25.33884097]), 

427 atol=TOLERANCE_ABSOLUTE_TESTS, 

428 ) 

429 

430 def test_n_dimensional_sUCS_ICh_to_sUCS_Iab(self) -> None: 

431 """ 

432 Test :func:`colour.models.sucs.sUCS_ICh_to_sUCS_Iab` definition 

433 n-dimensional support. 

434 """ 

435 

436 ICh = np.array([42.62923653, 40.42051106, 20.90415607]) 

437 Iab = sUCS_ICh_to_sUCS_Iab(ICh) 

438 

439 ICh = np.tile(ICh, (6, 1)) 

440 Iab = np.tile(Iab, (6, 1)) 

441 np.testing.assert_allclose( 

442 sUCS_ICh_to_sUCS_Iab(ICh), Iab, atol=TOLERANCE_ABSOLUTE_TESTS 

443 ) 

444 

445 ICh = np.reshape(ICh, (2, 3, 3)) 

446 Iab = np.reshape(Iab, (2, 3, 3)) 

447 np.testing.assert_allclose( 

448 sUCS_ICh_to_sUCS_Iab(ICh), Iab, atol=TOLERANCE_ABSOLUTE_TESTS 

449 ) 

450 

451 def test_domain_range_scale_sUCS_ICh_to_sUCS_Iab(self) -> None: 

452 """ 

453 Test :func:`colour.models.sucs.sUCS_ICh_to_sUCS_Iab` definition domain 

454 and range scale support. 

455 """ 

456 

457 ICh = np.array([42.62923653, 40.42051106, 20.90415607]) 

458 Iab = sUCS_ICh_to_sUCS_Iab(ICh) 

459 

460 d_r = ( 

461 ("reference", 1, 1), 

462 ("1", np.array([0.01, 0.01, 1 / 360]), 0.01), 

463 ("100", np.array([1, 1, 100 / 360]), 1), 

464 ) 

465 for scale, factor_a, factor_b in d_r: 

466 with domain_range_scale(scale): 

467 np.testing.assert_allclose( 

468 sUCS_ICh_to_sUCS_Iab(ICh * factor_a), 

469 Iab * factor_b, 

470 atol=TOLERANCE_ABSOLUTE_TESTS, 

471 ) 

472 

473 @ignore_numpy_errors 

474 def test_nan_sUCS_ICh_to_sUCS_Iab(self) -> None: 

475 """ 

476 Test :func:`colour.models.sucs.sUCS_ICh_to_sUCS_Iab` definition nan support. 

477 """ 

478 

479 cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] 

480 cases = np.array(list(set(product(cases, repeat=3)))) 

481 sUCS_ICh_to_sUCS_Iab(cases)