Coverage for characterisation/correction.py: 64%
132 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 22:49 +1300
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 22:49 +1300
1"""
2Colour Correction
3=================
5Define objects for colour correction, including methods for colour matching
6between images:
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.
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"""
69from __future__ import annotations
71import typing
73import numpy as np
75from colour.algebra import least_square_mapping_MoorePenrose, spow
77if typing.TYPE_CHECKING:
78 from colour.hints import Any, ArrayLike, Literal, NDArrayFloat
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)
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"
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]
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.
132 Parameters
133 ----------
134 RGB
135 *RGB* colourspace array to expand using polynomial expansion.
136 terms
137 Number of terms of the expanded polynomial.
139 Returns
140 -------
141 :class:`numpy.ndarray`
142 Polynomial-expanded *RGB* colourspace array.
144 Notes
145 -----
146 - This definition combines the augmented matrices specified in
147 :cite:`Cheung2004` and :cite:`Westland2004`.
149 References
150 ----------
151 :cite:`Cheung2004`, :cite:`Westland2004`
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 """
160 RGB = as_float_array(RGB)
162 R, G, B = tsplit(RGB)
163 tail = ones(R.shape)
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 )
174 raise ValueError(error)
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 )
425 return expansion
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.
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.
446 Returns
447 -------
448 :class:`numpy.ndarray`
449 Polynomial-expanded *RGB* colourspace array.
451 References
452 ----------
453 :cite:`Finlayson2015`
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 """
464 RGB = as_float_array(RGB)
466 R, G, B = tsplit(RGB)
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 )
478 raise ValueError(error)
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 )
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 )
620 return expansion
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.
628 Parameters
629 ----------
630 a
631 Array :math:`a` to expand using polynomial expansion.
632 degree
633 Degree of the expanded polynomial.
635 Returns
636 -------
637 :class:`numpy.ndarray`
638 Polynomial-expanded :math:`a` array.
640 References
641 ----------
642 :cite:`Wikipedia2003e`
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 """
651 a = as_float_array(a)
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))))
656 return np.squeeze(a_e[:, 0 : a_e.shape[-1] - a.shape[-1] + 1])
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.
669References
670----------
671:cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`,
672:cite:`Wikipedia2003e`
673"""
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.
686 Parameters
687 ----------
688 a
689 Array to expand using polynomial expansion.
690 method
691 Computation method for the polynomial expansion.
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.
708 Returns
709 -------
710 :class:`numpy.ndarray`
711 Polynomial-expanded :math:`a` array.
713 References
714 ----------
715 :cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`,
716 :cite:`Wikipedia2003e`
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 """
727 method = validate_method(method, tuple(POLYNOMIAL_EXPANSION_METHODS))
729 function = POLYNOMIAL_EXPANSION_METHODS[method]
731 return function(a, **filter_kwargs(function, **kwargs))
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.
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.
756 Returns
757 -------
758 :class:`numpy.ndarray`
759 Colour correction matrix mapping expanded test colours to reference
760 colours.
762 References
763 ----------
764 :cite:`Cheung2004`, :cite:`Westland2004`
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 """
777 return least_square_mapping_MoorePenrose(
778 matrix_augmented_Cheung2004(M_T, terms), M_R
779 )
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.
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.
807 Returns
808 -------
809 :class:`numpy.ndarray`
810 Colour correction matrix mapping expanded test colours to reference
811 colours.
813 References
814 ----------
815 :cite:`Finlayson2015`
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 """
828 return least_square_mapping_MoorePenrose(
829 polynomial_expansion_Finlayson2015(M_T, degree, root_polynomial_expansion),
830 M_R,
831 )
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.
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.
850 Returns
851 -------
852 :class:`numpy.ndarray`
853 Colour correction matrix mapping expanded test colours to reference
854 colours.
856 References
857 ----------
858 :cite:`Wikipedia2003e`
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 """
871 return least_square_mapping_MoorePenrose(
872 polynomial_expansion_Vandermonde(M_T, degree), M_R
873 )
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.
886References
887----------
888:cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`,
889:cite:`Wikipedia2003e`
890"""
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.
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.
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.
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.
934 Returns
935 -------
936 :class:`numpy.ndarray`
937 Colour correction matrix mapping expanded test colours to reference
938 colours.
940 References
941 ----------
942 :cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`,
943 :cite:`Wikipedia2003e`
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 """
1009 method = validate_method(method, tuple(MATRIX_COLOUR_CORRECTION_METHODS))
1011 function = MATRIX_COLOUR_CORRECTION_METHODS[method]
1013 return function(M_T, M_R, **filter_kwargs(function, **kwargs))
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.
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.
1035 Returns
1036 -------
1037 :class:`numpy.ndarray`
1038 Colour corrected *RGB* colourspace array.
1040 References
1041 ----------
1042 :cite:`Cheung2004`, :cite:`Westland2004`
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 """
1058 RGB = as_float_array(RGB)
1059 shape = RGB.shape
1061 RGB = np.reshape(RGB, (-1, 3))
1063 RGB_e = matrix_augmented_Cheung2004(RGB, terms)
1065 return np.reshape(np.transpose(np.dot(CCM, np.transpose(RGB_e))), shape)
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.
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.
1090 Returns
1091 -------
1092 :class:`numpy.ndarray`
1093 Colour corrected *RGB* colourspace array.
1095 References
1096 ----------
1097 :cite:`Finlayson2015`
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 """
1113 RGB = as_float_array(RGB)
1114 shape = RGB.shape
1116 RGB = np.reshape(RGB, (-1, 3))
1118 RGB_e = polynomial_expansion_Finlayson2015(RGB, degree, root_polynomial_expansion)
1120 return np.reshape(np.transpose(np.dot(CCM, np.transpose(RGB_e))), shape)
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.
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.
1140 Returns
1141 -------
1142 :class:`numpy.ndarray`
1143 Colour corrected *RGB* colourspace array.
1145 References
1146 ----------
1147 :cite:`Wikipedia2003e`
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 """
1163 RGB = as_float_array(RGB)
1164 shape = RGB.shape
1166 RGB = np.reshape(RGB, (-1, 3))
1168 RGB_e = polynomial_expansion_Vandermonde(RGB, degree)
1170 return np.reshape(np.transpose(np.dot(CCM, np.transpose(RGB_e))), shape)
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.
1183References
1184----------
1185:cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`,
1186:cite:`Wikipedia2003e`
1187"""
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.
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.
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.
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.
1232 Returns
1233 -------
1234 :class:`numpy.ndarray`
1235 Colour corrected *RGB* colourspace array.
1237 References
1238 ----------
1239 :cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`,
1240 :cite:`Wikipedia2003e`
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 """
1256 method = validate_method(method, tuple(APPLY_MATRIX_COLOUR_CORRECTION_METHODS))
1258 function = APPLY_MATRIX_COLOUR_CORRECTION_METHODS[method]
1260 return function(RGB, CCM, **filter_kwargs(function, **kwargs))
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.
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.
1286 Returns
1287 -------
1288 :class:`numpy.ndarray`
1289 Colour corrected *RGB* colourspace array.
1291 References
1292 ----------
1293 :cite:`Cheung2004`, :cite:`Westland2004`
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 """
1305 return apply_matrix_colour_correction_Cheung2004(
1306 RGB, matrix_colour_correction_Cheung2004(M_T, M_R, terms), terms
1307 )
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.
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.
1336 Returns
1337 -------
1338 :class:`numpy.ndarray`
1339 Colour corrected *RGB* colourspace array.
1341 References
1342 ----------
1343 :cite:`Finlayson2015`
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 """
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 )
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.
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.
1384 Returns
1385 -------
1386 :class:`numpy.ndarray`
1387 Colour corrected *RGB* colourspace array.
1389 References
1390 ----------
1391 :cite:`Wikipedia2003e`
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 """
1403 return apply_matrix_colour_correction_Vandermonde(
1404 RGB, matrix_colour_correction_Vandermonde(M_T, M_R, degree), degree
1405 )
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.
1418References
1419----------
1420:cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`,
1421:cite:`Wikipedia2003e`
1422"""
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.
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.
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.
1465 Returns
1466 -------
1467 :class:`numpy.ndarray`
1468 Colour corrected *RGB* colourspace array.
1470 References
1471 ----------
1472 :cite:`Cheung2004`, :cite:`Finlayson2015`, :cite:`Westland2004`,
1473 :cite:`Wikipedia2003e`
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 """
1538 method = validate_method(method, tuple(COLOUR_CORRECTION_METHODS))
1540 function = COLOUR_CORRECTION_METHODS[method]
1542 return function(RGB, M_T, M_R, **filter_kwargs(function, **kwargs))