Coverage for colour/characterisation/correction.py: 91%

132 statements  

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

1""" 

2Colour Correction 

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

4 

5Define objects for colour correction, including methods for colour matching 

6between images: 

7 

8- :func:`colour.characterisation.matrix_augmented_Cheung2004`: Perform 

9 polynomial expansion using *Cheung, Westland, Connah and Ripamonti (2004)* 

10 method. 

11- :func:`colour.characterisation.polynomial_expansion_Finlayson2015`: 

12 Perform polynomial expansion using *Finlayson, MacKiewicz and Hurlbert 

13 (2015)* method. 

14- :func:`colour.characterisation.polynomial_expansion_Vandermonde`: Perform 

15 polynomial expansion using *Vandermonde* method. 

16- :attr:`colour.POLYNOMIAL_EXPANSION_METHODS`: Supported polynomial 

17 expansion methods. 

18- :func:`colour.polynomial_expansion`: Perform polynomial expansion of 

19 :math:`a` array. 

20- :func:`colour.characterisation.matrix_colour_correction_Cheung2004`: 

21 Compute colour correction matrix using *Cheung et al. (2004)* method. 

22- :func:`colour.characterisation.matrix_colour_correction_Finlayson2015`: 

23 Compute colour correction matrix using *Finlayson et al. (2015)* method. 

24- :func:`colour.characterisation.matrix_colour_correction_Vandermonde`: 

25 Compute colour correction matrix using *Vandermonde* method. 

26- :attr:`colour.MATRIX_COLOUR_CORRECTION_METHODS`: Supported colour 

27 correction matrix methods. 

28- :func:`colour.matrix_colour_correction`: Compute colour correction matrix 

29 from :math:`M_T` colour array to :math:`M_R` colour array. 

30- :func:`colour.apply_matrix_colour_correction_Cheung2004`: Apply colour 

31 correction matrix computed using *Cheung et al. (2004)* method. 

32- :func:`colour.apply_matrix_colour_correction_Finlayson2015`: Apply colour 

33 correction matrix computed using *Finlayson et al. (2015)* method. 

34- :func:`colour.apply_matrix_colour_correction_Vandermonde`: Apply colour 

35 correction matrix computed using *Vandermonde* method. 

36- :attr:`colour.APPLY_MATRIX_COLOUR_CORRECTION_METHODS`: Supported methods 

37 to apply colour correction matrices. 

38- :func:`colour.apply_matrix_colour_correction`: Apply colour correction 

39 matrix. 

40- :func:`colour.characterisation.colour_correction_Cheung2004`: Perform 

41 colour correction using *Cheung et al. (2004)* method. 

42- :func:`colour.characterisation.colour_correction_Finlayson2015`: Perform 

43 colour correction using *Finlayson et al. (2015)* method. 

44- :func:`colour.characterisation.colour_correction_Vandermonde`: Perform 

45 colour correction using *Vandermonde* method. 

46- :attr:`colour.COLOUR_CORRECTION_METHODS`: Supported colour correction 

47 methods. 

48- :func:`colour.colour_correction`: Perform colour correction of *RGB* 

49 colourspace array using colour correction matrix from :math:`M_T` colour 

50 array to :math:`M_R` colour array. 

51 

52References 

53---------- 

54- :cite:`Cheung2004` : Cheung, V., Westland, S., Connah, D., & Ripamonti, C. 

55 (2004). A comparative study of the characterisation of colour cameras by 

56 means of neural networks and polynomial transforms. Coloration Technology, 

57 120(1), 19-25. doi:10.1111/j.1478-4408.2004.tb00201.x 

58- :cite:`Finlayson2015` : Finlayson, G. D., MacKiewicz, M., & Hurlbert, A. 

59 (2015). Color Correction Using Root-Polynomial Regression. IEEE 

60 Transactions on Image Processing, 24(5), 1460-1470. 

61 doi:10.1109/TIP.2015.2405336 

62- :cite:`Westland2004` : Westland, S., & Ripamonti, C. (2004). Table 8.2. In 

63 Computational Colour Science Using MATLAB (1st ed., p. 137). John Wiley & 

64 Sons, Ltd. doi:10.1002/0470020326 

65- :cite:`Wikipedia2003e` : Wikipedia. (2003). Vandermonde matrix. Retrieved 

66 May 2, 2018, from https://en.wikipedia.org/wiki/Vandermonde_matrix 

67""" 

68 

69from __future__ import annotations 

70 

71import typing 

72 

73import numpy as np 

74 

75from colour.algebra import least_square_mapping_MoorePenrose, spow 

76 

77if typing.TYPE_CHECKING: 

78 from colour.hints import Any, ArrayLike, Literal, NDArrayFloat 

79 

80from colour.utilities import ( 

81 CanonicalMapping, 

82 as_float, 

83 as_float_array, 

84 as_int, 

85 closest, 

86 filter_kwargs, 

87 ones, 

88 tsplit, 

89 tstack, 

90 validate_method, 

91) 

92 

93__author__ = "Colour Developers" 

94__copyright__ = "Copyright 2013 Colour Developers" 

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

96__maintainer__ = "Colour Developers" 

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

98__status__ = "Production" 

99 

100__all__ = [ 

101 "matrix_augmented_Cheung2004", 

102 "polynomial_expansion_Finlayson2015", 

103 "polynomial_expansion_Vandermonde", 

104 "POLYNOMIAL_EXPANSION_METHODS", 

105 "polynomial_expansion", 

106 "matrix_colour_correction_Cheung2004", 

107 "matrix_colour_correction_Finlayson2015", 

108 "matrix_colour_correction_Vandermonde", 

109 "MATRIX_COLOUR_CORRECTION_METHODS", 

110 "matrix_colour_correction", 

111 "apply_matrix_colour_correction_Cheung2004", 

112 "apply_matrix_colour_correction_Finlayson2015", 

113 "apply_matrix_colour_correction_Vandermonde", 

114 "APPLY_MATRIX_COLOUR_CORRECTION_METHODS", 

115 "apply_matrix_colour_correction", 

116 "colour_correction_Cheung2004", 

117 "colour_correction_Finlayson2015", 

118 "colour_correction_Vandermonde", 

119 "COLOUR_CORRECTION_METHODS", 

120 "colour_correction", 

121] 

122 

123 

124def matrix_augmented_Cheung2004( 

125 RGB: ArrayLike, 

126 terms: Literal[3, 4, 5, 7, 8, 10, 11, 14, 16, 17, 19, 20, 22, 35] | int = 3, 

127) -> NDArrayFloat: 

128 """ 

129 Perform polynomial expansion of *RGB* colourspace array using 

130 *Cheung et al. (2004)* method. 

131 

132 Parameters 

133 ---------- 

134 RGB 

135 *RGB* colourspace array to expand using polynomial expansion. 

136 terms 

137 Number of terms of the expanded polynomial. 

138 

139 Returns 

140 ------- 

141 :class:`numpy.ndarray` 

142 Polynomial-expanded *RGB* colourspace array. 

143 

144 Notes 

145 ----- 

146 - This definition combines the augmented matrices specified in 

147 :cite:`Cheung2004` and :cite:`Westland2004`. 

148 

149 References 

150 ---------- 

151 :cite:`Cheung2004`, :cite:`Westland2004` 

152 

153 Examples 

154 -------- 

155 >>> RGB = np.array([0.17224810, 0.09170660, 0.06416938]) 

156 >>> matrix_augmented_Cheung2004(RGB, terms=5) # doctest: +ELLIPSIS 

157 array([ 0.1722481..., 0.0917066..., 0.0641693..., 0.0010136..., 1...]) 

158 """ 

