Coverage for colour/colorimetry/whiteness.py: 100%

61 statements  

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

1""" 

2Whiteness Index :math:`W` 

3========================= 

4 

5Define *whiteness* index :math:`W` computation methods. 

6 

7- :func:`colour.colorimetry.whiteness_Berger1959`: Compute *whiteness* 

8 index :math:`WI` from the specified sample *CIE XYZ* tristimulus values 

9 using *Berger (1959)* method. 

10- :func:`colour.colorimetry.whiteness_Taube1960`: Compute *whiteness* 

11 index :math:`WI` from the specified sample *CIE XYZ* tristimulus values 

12 using *Taube (1960)* method. 

13- :func:`colour.colorimetry.whiteness_Stensby1968`: Compute *whiteness* 

14 index :math:`WI` from the specified sample *CIE L\\*a\\*b\\** colourspace 

15 array using *Stensby (1968)* method. 

16- :func:`colour.colorimetry.whiteness_ASTME313`: Compute *whiteness* 

17 index :math:`WI` from the specified sample *CIE XYZ* tristimulus values 

18 using *ASTM E313* method. 

19- :func:`colour.colorimetry.whiteness_Ganz1979`: Compute *whiteness* 

20 index :math:`W` and *tint* :math:`T` from the specified sample *CIE xy* 

21 chromaticity coordinates using *Ganz and Griesser (1979)* method. 

22- :func:`colour.colorimetry.whiteness_CIE2004`: Compute *whiteness* 

23 :math:`W` or :math:`W_{10}` and *tint* :math:`T` or :math:`T_{10}` 

24 from the specified sample *CIE xy* chromaticity coordinates using 

25 *CIE 2004* method. 

26- :attr:`colour.WHITENESS_METHODS`: Supported *whiteness* computation 

27 methods. 

28- :func:`colour.whiteness`: Compute *whiteness* :math:`W` using 

29 specified method. 

30 

31References 

32---------- 

33- :cite:`CIETC1-482004k` : CIE TC 1-48. (2004). The evaluation of whiteness. 

34 In CIE 015:2004 Colorimetry, 3rd Edition (p. 24). ISBN:978-3-901906-33-6 

35- :cite:`Wikipedia2004b` : Wikipedia. (2004). Whiteness. Retrieved September 

36 17, 2014, from http://en.wikipedia.org/wiki/Whiteness 

37- :cite:`Wyszecki2000ba` : Wyszecki, Günther, & Stiles, W. S. (2000). Table 

38 I(6.5.3) Whiteness Formulae (Whiteness Measure Denoted by W). In Color 

39 Science: Concepts and Methods, Quantitative Data and Formulae (pp. 

40 837-839). Wiley. ISBN:978-0-471-39918-6 

41- :cite:`X-Rite2012a` : X-Rite, & Pantone. (2012). Color iQC and Color iMatch 

42 Color Calculations Guide. 

43 https://www.xrite.com/-/media/xrite/files/apps_engineering_techdocuments/\ 

44c/09_color_calculations_en.pdf 

45""" 

46 

47from __future__ import annotations 

48 

49import typing 

50 

51if typing.TYPE_CHECKING: 

52 from colour.hints import Any, Literal 

53 

54from colour.hints import ( # noqa: TC001 

55 ArrayLike, 

56 Domain100, 

57 Range100, 

58) 

59from colour.utilities import ( 

60 CanonicalMapping, 

61 as_float, 

62 as_float_array, 

63 filter_kwargs, 

64 from_range_100, 

65 get_domain_range_scale, 

66 to_domain_100, 

67 tsplit, 

68 tstack, 

69 validate_method, 

70) 

71 

72__author__ = "Colour Developers" 

73__copyright__ = "Copyright 2013 Colour Developers" 

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

75__maintainer__ = "Colour Developers" 

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

77__status__ = "Production" 

78 

