Coverage for colorimetry/tests/test_dominant.py: 100%

1"""Define the unit tests for the :mod:`colour.colorimetry.dominant` module."""

2

3 from __future__ import annotations

4

5 from itertools import product

6

7 import numpy as np

8

9 from colour.colorimetry import (

10 CCS_ILLUMINANTS,

11 MSDS_CMFS,

12 colorimetric_purity,

13 complementary_wavelength,

14 dominant_wavelength,

15 excitation_purity,

16)

17 from colour.colorimetry.dominant import closest_spectral_locus_wavelength

18 from colour.constants import TOLERANCE_ABSOLUTE_TESTS

19 from colour.models import XYZ_to_xy

20 from colour.utilities import ignore_numpy_errors, is_scipy_installed

21

22 __author__ = "Colour Developers"

23 __copyright__ = "Copyright 2013 Colour Developers"

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

25 __maintainer__ = "Colour Developers"

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

27 __status__ = "Production"

28

29 __all__ = [

30 "TestClosestSpectralLocusWavelength",

31 "TestDominantWavelength",

32 "TestComplementaryWavelength",

33 "TestExcitationPurity",

34 "TestColorimetricPurity",

35]

36

37

38 class TestClosestSpectralLocusWavelength:

39 """

40 Define :func:`colour.colorimetry.dominant.\

41 closest_spectral_locus_wavelength` definition unit tests methods.

42 """

43

44 def setup_method(self) -> None:

45 """Initialise the common tests attributes."""

46

47 self._xy_s = XYZ_to_xy(MSDS_CMFS["CIE 1931 2 Degree Standard Observer"].values)

48

49 self._xy_D65 = CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"]["D65"]

50

51 def test_closest_spectral_locus_wavelength(self) -> None:

52 """

53 Test :func:`colour.colorimetry.dominant.\

54 closest_spectral_locus_wavelength` definition.

55 """

56

57 if not is_scipy_installed(): # pragma: no cover

58 return

59

60 xy = np.array([0.54369557, 0.32107944])

61 xy_n = self._xy_D65

62 i_wl, xy_wl = closest_spectral_locus_wavelength(xy, xy_n, self._xy_s)

63

64 assert i_wl == np.array(256)

65 np.testing.assert_allclose(

66 xy_wl,

67 np.array([0.68354746, 0.31628409]),

68 atol=TOLERANCE_ABSOLUTE_TESTS,

69 )

70

71 xy = np.array([0.37605506, 0.24452225])

72 i_wl, xy_wl = closest_spectral_locus_wavelength(xy, xy_n, self._xy_s)

73

74 assert i_wl == np.array(248)

75 np.testing.assert_allclose(

76 xy_wl,

77 np.array([0.45723147, 0.13628148]),

78 atol=TOLERANCE_ABSOLUTE_TESTS,

79 )

80

81 def test_n_dimensional_closest_spectral_locus_wavelength(self) -> None:

82 """

83 Test :func:`colour.colorimetry.dominant.\

84 closest_spectral_locus_wavelength` definition n-dimensional arrays support.

85 """

86

87 if not is_scipy_installed(): # pragma: no cover

88 return

89

90 xy = np.array([0.54369557, 0.32107944])

91 xy_n = self._xy_D65

92 i_wl, xy_wl = closest_spectral_locus_wavelength(xy, xy_n, self._xy_s)

93 i_wl_r, xy_wl_r = np.array(256), np.array([0.68354746, 0.31628409])