159 

160 RGB = as_float_array(RGB) 

161 

162 R, G, B = tsplit(RGB) 

163 tail = ones(R.shape) 

164 

165 existing_terms = np.array([3, 4, 5, 7, 8, 10, 11, 14, 16, 17, 19, 20, 22, 35]) 

166 closest_terms = as_int(closest(existing_terms, terms)) 

167 if closest_terms != terms: 

168 error = ( 

169 f'"Cheung et al. (2004)" method does not define an augmented ' 

170 f"matrix with {terms} terms, closest augmented matrix has " 

171 f"{closest_terms} terms!" 

172 ) 

173 

174 raise ValueError(error) 

175 

176 if terms == 3: 

177 expansion = RGB 

178 elif terms == 4: 

179 expansion = tstack([R, G, B, tail]) 

180 elif terms == 5: 

181 expansion = tstack( 

182 [ 

183 R, 

184 G, 

185 B, 

186 R * G * B, 

187 tail, 

188 ] 

189 ) 

190 elif terms == 7: 

191 expansion = tstack( 

192 [ 

193 R, 

194 G, 

195 B, 

196 R * G, 

197 R * B, 

198 G * B, 

199 tail, 

200 ] 

201 ) 

202 elif terms == 8: 

203 expansion = tstack( 

204 [ 

205 R, 

206 G, 

207 B, 

208 R * G, 

209 R * B, 

210 G * B, 

211 R * G * B, 

212 tail, 

213 ] 

214 ) 

215 elif terms == 10: 

216 expansion = tstack( 

217 [ 

218 R, 

219 G, 

220 B, 

221 R * G, 

222 R * B, 

223 G * B, 

224 R**2, 

225 G**2, 

226 B**2, 

227 tail, 

228 ] 

229 ) 

230 elif terms == 11: 

231 expansion = tstack( 

232 [ 

233 R, 

234 G, 

235 B, 

236 R * G, 

237 R * B, 

238 G * B, 

239 R**2, 

240 G**2, 

241 B**2, 

242 R * G * B, 

243 tail, 

244 ] 

245 ) 

246 elif terms == 14: 

247 expansion = tstack( 

248 [ 

249 R, 

250 G, 

251 B, 

252 R * G, 

253 R * B, 

254 G * B, 

255 R**2, 

256 G**2, 

257 B**2, 

258 R * G * B, 

259 R**3, 

260 G**3, 

261 B**3, 

262 tail, 

263 ] 

264 ) 

265 elif terms == 16: 

266 expansion = tstack( 

267 [ 

268 R, 

269 G, 

270 B, 

271 R * G, 

272 R * B, 

273 G * B, 

274 R**2, 

275 G**2, 

276 B**2, 

277 R * G * B, 

278 R**2 * G, 

279 G**2 * B, 

280 B**2 * R, 

281 R**3, 

282 G**3, 

283 B**3, 

284 ] 

285 ) 

286 elif terms == 17: 

287 expansion = tstack( 

288 [ 

289 R, 

290 G, 

291 B, 

292 R * G, 

293 R * B, 

294 G * B, 

295 R**2, 

296 G**2, 

297 B**2, 

298 R * G * B, 

299 R**2 * G, 

300 G**2 * B, 

301 B**2 * R, 

302 R**3, 

303 G**3, 

304 B**3, 

305 tail, 

306 ] 

307 ) 

308 elif terms == 19: 

309 expansion = tstack( 

310 [ 

311 R, 

312 G, 

313 B, 

314 R * G, 

315 R * B, 

316 G * B, 

317 R**2, 

318 G**2, 

319 B**2, 

320 R * G * B, 

321 R**2 * G, 

322 G**2 * B, 

323 B**2 * R, 

324 R**2 * B, 

325 G**2 * R, 

326 B**2 * G, 

327 R**3, 

328 G**3, 

329 B**3, 

330 ] 

331 ) 

332 elif terms == 20: 

333 expansion = tstack( 

334 [ 

335 R, 

336 G, 

337 B, 

338 R * G, 

339 R * B, 

340 G * B, 

341 R**2, 

342 G**2, 

343 B**2, 

344 R * G * B, 

345 R**2 * G, 

346 G**2 * B, 

347 B**2 * R, 

348 R**2 * B, 

349 G**2 * R, 

350 B**2 * G, 

351 R**3, 

352 G**3, 

353 B**3, 

354 tail, 

355 ] 

356 ) 

357 elif terms == 22: 

358 expansion = tstack( 

359 [ 

360 R, 

361 G, 

362 B, 

363 R * G, 

364 R * B, 

365 G * B, 

366 R**2, 

367 G**2, 

368 B**2, 

369 R * G * B, 

370 R**2 * G, 

371 G**2 * B, 

372 B**2 * R, 

373 R**2 * B, 

374 G**2 * R, 

375 B**2 * G, 

376 R**3, 

377 G**3, 

378 B**3, 

379 R**2 * G * B, 

380 R * G**2 * B, 

381 R * G * B**2, 

382 ] 

383 ) 

384 elif terms == 35: 

385 expansion = tstack( 

386 [ 

387 R, 

388 G, 

389 B, 

390 R * G, 

391 R * B, 

392 G * B, 

393 R**2, 

394 G**2, 

395 B**2, 

396 R * G * B, 

397 R**2 * G, 

398 G**2 * B, 

399 B**2 * R, 

400 R**2 * B, 

401 G**2 * R, 

402 B**2 * G, 

403 R**3, 

404 G**3, 

405 B**3, 

406 R**3 * G, 

407 R**3 * B, 

408 G**3 * R, 

409 G**3 * B, 

410 B**3 * R, 

411 B**3 * G, 

412 R**2 * G * B, 

413 R * G**2 * B, 

414 R * G * B**2, 

415 R**2 * G**2, 

416 R**2 * B**2, 

417 G**2 * B**2, 

418 R**4, 

419 G**4, 

420 B**4, 

421 tail, 

422 ] 

423 ) 

424 

425 return expansion 

426 

427 

428def polynomial_expansion_Finlayson2015( 

429 RGB: ArrayLike, 

430 degree: Literal[1, 2, 3, 4] | int = 1, 

431 root_polynomial_expansion: bool = True, 

432) -> NDArrayFloat: 

433 """ 

434 Perform polynomial expansion of the specified *RGB* colourspace 

435 array using the *Finlayson et al. (2015)* method. 

436 

437 Parameters 

438 ---------- 

439 RGB 

440 *RGB* colourspace array to expand using polynomial expansion. 

441 degree 

442 Expanded polynomial degree. 

443 root_polynomial_expansion 

444 Whether to use the root-polynomials set for the expansion. 

445 

446 Returns 

447 ------- 

448 :class:`numpy.ndarray` 

449 Polynomial-expanded *RGB* colourspace array. 

450 

451 References 

452 ---------- 

453 :cite:`Finlayson2015` 

454 

455 Examples 

456 -------- 

457 >>> RGB = np.array([0.17224810, 0.09170660, 0.06416938]) 

458 >>> polynomial_expansion_Finlayson2015(RGB, degree=2) # doctest: +ELLIPSIS 

459 array([ 0.1722481..., 0.0917066..., 0.0641693..., 0.1256832..., \ 

4600.0767121..., 

461 0.1051335...]) 

462 """ 