79__all__ = [ 

80 "whiteness_Berger1959", 

81 "whiteness_Taube1960", 

82 "whiteness_Stensby1968", 

83 "whiteness_ASTME313", 

84 "whiteness_Ganz1979", 

85 "whiteness_CIE2004", 

86 "WHITENESS_METHODS", 

87 "whiteness", 

88] 

89 

90 

91def whiteness_Berger1959(XYZ: Domain100, XYZ_0: Domain100) -> Range100: 

92 """ 

93 Compute the *whiteness* index :math:`WI` of the specified sample *CIE XYZ* 

94 tristimulus values using the *Berger (1959)* method. 

95 

96 Parameters 

97 ---------- 

98 XYZ 

99 *CIE XYZ* tristimulus values of the sample. 

100 XYZ_0 

101 *CIE XYZ* tristimulus values of the reference white. 

102 

103 Returns 

104 ------- 

105 :class:`numpy.ndarray` 

106 *Whiteness* index :math:`WI`. 

107 

108 Notes 

109 ----- 

110 +------------+-----------------------+---------------+ 

111 | **Domain** | **Scale - Reference** | **Scale - 1** | 

112 +============+=======================+===============+ 

113 | ``XYZ`` | 100 | 1 | 

114 +------------+-----------------------+---------------+ 

115 | ``XYZ_0`` | 100 | 1 | 

116 +------------+-----------------------+---------------+ 

117 

118 +------------+-----------------------+---------------+ 

119 | **Range** | **Scale - Reference** | **Scale - 1** | 

120 +============+=======================+===============+ 

121 | ``WI`` | 100 | 1 | 

122 +------------+-----------------------+---------------+ 

123 

124 - *Whiteness* :math:`WI` values larger than 33.33 indicate a bluish 

125 white and values smaller than 33.33 indicate a yellowish white. 

126 

127 References 

128 ---------- 

129 :cite:`X-Rite2012a` 

130 

131 Examples 

132 -------- 

133 >>> import numpy as np 

134 >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000]) 

135 >>> XYZ_0 = np.array([94.80966767, 100.00000000, 107.30513595]) 

136 >>> whiteness_Berger1959(XYZ, XYZ_0) # doctest: +ELLIPSIS 

137 30.3638017... 

138 """ 

139 

140 X, Y, Z = tsplit(to_domain_100(XYZ)) 

141 X_0, _Y_0, Z_0 = tsplit(to_domain_100(XYZ_0)) 

142 

143 WI = 0.333 * Y + 125 * (Z / Z_0) - 125 * (X / X_0) 

144 

145 return as_float(from_range_100(WI)) 

146 

147 

148def whiteness_Taube1960(XYZ: Domain100, XYZ_0: Domain100) -> Range100: 

149 """ 

150 Compute the *whiteness* index :math:`WI` of the specified sample *CIE XYZ* 

151 tristimulus values using the *Taube (1960)* method. 

152 

153 Parameters 

154 ---------- 

155 XYZ 

156 *CIE XYZ* tristimulus values of the sample. 

157 XYZ_0 

158 *CIE XYZ* tristimulus values of the reference white. 

159 

160 Returns 

161 ------- 

162 :class:`numpy.ndarray` 

163 *Whiteness* index :math:`WI`. 

164 

165 Notes 

166 ----- 

167 +------------+-----------------------+---------------+ 

168 | **Domain** | **Scale - Reference** | **Scale - 1** | 

169 +============+=======================+===============+ 

170 | ``XYZ`` | 100 | 1 | 

171 +------------+-----------------------+---------------+ 

172 | ``XYZ_0`` | 100 | 1 | 

173 +------------+-----------------------+---------------+ 

174 

175 +------------+-----------------------+---------------+ 

176 | **Range** | **Scale - Reference** | **Scale - 1** | 

177 +============+=======================+===============+ 

178 | ``WI`` | 100 | 1 | 

179 +------------+-----------------------+---------------+ 

180 

181 - *Whiteness* :math:`WI` values larger than 100 indicate a bluish 

182 white and values smaller than 100 indicate a yellowish white. 

183 

184 References 

185 ---------- 

186 :cite:`X-Rite2012a` 

187 

188 Examples 

189 -------- 

190 >>> import numpy as np 

191 >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000]) 

192 >>> XYZ_0 = np.array([94.80966767, 100.00000000, 107.30513595]) 

193 >>> whiteness_Taube1960(XYZ, XYZ_0) # doctest: +ELLIPSIS 

194 91.4071738... 

195 """ 

