Coverage for models/prolab.py: 47%

1"""

2 ProLab Colourspace

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

4

5 Define the *ProLab* colourspace transformations.

6

7- :func:`colour.XYZ_to_ProLab`

8- :func:`colour.ProLab_to_XYZ`

9

10 References

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"""

16

17 from __future__ import annotations

18

19 import numpy as np

20

21 from colour.colorimetry import CCS_ILLUMINANTS

22 from colour.hints import ( # noqa: TC001

23 ArrayLike,

24 Domain1,

25 NDArrayFloat,

26 Range1,

27)

28 from colour.models import xy_to_xyY, xyY_to_XYZ

29 from colour.utilities import as_float_array, from_range_1, ones, to_domain_1

30

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"

37

38 __all__ = [

39 "MATRIX_Q",

40 "MATRIX_INVERSE_Q",

41 "ProLab_to_XYZ",

42 "XYZ_to_ProLab",

43]

44

45 MATRIX_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."""

54

55 MATRIX_INVERSE_Q: NDArrayFloat = np.linalg.inv(MATRIX_Q)

56"""Normalised cone responses to *ProLab* colourspace matrix."""

57

58

59 def projective_transformation(a: ArrayLike, Q: ArrayLike) -> NDArrayFloat:

60 """

61 Apply the specified projective transformation matrix :math:`Q` to the

62 array :math:`a`.

63

64 Parameters

65 ----------

66 a

67 Array :math:`a` to apply the projective transformation matrix onto.

68 Q

69 Projective transformation matrix :math:`Q`.

70

71 Returns

72 -------

73 :class:`numpy.ndarray`

74 Transformed array :math:`a`.

75 """

76

77 a = as_float_array(a)

78 Q = as_float_array(Q)

79

80 shape = list(a.shape)

81 shape[-1] = shape[-1] + 1

82

83 M = ones(tuple(shape))

84 M[..., :-1] = a

85

86 homography = np.dot(M, np.transpose(Q))

87 homography[..., 0:-1] /= homography[..., -1][..., None]

88

89 return homography[..., 0:-1]

90

91

92 def 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.

100

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.

108

109 Returns

110 -------

111 :class:`numpy.ndarray`

112 *ProLab* colourspace array.

113

114 Notes

115 -----

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

117 | **Domain** | **Scale - Reference** | **Scale - 1** |

118 +============+=======================+=================+

119 | ``XYZ`` | 1 | 1 |

120 +------------+-----------------------+-----------------+

121

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

123 | **Range** | **Scale - Reference** | **Scale - 1** |

124 +============+=======================+=================+

125 | ``ProLab`` | 1 | 1 |

126 +------------+-----------------------+-----------------+

127

128 References

129 ----------

130 :cite:`Konovalenko2021`

131

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 """

138

139 XYZ = to_domain_1(XYZ)

140 XYZ_n = xyY_to_XYZ(xy_to_xyY(illuminant))

141

142 ProLab = projective_transformation(XYZ / XYZ_n, MATRIX_Q)

143

144 return from_range_1(ProLab)

145

146

147 def 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.

155

156 Parameters

157 ----------

158 ProLab

159 *ProLab* colourspace array.

160 illuminant

161 Reference *illuminant* *CIE xy* chromaticity coordinates or *CIE xyY*

162 colourspace array.

163

164 Returns

165 -------

166 :class:`numpy.ndarray`

167 *CIE XYZ* tristimulus values.

168

169 Notes

170 -----

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

172 | **Domain** | **Scale - Reference** | **Scale - 1** |

173 +============+=======================+=================+

174 | ``ProLab`` | 1 | 1 |

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

176

177 +------------+-----------------------+-----------------+

178 | **Range** | **Scale - Reference** | **Scale - 1** |

179 +============+=======================+=================+

180 | ``XYZ`` | 1 | 1 |

181 +------------+-----------------------+-----------------+

182

183 References

184 ----------

185 :cite:`Konovalenko2021`

186

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 """

193

194 ProLab = to_domain_1(ProLab)

195 XYZ_n = xyY_to_XYZ(xy_to_xyY(illuminant))

196

197 XYZ = projective_transformation(ProLab, MATRIX_INVERSE_Q)

198

199 XYZ *= XYZ_n

200

201 return from_range_1(XYZ)