463 

464 RGB = as_float_array(RGB) 

465 

466 R, G, B = tsplit(RGB) 

467 

468 # TODO: Generalise polynomial expansion. 

469 existing_degrees = np.array([1, 2, 3, 4]) 

470 closest_degree = as_int(closest(existing_degrees, degree)) 

471 if closest_degree != degree: 

472 error = ( 

473 f'"Finlayson et al. (2015)" method does not define a polynomial ' 

474 f"expansion for {degree} degree, closest polynomial expansion is " 

475 f"{closest_degree} degree!" 

476 ) 

477 

478 raise ValueError(error) 

479 

480 if degree == 1: 

481 expansion = RGB 

482 elif degree == 2: 

483 if root_polynomial_expansion: 

484 expansion = tstack( 

485 [ 

486 as_float(R), 

487 as_float(G), 

488 as_float(B), 

489 spow(R * G, 1 / 2), 

490 spow(G * B, 1 / 2), 

491 spow(R * B, 1 / 2), 

492 ] 

493 ) 

494 

495 else: 

496 expansion = tstack( 

497 [ 

498 R, 

499 G, 

500 B, 

501 R**2, 

502 G**2, 

503 B**2, 

504 R * G, 

505 G * B, 

506 R * B, 

507 ] 

508 ) 

509 elif degree == 3: 

510 if root_polynomial_expansion: 

511 expansion = tstack( 

512 [ 

513 as_float(R), 

514 as_float(G), 

515 as_float(B), 

516 spow(R * G, 1 / 2), 

517 spow(G * B, 1 / 2), 

518 spow(R * B, 1 / 2), 

519 spow(R * G**2, 1 / 3), 

520 spow(G * B**2, 1 / 3), 

521 spow(R * B**2, 1 / 3), 

522 spow(G * R**2, 1 / 3), 

523 spow(B * G**2, 1 / 3), 

524 spow(B * R**2, 1 / 3), 

525 spow(R * G * B, 1 / 3), 

526 ] 

527 ) 

528 else: 

529 expansion = tstack( 

530 [ 

531 R, 

532 G, 

533 B, 

534 R**2, 

535 G**2, 

536 B**2, 

537 R * G, 

538 G * B, 

539 R * B, 

540 R**3, 

541 G**3, 

542 B**3, 

543 R * G**2, 

544 G * B**2, 

545 R * B**2, 

546 G * R**2, 

547 B * G**2, 

548 B * R**2, 

549 R * G * B, 

550 ] 

551 ) 

552 elif degree == 4: 

553 if root_polynomial_expansion: 

554 expansion = tstack( 

555 [ 

556 as_float(R), 

557 as_float(G), 

558 as_float(B), 

559 spow(R * G, 1 / 2), 

560 spow(G * B, 1 / 2), 

561 spow(R * B, 1 / 2), 

562 spow(R * G**2, 1 / 3), 

563 spow(G * B**2, 1 / 3), 

564 spow(R * B**2, 1 / 3), 

565 spow(G * R**2, 1 / 3), 

566 spow(B * G**2, 1 / 3), 

567 spow(B * R**2, 1 / 3), 

568 spow(R * G * B, 1 / 3), 

569 spow(R**3 * G, 1 / 4), 

570 spow(R**3 * B, 1 / 4), 

571 spow(G**3 * R, 1 / 4), 

572 spow(G**3 * B, 1 / 4), 

573 spow(B**3 * R, 1 / 4), 

574 spow(B**3 * G, 1 / 4), 

575 spow(R**2 * G * B, 1 / 4), 

576 spow(G**2 * R * B, 1 / 4), 

577 spow(B**2 * R * G, 1 / 4), 

578 ] 

579 ) 

580 else: 

581 expansion = tstack( 

582 [ 

583 R, 

584 G, 

585 B, 

586 R**2, 

587 G**2, 

588 B**2, 

589 R * G, 

590 G * B, 

591 R * B, 

592 R**3, 

593 G**3, 

594 B**3, 

595 R * G**2, 

596 G * B**2, 

597 R * B**2, 

598 G * R**2, 

599 B * G**2, 

600 B * R**2, 

601 R * G * B, 

602 R**4, 

603 G**4, 

604 B**4, 

605 R**3 * G, 

606 R**3 * B, 

607 G**3 * R, 

608 G**3 * B, 

609 B**3 * R, 

610 B**3 * G, 

611 R**2 * G**2, 

612 G**2 * B**2, 

613 R**2 * B**2, 

614 R**2 * G * B, 

615 G**2 * R * B, 

616 B**2 * R * G, 

617 ] 

618 ) 

619 

620 return expansion 

621 

622 

623def polynomial_expansion_Vandermonde(a: ArrayLike, degree: int = 1) -> NDArrayFloat: 

624 """ 

625 Perform polynomial expansion of the specified :math:`a` array using the 

626 *Vandermonde* method. 

627 

628 Parameters 

629 ---------- 

630 a 

631 Array :math:`a` to expand using polynomial expansion. 

632 degree 

633 Degree of the expanded polynomial. 

634 

635 Returns 

636 ------- 

637 :class:`numpy.ndarray` 

638 Polynomial-expanded :math:`a` array. 

639 

640 References 

641 ---------- 

642 :cite:`Wikipedia2003e` 

643 

644 Examples 

645 -------- 

646 >>> RGB = np.array([0.17224810, 0.09170660, 0.06416938]) 

647 >>> polynomial_expansion_Vandermonde(RGB) # doctest: +ELLIPSIS 

648 array([ 0.1722481 , 0.0917066 , 0.06416938, 1. ]) 

649 """ 

650 

651 a = as_float_array(a) 

652 

653 a_e = np.transpose(np.vander(np.ravel(a), int(degree) + 1)) 

654 a_e = np.hstack(list(np.reshape(a_e, (a_e.shape[0], -1, 3)))) 

655 

656 return np.squeeze(a_e[:, 0 : a_e.shape[-1] - a.shape[-1] + 1]) 

657 

658 

659POLYNOMIAL_EXPANSION_METHODS: CanonicalMapping = CanonicalMapping( 

660 { 

661 "Cheung 2004": matrix_augmented_Cheung2004, 

662 "Finlayson 2015": polynomial_expansion_Finlayson2015, 

663 "Vandermonde": polynomial_expansion_Vandermonde, 

664 } 

665) 

666POLYNOMIAL_EXPANSION_METHODS.__doc__ = """ 

667Supported polynomial expansion methods. 

668 

669References 

670---------- 

671:cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`, 

672:cite:`Wikipedia2003e` 

673""" 

674 

675 

676def polynomial_expansion( 

677 a: ArrayLike, 

678 method: ( 

679 Literal["Cheung 2004", "Finlayson 2015", "Vandermonde"] | str 

680 ) = "Cheung 2004", 

681 **kwargs: Any, 

682) -> NDArrayFloat: 