196 

197 _X, Y, Z = tsplit(to_domain_100(XYZ)) 

198 _X_0, _Y_0, Z_0 = tsplit(to_domain_100(XYZ_0)) 

199 

200 WI = 400 * (Z / Z_0) - 3 * Y 

201 

202 return as_float(from_range_100(WI)) 

203 

204 

205def whiteness_Stensby1968( 

206 Lab: Domain100, 

207) -> Range100: 

208 """ 

209 Compute the *whiteness* index :math:`WI` of the specified sample 

210 *CIE L\\*a\\*b\\** colourspace array using the *Stensby (1968)* method. 

211 

212 Parameters 

213 ---------- 

214 Lab 

215 *CIE L\\*a\\*b\\** colourspace array of the sample. 

216 

217 Returns 

218 ------- 

219 :class:`numpy.ndarray` 

220 *Whiteness* index :math:`WI`. 

221 

222 Notes 

223 ----- 

224 +------------+-----------------------+-----------------+ 

225 | **Domain** | **Scale - Reference** | **Scale - 1** | 

226 +============+=======================+=================+ 

227 | ``Lab`` | 100 | 1 | 

228 +------------+-----------------------+-----------------+ 

229 

230 +------------+-----------------------+-----------------+ 

231 | **Range** | **Scale - Reference** | **Scale - 1** | 

232 +============+=======================+=================+ 

233 | ``WI`` | 100 | 1 | 

234 +------------+-----------------------+-----------------+ 

235 

236 - *Whiteness* :math:`WI` values larger than 100 indicate a bluish 

237 white and values smaller than 100 indicate a yellowish white. 

238 

239 References 

240 ---------- 

241 :cite:`X-Rite2012a` 

242 

243 Examples 

244 -------- 

245 >>> import numpy as np 

246 >>> Lab = np.array([100.00000000, -2.46875131, -16.72486654]) 

247 >>> whiteness_Stensby1968(Lab) # doctest: +ELLIPSIS 

248 142.7683456... 

249 """ 

250 

251 L, a, b = tsplit(to_domain_100(Lab)) 

252 

253 WI = L - 3 * b + 3 * a 

254 

255 return as_float(from_range_100(WI)) 

256 

257 

258def whiteness_ASTME313(XYZ: Domain100) -> Range100: 

259 """ 

260 Compute the *whiteness* index :math:`WI` of the specified sample *CIE XYZ* 

261 tristimulus values using the *ASTM E313* method. 

262 

263 Parameters 

264 ---------- 

265 XYZ 

266 *CIE XYZ* tristimulus values of the sample. 

267 

268 Returns 

269 ------- 

270 :class:`numpy.ndarray` 

271 *Whiteness* index :math:`WI`. 

272 

273 Notes 

274 ----- 

275 +------------+-----------------------+---------------+ 

276 | **Domain** | **Scale - Reference** | **Scale - 1** | 

277 +============+=======================+===============+ 

278 | ``XYZ`` | 100 | 1 | 

279 +------------+-----------------------+---------------+ 

280 

281 +------------+-----------------------+---------------+ 

282 | **Range** | **Scale - Reference** | **Scale - 1** | 

283 +============+=======================+===============+ 

284 | ``WI`` | 100 | 1 | 

285 +------------+-----------------------+---------------+ 

286 

287 References 

288 ---------- 

289 :cite:`X-Rite2012a` 

290 

291 Examples 

292 -------- 

293 >>> import numpy as np 

294 >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000]) 

295 >>> whiteness_ASTME313(XYZ) # doctest: +ELLIPSIS 

296 55.7400000... 

297 """ 

