Coverage for colour/models/prolab.py: 100%

38 statements  

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

1""" 

2ProLab Colourspace 

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

4 

5Define the *ProLab* colourspace transformations. 

6 

7- :func:`colour.XYZ_to_ProLab` 

8- :func:`colour.ProLab_to_XYZ` 

9 

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

16 

17from __future__ import annotations 

18 

19import numpy as np 

20 

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 

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 

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

54 

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

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

57 

58 

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

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. 

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 

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. 

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)