683 """ 

684 Perform polynomial expansion of the :math:`a` array. 

685 

686 Parameters 

687 ---------- 

688 a 

689 Array to expand using polynomial expansion. 

690 method 

691 Computation method for the polynomial expansion. 

692 

693 Other Parameters 

694 ---------------- 

695 degree 

696 {:func:`colour.characterisation.polynomial_expansion_Finlayson2015`, 

697 :func:`colour.characterisation.polynomial_expansion_Vandermonde`}, 

698 Expanded polynomial degree, must be one of *[1, 2, 3, 4]* for 

699 :func:`colour.characterisation.polynomial_expansion_Finlayson2015` 

700 definition. 

701 root_polynomial_expansion 

702 {:func:`colour.characterisation.polynomial_expansion_Finlayson2015`}, 

703 Whether to use the root-polynomials set for the expansion. 

704 terms 

705 {:func:`colour.characterisation.matrix_augmented_Cheung2004`}, 

706 Number of terms of the expanded polynomial. 

707 

708 Returns 

709 ------- 

710 :class:`numpy.ndarray` 

711 Polynomial-expanded :math:`a` array. 

712 

713 References 

714 ---------- 

715 :cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`, 

716 :cite:`Wikipedia2003e` 

717 

718 Examples 

719 -------- 

720 >>> RGB = np.array([0.17224810, 0.09170660, 0.06416938]) 

721 >>> polynomial_expansion(RGB) # doctest: +ELLIPSIS 

722 array([ 0.1722481..., 0.0917066..., 0.0641693...]) 

723 >>> polynomial_expansion(RGB, "Cheung 2004", terms=5) # doctest: +ELLIPSIS 

724 array([ 0.1722481..., 0.0917066..., 0.0641693..., 0.0010136..., 1...]) 

725 """ 

726 

727 method = validate_method(method, tuple(POLYNOMIAL_EXPANSION_METHODS)) 

728 

729 function = POLYNOMIAL_EXPANSION_METHODS[method] 

730 

731 return function(a, **filter_kwargs(function, **kwargs)) 

732 

733 

734def matrix_colour_correction_Cheung2004( 

735 M_T: ArrayLike, 

736 M_R: ArrayLike, 

737 terms: Literal[3, 4, 5, 7, 8, 10, 11, 14, 16, 17, 19, 20, 22, 35] | int = 3, 

738) -> NDArrayFloat: 

739 """ 

740 Compute a colour correction matrix from test array :math:`M_T` to 

741 reference array :math:`M_R` using the *Cheung et al. (2004)* polynomial 

742 expansion method. 

743 

744 Parameters 

745 ---------- 

746 M_T 

747 Test array :math:`M_T` to fit onto reference array :math:`M_R`. 

748 M_R 

749 Reference array that the test array :math:`M_T` will be colour 

750 fitted against. 

751 terms 

752 Number of terms of the expanded polynomial. The value must be one 

753 of the supported term counts: 3, 4, 5, 7, 8, 10, 11, 14, 16, 17, 

754 19, 20, 22, or 35. 

755 

756 Returns 

757 ------- 

758 :class:`numpy.ndarray` 

759 Colour correction matrix mapping expanded test colours to reference 

760 colours. 

761 

762 References 

763 ---------- 

764 :cite:`Cheung2004`, :cite:`Westland2004` 

765 

766 Examples 

767 -------- 

768 >>> prng = np.random.RandomState(2) 

769 >>> M_T = prng.random_sample((24, 3)) 

770 >>> M_R = M_T + (prng.random_sample((24, 3)) - 0.5) * 0.5 

771 >>> matrix_colour_correction_Cheung2004(M_T, M_R) # doctest: +ELLIPSIS 

772 array([[ 1.0526376..., 0.1378078..., -0.2276339...], 

773 [ 0.0739584..., 1.0293994..., -0.1060115...], 

774 [ 0.0572550..., -0.2052633..., 1.1015194...]]) 

775 """ 

776 

777 return least_square_mapping_MoorePenrose( 

778 matrix_augmented_Cheung2004(M_T, terms), M_R 

779 ) 

780 

781 

782def matrix_colour_correction_Finlayson2015( 

783 M_T: ArrayLike, 

784 M_R: ArrayLike, 

785 degree: Literal[1, 2, 3, 4] | int = 1, 

786 root_polynomial_expansion: bool = True, 

787) -> NDArrayFloat: 

788 """ 

789 Compute a colour correction matrix from test colour array :math:`M_T` to 

790 reference colour array :math:`M_R` using *Finlayson et al. (2015)* 

791 root-polynomial colour correction method. 

792 

793 Parameters 

794 ---------- 

795 M_T 

796 Test array :math:`M_T` to fit onto reference array :math:`M_R`. 

797 M_R 

798 Reference array the test array :math:`M_T` will be colour fitted 

799 against. 

800 degree 

801 Polynomial expansion degree for the root-polynomial basis. The value 

802 must be one of the degrees: 1, 2, 3, 4. 

803 root_polynomial_expansion 

804 Whether to use the root-polynomial basis set for the expansion. If 

805 *False*, uses standard polynomial expansion. 

806 

807 Returns 

808 ------- 

809 :class:`numpy.ndarray` 

810 Colour correction matrix mapping expanded test colours to reference 

811 colours. 

812 

813 References 

814 ---------- 

815 :cite:`Finlayson2015` 

816 

817 Examples 

818 -------- 

819 >>> prng = np.random.RandomState(2) 

820 >>> M_T = prng.random_sample((24, 3)) 

821 >>> M_R = M_T + (prng.random_sample((24, 3)) - 0.5) * 0.5 

822 >>> matrix_colour_correction_Finlayson2015(M_T, M_R) # doctest: +ELLIPSIS 

823 array([[ 1.0526376..., 0.1378078..., -0.2276339...], 

824 [ 0.0739584..., 1.0293994..., -0.1060115...], 

825 [ 0.0572550..., -0.2052633..., 1.1015194...]]) 

826 """ 

827 

828 return least_square_mapping_MoorePenrose( 

829 polynomial_expansion_Finlayson2015(M_T, degree, root_polynomial_expansion), 

830 M_R, 

831 ) 

832 

833 

834def matrix_colour_correction_Vandermonde( 

835 M_T: ArrayLike, M_R: ArrayLike, degree: int = 1 

836) -> NDArrayFloat: 

837 """ 

838 Compute a colour correction matrix from :math:`M_T` test colour array 

839 to :math:`M_R` reference colour array using the *Vandermonde* method. 

840 

841 Parameters 

842 ---------- 

843 M_T 

844 Test array :math:`M_T` to fit onto array :math:`M_R`. 

845 M_R 

846 Reference array the array :math:`M_T` will be colour fitted against. 

847 degree 

848 Expanded polynomial degree. 

849 

850 Returns 

851 ------- 

852 :class:`numpy.ndarray` 

853 Colour correction matrix mapping expanded test colours to reference 

854 colours. 

855 

856 References 

857 ---------- 

858 :cite:`Wikipedia2003e` 

859 

860 Examples 

861 -------- 

862 >>> prng = np.random.RandomState(2) 

863 >>> M_T = prng.random_sample((24, 3)) 

864 >>> M_R = M_T + (prng.random_sample((24, 3)) - 0.5) * 0.5 

865 >>> matrix_colour_correction_Vandermonde(M_T, M_R) # doctest: +ELLIPSIS 

866 array([[ 1.0300256..., 0.1141770..., -0.2621816..., 0.0418022...], 

867 [ 0.0670209..., 1.0221494..., -0.1166108..., 0.0128250...], 

868 [ 0.0744612..., -0.1872819..., 1.1278078..., -0.0318085...]]) 

869 """ 

870 

871 return least_square_mapping_MoorePenrose( 

872 polynomial_expansion_Vandermonde(M_T, degree), M_R 

873 ) 

874 

875 