298 

299 _X, Y, Z = tsplit(to_domain_100(XYZ)) 

300 

301 WI = 3.388 * Z - 3 * Y 

302 

303 return as_float(from_range_100(WI)) 

304 

305 

306def whiteness_Ganz1979(xy: ArrayLike, Y: Domain100) -> Range100: 

307 """ 

308 Compute the *whiteness* index :math:`W` and *tint* :math:`T` of the 

309 specified sample *CIE xy* chromaticity coordinates using the 

310 *Ganz and Griesser (1979)* method. 

311 

312 Parameters 

313 ---------- 

314 xy 

315 Chromaticity coordinates *CIE xy* of the sample. 

316 Y 

317 Tristimulus :math:`Y` value of the sample. 

318 

319 Returns 

320 ------- 

321 :class:`numpy.ndarray` 

322 *Whiteness* :math:`W` and *tint* :math:`T`. 

323 

324 Notes 

325 ----- 

326 +------------+-----------------------+---------------+ 

327 | **Domain** | **Scale - Reference** | **Scale - 1** | 

328 +============+=======================+===============+ 

329 | ``Y`` | 100 | 1 | 

330 +------------+-----------------------+---------------+ 

331 

332 +------------+-----------------------+---------------+ 

333 | **Range** | **Scale - Reference** | **Scale - 1** | 

334 +============+=======================+===============+ 

335 | ``WT`` | 100 | 1 | 

336 +------------+-----------------------+---------------+ 

337 

338 - The formula coefficients are valid for 

339 *CIE Standard Illuminant D Series* *D65* and 

340 *CIE 1964 10 Degree Standard Observer*. 

341 - Positive output *tint* :math:`T` values indicate a greener tint 

342 while negative values indicate a redder tint. 

343 - Whiteness differences of less than 5 Ganz units appear to be 

344 indistinguishable to the human eye. 

345 - Tint differences of less than 0.5 Ganz units appear to be 

346 indistinguishable to the human eye. 

347 

348 References 

349 ---------- 

350 :cite:`X-Rite2012a` 

351 

352 Examples 

353 -------- 

354 >>> import numpy as np 

355 >>> xy = np.array([0.3167, 0.3334]) 

356 >>> whiteness_Ganz1979(xy, 100) # doctest: +ELLIPSIS 

357 array([ 85.6003766..., 0.6789003...]) 

358 """ 

359 

360 x, y = tsplit(xy) 

361 Y = to_domain_100(Y) 

362 

363 W = Y - 1868.322 * x - 3695.690 * y + 1809.441 

364 T = -1001.223 * x + 748.366 * y + 68.261 

365 

366 WT = tstack([W, T]) 

367 

368 return from_range_100(WT) 

369 

370 

371def whiteness_CIE2004( 

372 xy: ArrayLike, 

373 Y: Domain100, 

374 xy_n: ArrayLike, 

375 observer: Literal[ 

376 "CIE 1931 2 Degree Standard Observer", 

377 "CIE 1964 10 Degree Standard Observer", 

378 ] = ("CIE 1931 2 Degree Standard Observer"), 

379) -> Range100: 

