Coverage for characterisation/correction.py: 64%

1"""

2 Colour Correction

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

4

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

6 between 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

52 References

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

69 from __future__ import annotations

70

71 import typing

72

73 import numpy as np

74

75 from colour.algebra import least_square_mapping_MoorePenrose, spow

76

77 if typing.TYPE_CHECKING:

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

79

80 from 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

124 def 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

428 def 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..., \

460 0.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

623 def 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

659 POLYNOMIAL_EXPANSION_METHODS: CanonicalMapping = CanonicalMapping(

660 {

661 "Cheung 2004": matrix_augmented_Cheung2004,

662 "Finlayson 2015": polynomial_expansion_Finlayson2015,

663 "Vandermonde": polynomial_expansion_Vandermonde,

664 }

665)

666 POLYNOMIAL_EXPANSION_METHODS.__doc__ = """

667 Supported polynomial expansion methods.

668

669 References

670----------

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

672:cite:`Wikipedia2003e`

673"""

674

675

676 def 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

734 def 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

782 def 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

834 def 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

876 MATRIX_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)

883 MATRIX_COLOUR_CORRECTION_METHODS.__doc__ = """

884 Supported colour correction matrix computation methods.

885

886 References

887----------

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

889:cite:`Wikipedia2003e`

890"""

891

892

893 def 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

1016 def 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

1068 def 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

1123 def 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

1173 APPLY_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)

1180 APPLY_MATRIX_COLOUR_CORRECTION_METHODS.__doc__ = """

1181 Supported methods to apply a colour correction matrix.

1182

1183 References

1184----------

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

1186:cite:`Wikipedia2003e`

1187"""

1188

1189

1190 def 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

1263 def 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

1310 def 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

1365 def 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

1408 COLOUR_CORRECTION_METHODS = CanonicalMapping(

1409 {

1410 "Cheung 2004": colour_correction_Cheung2004,

1411 "Finlayson 2015": colour_correction_Finlayson2015,

1412 "Vandermonde": colour_correction_Vandermonde,

1413 }

1414)

1415 COLOUR_CORRECTION_METHODS.__doc__ = """

1416 Define the supported colour correction methods.

1417

1418 References

1419----------

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

1421:cite:`Wikipedia2003e`

1422"""

1423

1424

1425 def 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))