876MATRIX_COLOUR_CORRECTION_METHODS: CanonicalMapping = CanonicalMapping( 

877 { 

878 "Cheung 2004": matrix_colour_correction_Cheung2004, 

879 "Finlayson 2015": matrix_colour_correction_Finlayson2015, 

880 "Vandermonde": matrix_colour_correction_Vandermonde, 

881 } 

882) 

883MATRIX_COLOUR_CORRECTION_METHODS.__doc__ = """ 

884Supported colour correction matrix computation methods. 

885 

886References 

887---------- 

888:cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`, 

889:cite:`Wikipedia2003e` 

890""" 

891 

892 

893def matrix_colour_correction( 

894 M_T: ArrayLike, 

895 M_R: ArrayLike, 

896 method: ( 

897 Literal["Cheung 2004", "Finlayson 2015", "Vandermonde"] | str 

898 ) = "Cheung 2004", 

899 **kwargs: Any, 

900) -> NDArrayFloat: 

901 """ 

902 Compute a colour correction matrix from :math:`M_T` colour array to 

903 :math:`M_R` colour array. 

904 

905 Compute the colour correction matrix using multiple linear or polynomial 

906 regression with the specified method. The resulting matrix enables colour 

907 matching between two arrays, such as matching two *ColorChecker* colour 

908 rendition charts together. 

909 

910 Parameters 

911 ---------- 

912 M_T 

913 Test array :math:`M_T` to fit onto array :math:`M_R`. 

914 M_R 

915 Reference array the array :math:`M_T` will be colour fitted against. 

916 method 

917 Computation method. 

918 

919 Other Parameters 

920 ---------------- 

921 degree 

922 {:func:`colour.characterisation.matrix_colour_correction_Finlayson2015`, 

923 :func:`colour.characterisation.matrix_colour_correction_Vandermonde`}, 

924 Expanded polynomial degree, must be one of *[1, 2, 3, 4]* for 

925 :func:`colour.characterisation.matrix_colour_correction_Finlayson2015` 

926 definition. 

927 root_polynomial_expansion 

928 {:func:`colour.characterisation.matrix_colour_correction_Finlayson2015`}, 

929 Whether to use the root-polynomials set for the expansion. 

930 terms 

931 {:func:`colour.characterisation.matrix_colour_correction_Cheung2004`}, 

932 Number of terms of the expanded polynomial. 

933 

934 Returns 

935 ------- 

936 :class:`numpy.ndarray` 

937 Colour correction matrix mapping expanded test colours to reference 

938 colours. 

939 

940 References 

941 ---------- 

942 :cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`, 

943 :cite:`Wikipedia2003e` 

944 

945 Examples 

946 -------- 

947 >>> M_T = np.array( 

948 ... [ 

949 ... [0.17224810, 0.09170660, 0.06416938], 

950 ... [0.49189645, 0.27802050, 0.21923399], 

951 ... [0.10999751, 0.18658946, 0.29938611], 

952 ... [0.11666120, 0.14327905, 0.05713804], 

953 ... [0.18988879, 0.18227649, 0.36056247], 

954 ... [0.12501329, 0.42223442, 0.37027445], 

955 ... [0.64785606, 0.22396782, 0.03365194], 

956 ... [0.06761093, 0.11076896, 0.39779139], 

957 ... [0.49101797, 0.09448929, 0.11623839], 

958 ... [0.11622386, 0.04425753, 0.14469986], 

959 ... [0.36867946, 0.44545230, 0.06028681], 

960 ... [0.61632937, 0.32323906, 0.02437089], 

961 ... [0.03016472, 0.06153243, 0.29014596], 

962 ... [0.11103655, 0.30553067, 0.08149137], 

963 ... [0.41162190, 0.05816656, 0.04845934], 

964 ... [0.73339206, 0.53075188, 0.02475212], 

965 ... [0.47347718, 0.08834792, 0.30310315], 

966 ... [0.00000000, 0.25187016, 0.35062450], 

967 ... [0.76809639, 0.78486240, 0.77808297], 

968 ... [0.53822392, 0.54307997, 0.54710883], 

969 ... [0.35458526, 0.35318419, 0.35524431], 

970 ... [0.17976704, 0.18000531, 0.17991488], 

971 ... [0.09351417, 0.09510603, 0.09675027], 

972 ... [0.03405071, 0.03295077, 0.03702047], 

973 ... ] 

974 ... ) 

975 >>> M_R = np.array( 

976 ... [ 

977 ... [0.15579559, 0.09715755, 0.07514556], 

978 ... [0.39113140, 0.25943419, 0.21266708], 

979 ... [0.12824821, 0.18463570, 0.31508023], 

980 ... [0.12028974, 0.13455659, 0.07408400], 

981 ... [0.19368988, 0.21158946, 0.37955964], 

982 ... [0.19957425, 0.36085439, 0.40678123], 

983 ... [0.48896605, 0.20691688, 0.05816533], 

984 ... [0.09775522, 0.16710693, 0.47147724], 

985 ... [0.39358649, 0.12233400, 0.10526425], 

986 ... [0.10780332, 0.07258529, 0.16151473], 

987 ... [0.27502671, 0.34705454, 0.09728099], 

988 ... [0.43980441, 0.26880559, 0.05430533], 

989 ... [0.05887212, 0.11126272, 0.38552469], 

990 ... [0.12705825, 0.25787860, 0.13566464], 

991 ... [0.35612929, 0.07933258, 0.05118732], 

992 ... [0.48131976, 0.42082843, 0.07120612], 

993 ... [0.34665585, 0.15170714, 0.24969804], 

994 ... [0.08261116, 0.24588716, 0.48707733], 

995 ... [0.66054904, 0.65941137, 0.66376412], 

996 ... [0.48051509, 0.47870296, 0.48230082], 

997 ... [0.33045354, 0.32904184, 0.33228886], 

998 ... [0.18001305, 0.17978567, 0.18004416], 

999 ... [0.10283975, 0.10424680, 0.10384975], 

1000 ... [0.04742204, 0.04772203, 0.04914226], 

1001 ... ] 

1002 ... ) 

1003 >>> matrix_colour_correction(M_T, M_R) # doctest: +ELLIPSIS 

1004 array([[ 0.6982266..., 0.0307162..., 0.1621042...], 

1005 [ 0.0689349..., 0.6757961..., 0.1643038...], 

1006 [-0.0631495..., 0.0921247..., 0.9713415...]]) 

1007 """ 

1008 

1009 method = validate_method(method, tuple(MATRIX_COLOUR_CORRECTION_METHODS)) 

1010 

1011 function = MATRIX_COLOUR_CORRECTION_METHODS[method] 

1012 

1013 return function(M_T, M_R, **filter_kwargs(function, **kwargs)) 

1014 

1015 

1016def apply_matrix_colour_correction_Cheung2004( 

1017 RGB: ArrayLike, 

1018 CCM: ArrayLike, 

1019 terms: Literal[3, 4, 5, 7, 8, 10, 11, 14, 16, 17, 19, 20, 22, 35] | int = 3, 

1020) -> NDArrayFloat: 