380 """ 

381 Compute the *whiteness* :math:`W` or :math:`W_{10}` and *tint* 

382 :math:`T` or :math:`T_{10}` of the specified sample *CIE xy* chromaticity 

383 coordinates using the *CIE 2004* method. 

384 

385 Parameters 

386 ---------- 

387 xy 

388 Chromaticity coordinates *CIE xy* of the sample. 

389 Y 

390 Tristimulus :math:`Y` value of the sample. 

391 xy_n 

392 Chromaticity coordinates *xy_n* of a perfect diffuser. 

393 observer 

394 *CIE Standard Observer* used for computations, *tint* :math:`T` or 

395 :math:`T_{10}` value is dependent on viewing field angular subtense. 

396 

397 Returns 

398 ------- 

399 :class:`numpy.ndarray` 

400 *Whiteness* :math:`W` or :math:`W_{10}` and *tint* :math:`T` or 

401 :math:`T_{10}` of the specified sample. 

402 

403 Notes 

404 ----- 

405 +------------+-----------------------+---------------+ 

406 | **Domain** | **Scale - Reference** | **Scale - 1** | 

407 +============+=======================+===============+ 

408 | ``Y`` | 100 | 1 | 

409 +------------+-----------------------+---------------+ 

410 

411 +------------+-----------------------+---------------+ 

412 | **Range** | **Scale - Reference** | **Scale - 1** | 

413 +============+=======================+===============+ 

414 | ``WT`` | 100 | 1 | 

415 +------------+-----------------------+---------------+ 

416 

417 - This method may be used only for samples whose values of :math:`W` 

418 or :math:`W_{10}` lie within the following limits: greater than 40 

419 and less than 5Y - 280, or 5Y10 - 280. 

420 - This method may be used only for samples whose values of :math:`T` 

421 or :math:`T_{10}` lie within the following limits: greater than -4 

422 and less than +2. 

423 - Output *whiteness* :math:`W` or :math:`W_{10}` values larger than 

424 100 indicate a bluish white while values smaller than 100 indicate 

425 a yellowish white. 

426 - Positive output *tint* :math:`T` or :math:`T_{10}` values indicate 

427 a greener tint while negative values indicate a redder tint. 

428 

429 References 

430 ---------- 

431 :cite:`CIETC1-482004k` 

432 

433 Examples 

434 -------- 

435 >>> import numpy as np 

436 >>> xy = np.array([0.3167, 0.3334]) 

437 >>> xy_n = np.array([0.3139, 0.3311]) 

438 >>> whiteness_CIE2004(xy, 100, xy_n) # doctest: +ELLIPSIS 

439 array([ 93.85..., -1.305...]) 

440 """ 

441 

442 x, y = tsplit(xy) 

443 Y = to_domain_100(Y) 

444 x_n, y_n = tsplit(xy_n) 

445 

446 W = Y + 800 * (x_n - x) + 1700 * (y_n - y) 

447 T = (1000 if "1931" in observer else 900) * (x_n - x) - 650 * (y_n - y) 

448 

449 WT = tstack([W, T]) 

450 

451 return from_range_100(WT) 

452 

453 

454WHITENESS_METHODS: CanonicalMapping = CanonicalMapping( 

455 { 

456 "Berger 1959": whiteness_Berger1959, 

457 "Taube 1960": whiteness_Taube1960, 

458 "Stensby 1968": whiteness_Stensby1968, 

459 "ASTM E313": whiteness_ASTME313, 

460 "Ganz 1979": whiteness_Ganz1979, 

461 "CIE 2004": whiteness_CIE2004, 

462 } 

463) 

464WHITENESS_METHODS.__doc__ = """ 

465Supported *whiteness* computation methods. 

466 

467References 

468---------- 

469:cite:`CIETC1-482004k`, :cite:`X-Rite2012a` 

470 

471Aliases: 

472 

473- 'cie2004': 'CIE 2004' 

474""" 

475WHITENESS_METHODS["cie2004"] = WHITENESS_METHODS["CIE 2004"] 

476 

477 

478def whiteness( 

479 XYZ: Domain100, 

480 XYZ_0: ArrayLike, 

481 method: ( 

482 Literal[ 

483 "ASTM E313", 

484 "CIE 2004", 

485 "Berger 1959", 

486 "Ganz 1979", 

487 "Stensby 1968", 

488 "Taube 1960", 

489 ] 

490 | str 

491 ) = "CIE 2004", 

492 **kwargs: Any, 

493) -> Range100: 