94 np.testing.assert_allclose(i_wl, i_wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

95 np.testing.assert_allclose(xy_wl, xy_wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

96

97 xy = np.tile(xy, (6, 1))

98 xy_n = np.tile(xy_n, (6, 1))

99 i_wl, xy_wl = closest_spectral_locus_wavelength(xy, xy_n, self._xy_s)

100 i_wl_r = np.tile(i_wl_r, 6)

101 xy_wl_r = np.tile(xy_wl_r, (6, 1))

102 np.testing.assert_allclose(i_wl, i_wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

103 np.testing.assert_allclose(xy_wl, xy_wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

104

105 xy = np.reshape(xy, (2, 3, 2))

106 xy_n = np.reshape(xy_n, (2, 3, 2))

107 i_wl, xy_wl = closest_spectral_locus_wavelength(xy, xy_n, self._xy_s)

108 i_wl_r = np.reshape(i_wl_r, (2, 3))

109 xy_wl_r = np.reshape(xy_wl_r, (2, 3, 2))

110 np.testing.assert_allclose(i_wl, i_wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

111 np.testing.assert_allclose(xy_wl, xy_wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

112

113 @ignore_numpy_errors

114 def test_nan_closest_spectral_locus_wavelength(self) -> None:

115 """

116 Test :func:`colour.colorimetry.dominant.\

117 closest_spectral_locus_wavelength` definition nan support.

118 """

119

120 if not is_scipy_installed(): # pragma: no cover

121 return

122

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

124 cases = np.array(list(set(product(cases, repeat=2))))

125 for case in cases:

126 closest_spectral_locus_wavelength(case, case, self._xy_s)

127

128

129 class TestDominantWavelength:

130 """

131 Define :func:`colour.colorimetry.dominant.dominant_wavelength` definition

132 unit tests methods.

133 """

134

135 def setup_method(self) -> None:

136 """Initialise the common tests attributes."""

137

138 self._xy_D65 = CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"]["D65"]

139

140 def test_dominant_wavelength(self) -> None:

141 """

142 Test :func:`colour.colorimetry.dominant.dominant_wavelength`

143 definition.

144 """

145

146 if not is_scipy_installed(): # pragma: no cover

147 return

148

149 xy = np.array([0.54369557, 0.32107944])

150 xy_n = self._xy_D65

151 wl, xy_wl, xy_cwl = dominant_wavelength(xy, xy_n)

152

153 assert wl == np.array(616.0)

154 np.testing.assert_allclose(

155 xy_wl,

156 np.array([0.68354746, 0.31628409]),

157 atol=TOLERANCE_ABSOLUTE_TESTS,

158 )

159 np.testing.assert_allclose(

160 xy_cwl,

161 np.array([0.68354746, 0.31628409]),

162 atol=TOLERANCE_ABSOLUTE_TESTS,

163 )

164

165 xy = np.array([0.37605506, 0.24452225])

166 i_wl, xy_wl, xy_cwl = dominant_wavelength(xy, xy_n)

167

168 assert i_wl == np.array(-509.0)

169 np.testing.assert_allclose(

170 xy_wl,

171 np.array([0.45723147, 0.13628148]),

172 atol=TOLERANCE_ABSOLUTE_TESTS,

173 )

174 np.testing.assert_allclose(

175 xy_cwl,

176 np.array([0.01040962, 0.73207453]),

177 atol=TOLERANCE_ABSOLUTE_TESTS,

178 )

179

180 def test_n_dimensional_dominant_wavelength(self) -> None:

181 """

182 Test :func:`colour.colorimetry.dominant.dominant_wavelength`

183 definition n-dimensional arrays support.

184 """

185

186 if not is_scipy_installed(): # pragma: no cover

187 return

188

189 xy = np.array([0.54369557, 0.32107944])

190 xy_n = self._xy_D65

191 wl, xy_wl, xy_cwl = dominant_wavelength(xy, xy_n)

192 wl_r, xy_wl_r, xy_cwl_r = (

193 np.array(616.0),

194 np.array([0.68354746, 0.31628409]),

195 np.array([0.68354746, 0.31628409]),

196 )

197 np.testing.assert_allclose(wl, wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

198 np.testing.assert_allclose(xy_wl, xy_wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

199 np.testing.assert_allclose(xy_cwl, xy_cwl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

200

201 xy = np.tile(xy, (6, 1))

202 xy_n = np.tile(xy_n, (6, 1))

203 wl, xy_wl, xy_cwl = dominant_wavelength(xy, xy_n)

204 wl_r = np.tile(wl_r, 6)

205 xy_wl_r = np.tile(xy_wl_r, (6, 1))

206 xy_cwl_r = np.tile(xy_cwl_r, (6, 1))

207 np.testing.assert_allclose(wl, wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

208 np.testing.assert_allclose(xy_wl, xy_wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

209 np.testing.assert_allclose(xy_cwl, xy_cwl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

210

211 xy = np.reshape(xy, (2, 3, 2))

212 xy_n = np.reshape(xy_n, (2, 3, 2))

213 wl, xy_wl, xy_cwl = dominant_wavelength(xy, xy_n)

214 wl_r = np.reshape(wl_r, (2, 3))

215 xy_wl_r = np.reshape(xy_wl_r, (2, 3, 2))

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

217 np.testing.assert_allclose(wl, wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

218 np.testing.assert_allclose(xy_wl, xy_wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

219 np.testing.assert_allclose(xy_cwl, xy_cwl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

220

221 @ignore_numpy_errors

222 def test_nan_dominant_wavelength(self) -> None:

223 """

224 Test :func:`colour.colorimetry.dominant.dominant_wavelength`

225 definition nan support.

226 """

227

228 if not is_scipy_installed(): # pragma: no cover

229 return

230

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

232 cases = np.array(list(set(product(cases, repeat=2))))

233 for case in cases:

234 dominant_wavelength(case, case)

235

236

237 class TestComplementaryWavelength:

238 """

239 Define :func:`colour.colorimetry.dominant.complementary_wavelength`

240 definition unit tests methods.

241 """

242

243 def setup_method(self) -> None:

244 """Initialise the common tests attributes."""

245

246 self._xy_D65 = CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"]["D65"]

247

248 def test_complementary_wavelength(self) -> None:

249 """

250 Test :func:`colour.colorimetry.dominant.complementary_wavelength`

251 definition.

252 """

253

254 if not is_scipy_installed(): # pragma: no cover

255 return

256

257 xy = np.array([0.54369557, 0.32107944])

258 xy_n = self._xy_D65

259 wl, xy_wl, xy_cwl = complementary_wavelength(xy, xy_n)

260

261 assert wl == np.array(492.0)

262 np.testing.assert_allclose(

263 xy_wl,

264 np.array([0.03647950, 0.33847127]),

265 atol=TOLERANCE_ABSOLUTE_TESTS,

266 )

267 np.testing.assert_allclose(

268 xy_cwl,

269 np.array([0.03647950, 0.33847127]),

270 atol=TOLERANCE_ABSOLUTE_TESTS,

271 )

272

273 xy = np.array([0.37605506, 0.24452225])

274 i_wl, xy_wl, xy_cwl = complementary_wavelength(xy, xy_n)

275

276 assert i_wl == np.array(509.0)

277 np.testing.assert_allclose(

278 xy_wl,

279 np.array([0.01040962, 0.73207453]),

280 atol=TOLERANCE_ABSOLUTE_TESTS,

281 )

282 np.testing.assert_allclose(

283 xy_cwl,

284 np.array([0.01040962, 0.73207453]),

285 atol=TOLERANCE_ABSOLUTE_TESTS,

286 )

287

288 def test_n_dimensional_complementary_wavelength(self) -> None:

289 """

290 Test :func:`colour.colorimetry.dominant.complementary_wavelength`

291 definition n-dimensional arrays support.

292 """

293

294 if not is_scipy_installed(): # pragma: no cover

295 return

296

297 xy = np.array([0.54369557, 0.32107944])

298 xy_n = self._xy_D65

299 wl, xy_wl, xy_cwl = complementary_wavelength(xy, xy_n)

300 wl_r, xy_wl_r, xy_cwl_r = (

301 np.array(492.0),

302 np.array([0.03647950, 0.33847127]),

303 np.array([0.03647950, 0.33847127]),

304 )

305 np.testing.assert_allclose(wl, wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

306 np.testing.assert_allclose(xy_wl, xy_wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

307 np.testing.assert_allclose(xy_cwl, xy_cwl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

308

309 xy = np.tile(xy, (6, 1))

310 xy_n = np.tile(xy_n, (6, 1))

311 wl, xy_wl, xy_cwl = complementary_wavelength(xy, xy_n)

312 wl_r = np.tile(wl_r, 6)

313 xy_wl_r = np.tile(xy_wl_r, (6, 1))

314 xy_cwl_r = np.tile(xy_cwl_r, (6, 1))

315 np.testing.assert_allclose(wl, wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

316 np.testing.assert_allclose(xy_wl, xy_wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

317 np.testing.assert_allclose(xy_cwl, xy_cwl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

318

319 xy = np.reshape(xy, (2, 3, 2))

320 xy_n = np.reshape(xy_n, (2, 3, 2))

321 wl, xy_wl, xy_cwl = complementary_wavelength(xy, xy_n)

322 wl_r = np.reshape(wl_r, (2, 3))

323 xy_wl_r = np.reshape(xy_wl_r, (2, 3, 2))

324 xy_cwl_r = np.reshape(xy_cwl_r, (2, 3, 2))

325 np.testing.assert_allclose(wl, wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

326 np.testing.assert_allclose(xy_wl, xy_wl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

327 np.testing.assert_allclose(xy_cwl, xy_cwl_r, atol=TOLERANCE_ABSOLUTE_TESTS)

328

329 @ignore_numpy_errors

330 def test_nan_complementary_wavelength(self) -> None:

331 """

332 Test :func:`colour.colorimetry.dominant.complementary_wavelength`

333 definition nan support.

334 """

335

336 if not is_scipy_installed(): # pragma: no cover

337 return

338

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

340 cases = np.array(list(set(product(cases, repeat=2))))

341 for case in cases:

342 complementary_wavelength(case, case)

343

344

345 class TestExcitationPurity:

346 """

347 Define :func:`colour.colorimetry.dominant.excitation_purity` definition

348 unit tests methods.

349 """

350

351 def setup_method(self) -> None:

352 """Initialise the common tests attributes."""

353

354 self._xy_D65 = CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"]["D65"]

355

356 def test_excitation_purity(self) -> None:

357 """Test :func:`colour.colorimetry.dominant.excitation_purity` definition."""

358

359 if not is_scipy_installed(): # pragma: no cover

360 return

361

362 xy = np.array([0.54369557, 0.32107944])

363 xy_n = self._xy_D65

364

365 np.testing.assert_allclose(

366 excitation_purity(xy, xy_n),

367 0.622885671878446,

368 atol=TOLERANCE_ABSOLUTE_TESTS,

369 )

370

371 xy = np.array([0.37605506, 0.24452225])

372 np.testing.assert_allclose(

373 excitation_purity(xy, xy_n),

374 0.438347859215887,

375 atol=TOLERANCE_ABSOLUTE_TESTS,

376 )

377

378 def test_n_dimensional_excitation_purity(self) -> None:

379 """

380 Test :func:`colour.colorimetry.dominant.excitation_purity` definition

381 n-dimensional arrays support.

382 """

383

384 if not is_scipy_installed(): # pragma: no cover

385 return

386

387 xy = np.array([0.54369557, 0.32107944])

388 xy_n = self._xy_D65

389 P_e = excitation_purity(xy, xy_n)

390

391 xy = np.tile(xy, (6, 1))

392 xy_n = np.tile(xy_n, (6, 1))

393 P_e = np.tile(P_e, 6)

394 np.testing.assert_allclose(

395 excitation_purity(xy, xy_n), P_e, atol=TOLERANCE_ABSOLUTE_TESTS

396 )

397

398 xy = np.reshape(xy, (2, 3, 2))

399 xy_n = np.reshape(xy_n, (2, 3, 2))

400 P_e = np.reshape(P_e, (2, 3))

401 np.testing.assert_allclose(

402 excitation_purity(xy, xy_n), P_e, atol=TOLERANCE_ABSOLUTE_TESTS

403 )

404

405 @ignore_numpy_errors

406 def test_nan_excitation_purity(self) -> None:

407 """

408 Test :func:`colour.colorimetry.dominant.excitation_purity` definition

409 nan support.

410 """

411

412 if not is_scipy_installed(): # pragma: no cover

413 return

414

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

416 cases = np.array(list(set(product(cases, repeat=2))))

417 for case in cases:

418 excitation_purity(case, case)

419

420

421 class TestColorimetricPurity:

422 """

423 Define :func:`colour.colorimetry.dominant.colorimetric_purity` definition

424 unit tests methods.

425 """

426

427 def setup_method(self) -> None:

428 """Initialise the common tests attributes."""

429

430 self._xy_D65 = CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"]["D65"]

431

432 def test_colorimetric_purity(self) -> None:

433 """

434 Test :func:`colour.colorimetry.dominant.colorimetric_purity`

435 definition.

436 """

437

438 if not is_scipy_installed(): # pragma: no cover

439 return

440

441 xy = np.array([0.54369557, 0.32107944])

442 xy_n = self._xy_D65

443

444 np.testing.assert_allclose(

445 colorimetric_purity(xy, xy_n),

446 0.613582813175483,

447 atol=TOLERANCE_ABSOLUTE_TESTS,

448 )

449

450 xy = np.array([0.37605506, 0.24452225])

451 np.testing.assert_allclose(

452 colorimetric_purity(xy, xy_n),

453 0.244307811178847,

454 atol=TOLERANCE_ABSOLUTE_TESTS,

455 )

456

457 def test_n_dimensional_colorimetric_purity(self) -> None:

458 """

459 Test :func:`colour.colorimetry.dominant.colorimetric_purity`

460 definition n-dimensional arrays support.

461 """

462

463 if not is_scipy_installed(): # pragma: no cover

464 return

465

466 xy = np.array([0.54369557, 0.32107944])

467 xy_n = self._xy_D65

468 P_e = colorimetric_purity(xy, xy_n)

469

470 xy = np.tile(xy, (6, 1))

471 xy_n = np.tile(xy_n, (6, 1))

472 P_e = np.tile(P_e, 6)

473 np.testing.assert_allclose(

474 colorimetric_purity(xy, xy_n), P_e, atol=TOLERANCE_ABSOLUTE_TESTS

475 )

476

477 xy = np.reshape(xy, (2, 3, 2))

478 xy_n = np.reshape(xy_n, (2, 3, 2))

479 P_e = np.reshape(P_e, (2, 3))

480 np.testing.assert_allclose(

481 colorimetric_purity(xy, xy_n), P_e, atol=TOLERANCE_ABSOLUTE_TESTS

482 )

483

484 @ignore_numpy_errors

485 def test_nan_colorimetric_purity(self) -> None:

486 """

487 Test :func:`colour.colorimetry.dominant.colorimetric_purity`

488 definition nan support.

489 """

490

491 if not is_scipy_installed(): # pragma: no cover

492 return

493

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

495 cases = np.array(list(set(product(cases, repeat=2))))

496 for case in cases:

497 colorimetric_purity(case, case)