1021 """ 

1022 Apply colour correction matrix :math:`CCM` computed using *Cheung et al. 

1023 (2004)* method to the specified *RGB* colourspace array. 

1024 

1025 Parameters 

1026 ---------- 

1027 RGB 

1028 *RGB* colourspace array to which the colour correction matrix 

1029 :math:`CCM` is applied. 

1030 CCM 

1031 Colour correction matrix :math:`CCM`. 

1032 terms 

1033 Number of terms of the expanded polynomial. 

1034 

1035 Returns 

1036 ------- 

1037 :class:`numpy.ndarray` 

1038 Colour corrected *RGB* colourspace array. 

1039 

1040 References 

1041 ---------- 

1042 :cite:`Cheung2004`, :cite:`Westland2004` 

1043 

1044 Examples 

1045 -------- 

1046 >>> RGB = np.array([0.17224810, 0.09170660, 0.06416938]) 

1047 >>> CCM = np.array( 

1048 ... [ 

1049 ... [1.05263767, 0.13780789, -0.22763399], 

1050 ... [0.07395843, 1.02939945, -0.1060115], 

1051 ... [0.05725508, -0.20526336, 1.10151945], 

1052 ... ] 

1053 ... ) 

1054 >>> apply_matrix_colour_correction_Cheung2004(RGB, CCM) # doctest: +ELLIPSIS 

1055 array([ 0.1793456..., 0.1003392..., 0.0617218...]) 

1056 """ 

1057 

1058 RGB = as_float_array(RGB) 

1059 shape = RGB.shape 

1060 

1061 RGB = np.reshape(RGB, (-1, 3)) 

1062 

1063 RGB_e = matrix_augmented_Cheung2004(RGB, terms) 

1064 

1065 return np.reshape(np.transpose(np.dot(CCM, np.transpose(RGB_e))), shape) 

1066 

1067 

1068def apply_matrix_colour_correction_Finlayson2015( 

1069 RGB: ArrayLike, 

1070 CCM: ArrayLike, 

1071 degree: Literal[1, 2, 3, 4] | int = 1, 

1072 root_polynomial_expansion: bool = True, 

1073) -> NDArrayFloat: 

1074 """ 

1075 Apply colour correction matrix :math:`CCM` computed using 

1076 *Finlayson et al. (2015)* method to the specified *RGB* colourspace array. 

1077 

1078 Parameters 

1079 ---------- 

1080 RGB 

1081 *RGB* colourspace array to which the colour correction matrix 

1082 :math:`CCM` is applied. 

1083 CCM 

1084 Colour correction matrix :math:`CCM`. 

1085 degree 

1086 Expanded polynomial degree. 

1087 root_polynomial_expansion 

1088 Whether to use the root-polynomials set for the expansion. 

1089 

1090 Returns 

1091 ------- 

1092 :class:`numpy.ndarray` 

1093 Colour corrected *RGB* colourspace array. 

1094 

1095 References 

1096 ---------- 

1097 :cite:`Finlayson2015` 

1098 

1099 Examples 

1100 -------- 

1101 >>> RGB = np.array([0.17224810, 0.09170660, 0.06416938]) 

1102 >>> CCM = np.array( 

1103 ... [ 

1104 ... [1.05263767, 0.13780789, -0.22763399], 

1105 ... [0.07395843, 1.02939945, -0.1060115], 

1106 ... [0.05725508, -0.20526336, 1.10151945], 

1107 ... ] 

1108 ... ) 

1109 >>> apply_matrix_colour_correction_Finlayson2015(RGB, CCM) # doctest: +ELLIPSIS 

1110 array([ 0.1793456..., 0.1003392..., 0.0617218...]) 

1111 """ 

1112 

1113 RGB = as_float_array(RGB) 

1114 shape = RGB.shape 

1115 

1116 RGB = np.reshape(RGB, (-1, 3)) 

1117 

1118 RGB_e = polynomial_expansion_Finlayson2015(RGB, degree, root_polynomial_expansion) 

1119 

1120 return np.reshape(np.transpose(np.dot(CCM, np.transpose(RGB_e))), shape) 

1121 

1122 

1123def apply_matrix_colour_correction_Vandermonde( 

1124 RGB: ArrayLike, CCM: ArrayLike, degree: int = 1 

1125) -> NDArrayFloat: 

1126 """ 

1127 Apply colour correction matrix :math:`CCM` computed using the 

1128 *Vandermonde* method to the specified *RGB* colourspace array. 

1129 

1130 Parameters 

1131 ---------- 

1132 RGB 

1133 *RGB* colourspace array to which the colour correction matrix 

1134 :math:`CCM` is applied. 

1135 CCM 

1136 Colour correction matrix :math:`CCM`. 

1137 degree 

1138 Expanded polynomial degree. 

1139 

1140 Returns 

1141 ------- 

1142 :class:`numpy.ndarray` 

1143 Colour corrected *RGB* colourspace array. 

1144 

1145 References 

1146 ---------- 

1147 :cite:`Wikipedia2003e` 

1148 

1149 Examples 

1150 -------- 

1151 >>> RGB = np.array([0.17224810, 0.09170660, 0.06416938]) 

1152 >>> CCM = np.array( 

1153 ... [ 

1154 ... [1.0300256, 0.11417701, -0.26218168, 0.04180222], 

1155 ... [0.06702098, 1.02214943, -0.11661082, 0.01282503], 

1156 ... [0.07446128, -0.18728192, 1.12780782, -0.03180856], 

1157 ... ] 

1158 ... ) 

1159 >>> apply_matrix_colour_correction_Vandermonde(RGB, CCM) # doctest: +ELLIPSIS 

1160 array([ 0.2128689..., 0.1106242..., 0.0362129...]) 

1161 """ 

1162 

1163 RGB = as_float_array(RGB) 

1164 shape = RGB.shape 

1165 

1166 RGB = np.reshape(RGB, (-1, 3)) 

1167 

1168 RGB_e = polynomial_expansion_Vandermonde(RGB, degree) 

1169 

1170 return np.reshape(np.transpose(np.dot(CCM, np.transpose(RGB_e))), shape) 

1171 

1172 

1173APPLY_MATRIX_COLOUR_CORRECTION_METHODS = CanonicalMapping( 

1174 { 

1175 "Cheung 2004": apply_matrix_colour_correction_Cheung2004, 

1176 "Finlayson 2015": apply_matrix_colour_correction_Finlayson2015, 

1177 "Vandermonde": apply_matrix_colour_correction_Vandermonde, 

1178 } 

1179) 

1180APPLY_MATRIX_COLOUR_CORRECTION_METHODS.__doc__ = """ 

1181Supported methods to apply a colour correction matrix. 

1182 

1183References 

1184---------- 

1185:cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`, 

1186:cite:`Wikipedia2003e` 

1187""" 

1188 

1189 

1190def apply_matrix_colour_correction( 

1191 RGB: ArrayLike, 

1192 CCM: ArrayLike, 

1193 method: ( 

1194 Literal["Cheung 2004", "Finlayson 2015", "Vandermonde"] | str 

1195 ) = "Cheung 2004", 

1196 **kwargs: Any, 

1197) -> NDArrayFloat: 