494 """ 

495 Compute the *whiteness* index :math:`W` of the specified sample *CIE XYZ* 

496 tristimulus values using the specified method. 

497 

498 Parameters 

499 ---------- 

500 XYZ 

501 *CIE XYZ* tristimulus values of the sample. 

502 XYZ_0 

503 *CIE XYZ* tristimulus values of the reference white. 

504 method 

505 Computation method. 

506 

507 Other Parameters 

508 ---------------- 

509 observer 

510 {:func:`colour.colorimetry.whiteness_CIE2004`}, 

511 *CIE Standard Observer* used for computations, *tint* :math:`T` or 

512 :math:`T_{10}` value is dependent on viewing field angular subtense. 

513 

514 Returns 

515 ------- 

516 :class:`numpy.ndarray` 

517 *Whiteness* index :math:`W`. 

518 

519 Notes 

520 ----- 

521 +------------+-----------------------+---------------+ 

522 | **Domain** | **Scale - Reference** | **Scale - 1** | 

523 +============+=======================+===============+ 

524 | ``XYZ`` | 100 | 1 | 

525 +------------+-----------------------+---------------+ 

526 | ``XYZ_0`` | 100 | 1 | 

527 +------------+-----------------------+---------------+ 

528 

529 +------------+-----------------------+---------------+ 

530 | **Range** | **Scale - Reference** | **Scale - 1** | 

531 +============+=======================+===============+ 

532 | ``W`` | 100 | 1 | 

533 +------------+-----------------------+---------------+ 

534 

535 References 

536 ---------- 

537 :cite:`CIETC1-482004k`, :cite:`Wyszecki2000ba`, :cite:`X-Rite2012a`, 

538 :cite:`Wikipedia2004b` 

539 

540 Examples 

541 -------- 

542 >>> import numpy as np 

543 >>> from colour.models import xyY_to_XYZ 

544 >>> XYZ = xyY_to_XYZ(np.array([0.3167, 0.3334, 100])) 

545 >>> XYZ_0 = xyY_to_XYZ(np.array([0.3139, 0.3311, 100])) 

546 >>> whiteness(XYZ, XYZ_0) # doctest: +ELLIPSIS 

547 array([ 93.85..., -1.305...]) 

548 >>> XYZ = np.array([95.00000000, 100.00000000, 105.00000000]) 

549 >>> XYZ_0 = np.array([94.80966767, 100.00000000, 107.30513595]) 

550 >>> whiteness(XYZ, XYZ_0, method="Taube 1960") # doctest: +ELLIPSIS 

551 91.4071738... 

552 """ 

553 

554 XYZ = as_float_array(XYZ) 

555 XYZ_0 = as_float_array(XYZ_0) 

556 

557 method = validate_method(method, tuple(WHITENESS_METHODS)) 

558 

559 kwargs.update({"XYZ": XYZ, "XYZ_0": XYZ_0}) 

560 

561 function = WHITENESS_METHODS[method] 

562 

563 if function is whiteness_Stensby1968: 

564 from colour.models import XYZ_to_Lab, XYZ_to_xy # noqa: PLC0415 

565 

566 # XYZ_to_Lab always expects XYZ in [0, 1], convert from reference [0, 100]. 

567 kwargs.update( 

568 { 

569 "Lab": XYZ_to_Lab( 

570 XYZ / 100 if get_domain_range_scale() == "reference" else XYZ, 

571 XYZ_to_xy( 

572 XYZ_0 / 100 

573 if get_domain_range_scale() == "reference" 

574 else XYZ_0 

575 ), 

576 ) 

577 } 

578 ) 

579 elif function in (whiteness_Ganz1979, whiteness_CIE2004): 

580 from colour.models import XYZ_to_xy # noqa: PLC0415 

581 

582 _X_0, Y_0, _Z_0 = tsplit(XYZ_0) 

583 kwargs.update({"xy": XYZ_to_xy(XYZ), "Y": Y_0, "xy_n": XYZ_to_xy(XYZ_0)}) 

584 

585 return function(**filter_kwargs(function, **kwargs))