Coverage for models/prolab.py: 47%
38 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"""
2ProLab Colourspace
3==================
5Define the *ProLab* colourspace transformations.
7- :func:`colour.XYZ_to_ProLab`
8- :func:`colour.ProLab_to_XYZ`
10References
11----------
12- :cite:`Konovalenko2021` : Ivan A. Konovalenko, Anna A. Smagina, Dmitry P.
13 Nikolaev, Petr P. Nikolaev. ProLab: perceptually uniform projective colour
14 coordinate system. doi:10.1109/ACCESS.2017
15"""
17from __future__ import annotations
19import numpy as np
21from colour.colorimetry import CCS_ILLUMINANTS
22from colour.hints import ( # noqa: TC001
23 ArrayLike,
24 Domain1,
25 NDArrayFloat,
26 Range1,
27)
28from colour.models import xy_to_xyY, xyY_to_XYZ
29from colour.utilities import as_float_array, from_range_1, ones, to_domain_1
31__author__ = "Colour Developers"
32__copyright__ = "Copyright 2013 Colour Developers"
33__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
34__maintainer__ = "Colour Developers"
35__email__ = "colour-developers@colour-science.org"
36__status__ = "Production"
38__all__ = [
39 "MATRIX_Q",
40 "MATRIX_INVERSE_Q",
41 "ProLab_to_XYZ",
42 "XYZ_to_ProLab",
43]
45MATRIX_Q: NDArrayFloat = np.array(
46 [
47 [75.54, 486.66, 167.39, 0.0],
48 [617.72, -595.45, -22.27, 0.0],
49 [48.34, 194.94, -243.28, 0.0],
50 [0.7554, 3.8666, 1.6739, 1.0],
51 ]
52)
53"""Normalised cone responses to *CIE XYZ* tristimulus values matrix."""
55MATRIX_INVERSE_Q: NDArrayFloat = np.linalg.inv(MATRIX_Q)
56"""Normalised cone responses to *ProLab* colourspace matrix."""
59def projective_transformation(a: ArrayLike, Q: ArrayLike) -> NDArrayFloat:
60 """
61 Apply the specified projective transformation matrix :math:`Q` to the
62 array :math:`a`.
64 Parameters
65 ----------
66 a
67 Array :math:`a` to apply the projective transformation matrix onto.
68 Q
69 Projective transformation matrix :math:`Q`.
71 Returns
72 -------
73 :class:`numpy.ndarray`
74 Transformed array :math:`a`.
75 """
77 a = as_float_array(a)
78 Q = as_float_array(Q)
80 shape = list(a.shape)
81 shape[-1] = shape[-1] + 1
83 M = ones(tuple(shape))
84 M[..., :-1] = a
86 homography = np.dot(M, np.transpose(Q))
87 homography[..., 0:-1] /= homography[..., -1][..., None]
89 return homography[..., 0:-1]
92def XYZ_to_ProLab(
93 XYZ: Domain1,
94 illuminant: ArrayLike = CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"][
95 "D65"
96 ],
97) -> Range1:
98 """
99 Convert from *CIE XYZ* tristimulus values to *ProLab* colourspace.
101 Parameters
102 ----------
103 XYZ
104 *CIE XYZ* tristimulus values.
105 illuminant
106 Reference *illuminant* *CIE xy* chromaticity coordinates or *CIE xyY*
107 colourspace array.
109 Returns
110 -------
111 :class:`numpy.ndarray`
112 *ProLab* colourspace array.
114 Notes
115 -----
116 +------------+-----------------------+-----------------+
117 | **Domain** | **Scale - Reference** | **Scale - 1** |
118 +============+=======================+=================+
119 | ``XYZ`` | 1 | 1 |
120 +------------+-----------------------+-----------------+
122 +------------+-----------------------+-----------------+
123 | **Range** | **Scale - Reference** | **Scale - 1** |
124 +============+=======================+=================+
125 | ``ProLab`` | 1 | 1 |
126 +------------+-----------------------+-----------------+
128 References
129 ----------
130 :cite:`Konovalenko2021`
132 Examples
133 --------
134 >>> Lab = np.array([0.51634019, 0.15469500, 0.06289579])
135 >>> XYZ_to_ProLab(Lab) # doctest: +ELLIPSIS
136 array([ 59.846628... , 115.039635... , 20.1251035...])
137 """
139 XYZ = to_domain_1(XYZ)
140 XYZ_n = xyY_to_XYZ(xy_to_xyY(illuminant))
142 ProLab = projective_transformation(XYZ / XYZ_n, MATRIX_Q)
144 return from_range_1(ProLab)
147def ProLab_to_XYZ(
148 ProLab: Domain1,
149 illuminant: ArrayLike = CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"][
150 "D65"
151 ],
152) -> Range1:
153 """
154 Convert from *ProLab* colourspace to *CIE XYZ* tristimulus values.
156 Parameters
157 ----------
158 ProLab
159 *ProLab* colourspace array.
160 illuminant
161 Reference *illuminant* *CIE xy* chromaticity coordinates or *CIE xyY*
162 colourspace array.
164 Returns
165 -------
166 :class:`numpy.ndarray`
167 *CIE XYZ* tristimulus values.
169 Notes
170 -----
171 +------------+-----------------------+-----------------+
172 | **Domain** | **Scale - Reference** | **Scale - 1** |
173 +============+=======================+=================+
174 | ``ProLab`` | 1 | 1 |
175 +------------+-----------------------+-----------------+
177 +------------+-----------------------+-----------------+
178 | **Range** | **Scale - Reference** | **Scale - 1** |
179 +============+=======================+=================+
180 | ``XYZ`` | 1 | 1 |
181 +------------+-----------------------+-----------------+
183 References
184 ----------
185 :cite:`Konovalenko2021`
187 Examples
188 --------
189 >>> ProLab = np.array([59.8466286, 115.0396354, 20.12510352])
190 >>> ProLab_to_XYZ(ProLab) # doctest: +ELLIPSIS
191 array([ 0.5163401..., 0.154695 ..., 0.0628957...])
192 """
194 ProLab = to_domain_1(ProLab)
195 XYZ_n = xyY_to_XYZ(xy_to_xyY(illuminant))
197 XYZ = projective_transformation(ProLab, MATRIX_INVERSE_Q)
199 XYZ *= XYZ_n
201 return from_range_1(XYZ)