1198 """ 

1199 Apply colour correction matrix :math:`CCM` to the specified *RGB* 

1200 colourspace array. 

1201 

1202 The colour correction matrix transforms the input *RGB* values through 

1203 polynomial expansion and matrix multiplication to produce colour 

1204 corrected output values. The computation method determines the 

1205 polynomial expansion approach used before applying the matrix. 

1206 

1207 Parameters 

1208 ---------- 

1209 RGB 

1210 *RGB* colourspace array to which the colour correction matrix 

1211 :math:`CCM` is applied. 

1212 CCM 

1213 Colour correction matrix :math:`CCM`. 

1214 method 

1215 Computation method. 

1216 

1217 Other Parameters 

1218 ---------------- 

1219 degree 

1220 {:func:`colour.characterisation.apply_matrix_colour_correction_Finlayson2015`, 

1221 :func:`colour.characterisation.apply_matrix_colour_correction_Vandermonde`}, 

1222 Expanded polynomial degree, must be one of *[1, 2, 3, 4]* for 

1223 :func:`colour.characterisation.apply_matrix_colour_correction_Finlayson2015` 

1224 definition. 

1225 root_polynomial_expansion 

1226 {:func:`colour.characterisation.apply_matrix_colour_correction_Finlayson2015`}, 

1227 Whether to use the root-polynomials set for the expansion. 

1228 terms 

1229 {:func:`colour.characterisation.apply_matrix_colour_correction_Cheung2004`}, 

1230 Number of terms of the expanded polynomial. 

1231 

1232 Returns 

1233 ------- 

1234 :class:`numpy.ndarray` 

1235 Colour corrected *RGB* colourspace array. 

1236 

1237 References 

1238 ---------- 

1239 :cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`, 

1240 :cite:`Wikipedia2003e` 

1241 

1242 Examples 

1243 -------- 

1244 >>> RGB = np.array([0.17224810, 0.09170660, 0.06416938]) 

1245 >>> CCM = np.array( 

1246 ... [ 

1247 ... [1.05263767, 0.13780789, -0.22763399], 

1248 ... [0.07395843, 1.02939945, -0.1060115], 

1249 ... [0.05725508, -0.20526336, 1.10151945], 

1250 ... ] 

1251 ... ) 

1252 >>> apply_matrix_colour_correction(RGB, CCM) # doctest: +ELLIPSIS 

1253 array([ 0.1793456..., 0.1003392..., 0.0617218...]) 

1254 """ 

1255 

1256 method = validate_method(method, tuple(APPLY_MATRIX_COLOUR_CORRECTION_METHODS)) 

1257 

1258 function = APPLY_MATRIX_COLOUR_CORRECTION_METHODS[method] 

1259 

1260 return function(RGB, CCM, **filter_kwargs(function, **kwargs)) 

1261 

1262 

1263def colour_correction_Cheung2004( 

1264 RGB: ArrayLike, 

1265 M_T: ArrayLike, 

1266 M_R: ArrayLike, 

1267 terms: Literal[3, 4, 5, 7, 8, 10, 11, 14, 16, 17, 19, 20, 22, 35] | int = 3, 

1268) -> NDArrayFloat: 

1269 """ 

1270 Perform colour correction of the specified *RGB* colourspace array using 

1271 the colour correction matrix derived from test array :math:`M_T` to 

1272 reference array :math:`M_R` using the *Cheung et al. (2004)* method. 

1273 

1274 Parameters 

1275 ---------- 

1276 RGB 

1277 *RGB* colourspace array to colour correct. 

1278 M_T 

1279 Test array :math:`M_T` to fit onto reference array :math:`M_R`. 

1280 M_R 

1281 Reference array that the test array :math:`M_T` will be colour 

1282 fitted against. 

1283 terms 

1284 Number of terms of the expanded polynomial. 

1285 

1286 Returns 

1287 ------- 

1288 :class:`numpy.ndarray` 

1289 Colour corrected *RGB* colourspace array. 

1290 

1291 References 

1292 ---------- 

1293 :cite:`Cheung2004`, :cite:`Westland2004` 

1294 

1295 Examples 

1296 -------- 

1297 >>> RGB = np.array([0.17224810, 0.09170660, 0.06416938]) 

1298 >>> prng = np.random.RandomState(2) 

1299 >>> M_T = prng.random_sample((24, 3)) 

1300 >>> M_R = M_T + (prng.random_sample((24, 3)) - 0.5) * 0.5 

1301 >>> colour_correction_Cheung2004(RGB, M_T, M_R) # doctest: +ELLIPSIS 

1302 array([ 0.1793456..., 0.1003392..., 0.0617218...]) 

1303 """ 

1304 

1305 return apply_matrix_colour_correction_Cheung2004( 

1306 RGB, matrix_colour_correction_Cheung2004(M_T, M_R, terms), terms 

1307 ) 

1308 

1309 

1310def colour_correction_Finlayson2015( 

1311 RGB: ArrayLike, 

1312 M_T: ArrayLike, 

1313 M_R: ArrayLike, 

1314 degree: Literal[1, 2, 3, 4] | int = 1, 

1315 root_polynomial_expansion: bool = True, 

1316) -> NDArrayFloat: 

1317 """ 

1318 Perform colour correction of *RGB* colourspace array using the colour 

1319 correction matrix from test array :math:`M_T` to reference array 

1320 :math:`M_R` using the *Finlayson et al. (2015)* method. 

1321 

1322 Parameters 

1323 ---------- 

1324 RGB 

1325 *RGB* colourspace array to colour correct. 

1326 M_T 

1327 Test array :math:`M_T` to fit onto reference array :math:`M_R`. 

1328 M_R 

1329 Reference array that the test array :math:`M_T` will be fitted 

1330 against. 

1331 degree 

1332 Polynomial expansion degree. 

1333 root_polynomial_expansion 

1334 Whether to use the root-polynomial set for the expansion. 

1335 

1336 Returns 

1337 ------- 

1338 :class:`numpy.ndarray` 

1339 Colour corrected *RGB* colourspace array. 

1340 

1341 References 

1342 ---------- 

1343 :cite:`Finlayson2015` 

1344 

1345 Examples 

1346 -------- 

1347 >>> RGB = np.array([0.17224810, 0.09170660, 0.06416938]) 

1348 >>> prng = np.random.RandomState(2) 

1349 >>> M_T = prng.random_sample((24, 3)) 

1350 >>> M_R = M_T + (prng.random_sample((24, 3)) - 0.5) * 0.5 

1351 >>> colour_correction_Finlayson2015(RGB, M_T, M_R) # doctest: +ELLIPSIS 

1352 array([ 0.1793456..., 0.1003392..., 0.0617218...]) 

1353 """ 

1354 

1355 return apply_matrix_colour_correction_Finlayson2015( 

1356 RGB, 

1357 matrix_colour_correction_Finlayson2015( 

1358 M_T, M_R, degree, root_polynomial_expansion 

1359 ), 

1360 degree, 

1361 root_polynomial_expansion, 

1362 ) 

1363 

1364 

1365def colour_correction_Vandermonde( 

1366 RGB: ArrayLike, M_T: ArrayLike, M_R: ArrayLike, degree: int = 1 

1367) -> NDArrayFloat: 

1368 """ 

1369 Perform colour correction of *RGB* colourspace array using the colour 

1370 correction matrix from :math:`M_T` colour array to :math:`M_R` colour 

1371 array using *Vandermonde* method. 

1372 

1373 Parameters 

1374 ---------- 

1375 RGB 

1376 *RGB* colourspace array to colour correct. 

1377 M_T 

1378 Test array :math:`M_T` to fit onto array :math:`M_R`. 

1379 M_R 

1380 Reference array the array :math:`M_T` will be colour fitted against. 

1381 degree 

1382 Expanded polynomial degree. 

1383 

1384 Returns 

1385 ------- 

1386 :class:`numpy.ndarray` 

1387 Colour corrected *RGB* colourspace array. 

1388 

1389 References 

1390 ---------- 

1391 :cite:`Wikipedia2003e` 

1392 

1393 Examples 

1394 -------- 

1395 >>> RGB = np.array([0.17224810, 0.09170660, 0.06416938]) 

1396 >>> prng = np.random.RandomState(2) 

1397 >>> M_T = prng.random_sample((24, 3)) 

1398 >>> M_R = M_T + (prng.random_sample((24, 3)) - 0.5) * 0.5 

1399 >>> colour_correction_Vandermonde(RGB, M_T, M_R) # doctest: +ELLIPSIS 

1400 array([ 0.2128689..., 0.1106242..., 0.036213 ...]) 

1401 """ 

1402 

1403 return apply_matrix_colour_correction_Vandermonde( 

1404 RGB, matrix_colour_correction_Vandermonde(M_T, M_R, degree), degree 

1405 ) 

1406 

1407 

1408COLOUR_CORRECTION_METHODS = CanonicalMapping( 

1409 { 

1410 "Cheung 2004": colour_correction_Cheung2004, 

1411 "Finlayson 2015": colour_correction_Finlayson2015, 

1412 "Vandermonde": colour_correction_Vandermonde, 

1413 } 

1414) 

1415COLOUR_CORRECTION_METHODS.__doc__ = """ 

1416Define the supported colour correction methods. 

1417 

1418References 

1419---------- 

1420:cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`, 

1421:cite:`Wikipedia2003e` 

1422""" 

1423 

1424 

1425def colour_correction( 

1426 RGB: ArrayLike, 

1427 M_T: ArrayLike, 

1428 M_R: ArrayLike, 

1429 method: ( 

1430 Literal["Cheung 2004", "Finlayson 2015", "Vandermonde"] | str 

1431 ) = "Cheung 2004", 

1432 **kwargs: Any, 

1433) -> NDArrayFloat: 

1434 """ 

1435 Perform colour correction of *RGB* colourspace array using the colour 

1436 correction matrix from :math:`M_T` colour array to :math:`M_R` colour 

1437 array. 

1438 

1439 Parameters 

1440 ---------- 

1441 RGB 

1442 *RGB* colourspace array to colour correct. 

1443 M_T 

1444 Test array :math:`M_T` to fit onto array :math:`M_R`. 

1445 M_R 

1446 Reference array the array :math:`M_T` will be colour fitted against. 

1447 method 

1448 Computation method. 

1449 

1450 Other Parameters 

1451 ---------------- 

1452 degree 

1453 {:func:`colour.characterisation.colour_correction_Finlayson2015`, 

1454 :func:`colour.characterisation.colour_correction_Vandermonde`}, 

1455 Expanded polynomial degree, must be one of *[1, 2, 3, 4]* for 

1456 :func:`colour.characterisation.colour_correction_Finlayson2015` 

1457 definition. 

1458 root_polynomial_expansion 

1459 {:func:`colour.characterisation.colour_correction_Finlayson2015`}, 

1460 Whether to use the root-polynomials set for the expansion. 

1461 terms 

1462 {:func:`colour.characterisation.colour_correction_Cheung2004`}, 

1463 Number of terms of the expanded polynomial. 

1464 

1465 Returns 

1466 ------- 

1467 :class:`numpy.ndarray` 

1468 Colour corrected *RGB* colourspace array. 

1469 

1470 References 

1471 ---------- 

1472 :cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`, 

1473 :cite:`Wikipedia2003e` 

1474 

1475 Examples 

1476 -------- 

1477 >>> RGB = np.array([0.17224810, 0.09170660, 0.06416938]) 

1478 >>> M_T = np.array( 

1479 ... [ 

1480 ... [0.17224810, 0.09170660, 0.06416938], 

1481 ... [0.49189645, 0.27802050, 0.21923399], 

1482 ... [0.10999751, 0.18658946, 0.29938611], 

1483 ... [0.11666120, 0.14327905, 0.05713804], 

1484 ... [0.18988879, 0.18227649, 0.36056247], 

1485 ... [0.12501329, 0.42223442, 0.37027445], 

1486 ... [0.64785606, 0.22396782, 0.03365194], 

1487 ... [0.06761093, 0.11076896, 0.39779139], 

1488 ... [0.49101797, 0.09448929, 0.11623839], 

1489 ... [0.11622386, 0.04425753, 0.14469986], 

1490 ... [0.36867946, 0.44545230, 0.06028681], 

1491 ... [0.61632937, 0.32323906, 0.02437089], 

1492 ... [0.03016472, 0.06153243, 0.29014596], 

1493 ... [0.11103655, 0.30553067, 0.08149137], 

1494 ... [0.41162190, 0.05816656, 0.04845934], 

1495 ... [0.73339206, 0.53075188, 0.02475212], 

1496 ... [0.47347718, 0.08834792, 0.30310315], 

1497 ... [0.00000000, 0.25187016, 0.35062450], 

1498 ... [0.76809639, 0.78486240, 0.77808297], 

1499 ... [0.53822392, 0.54307997, 0.54710883], 

1500 ... [0.35458526, 0.35318419, 0.35524431], 

1501 ... [0.17976704, 0.18000531, 0.17991488], 

1502 ... [0.09351417, 0.09510603, 0.09675027], 

1503 ... [0.03405071, 0.03295077, 0.03702047], 

1504 ... ] 

1505 ... ) 

1506 >>> M_R = np.array( 

1507 ... [ 

1508 ... [0.15579559, 0.09715755, 0.07514556], 

1509 ... [0.39113140, 0.25943419, 0.21266708], 

1510 ... [0.12824821, 0.18463570, 0.31508023], 

1511 ... [0.12028974, 0.13455659, 0.07408400], 

1512 ... [0.19368988, 0.21158946, 0.37955964], 

1513 ... [0.19957425, 0.36085439, 0.40678123], 

1514 ... [0.48896605, 0.20691688, 0.05816533], 

1515 ... [0.09775522, 0.16710693, 0.47147724], 

1516 ... [0.39358649, 0.12233400, 0.10526425], 

1517 ... [0.10780332, 0.07258529, 0.16151473], 

1518 ... [0.27502671, 0.34705454, 0.09728099], 

1519 ... [0.43980441, 0.26880559, 0.05430533], 

1520 ... [0.05887212, 0.11126272, 0.38552469], 

1521 ... [0.12705825, 0.25787860, 0.13566464], 

1522 ... [0.35612929, 0.07933258, 0.05118732], 

1523 ... [0.48131976, 0.42082843, 0.07120612], 

1524 ... [0.34665585, 0.15170714, 0.24969804], 

1525 ... [0.08261116, 0.24588716, 0.48707733], 

1526 ... [0.66054904, 0.65941137, 0.66376412], 

1527 ... [0.48051509, 0.47870296, 0.48230082], 

1528 ... [0.33045354, 0.32904184, 0.33228886], 

1529 ... [0.18001305, 0.17978567, 0.18004416], 

1530 ... [0.10283975, 0.10424680, 0.10384975], 

1531 ... [0.04742204, 0.04772203, 0.04914226], 

1532 ... ] 

1533 ... ) 

1534 >>> colour_correction(RGB, M_T, M_R) # doctest: +ELLIPSIS 

1535 array([ 0.1334872..., 0.0843921..., 0.0599014...]) 

1536 """ 

1537 

1538 method = validate_method(method, tuple(COLOUR_CORRECTION_METHODS)) 

1539 

1540 function = COLOUR_CORRECTION_METHODS[method] 

1541 

1542 return function(RGB, M_T, M_R, **filter_kwargs(function, **kwargs))