Coverage for models/cie_lab.py: 59%

34 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-16 22:49 +1300

1""" 

2CIE L*a*b* Colourspace 

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

4 

5Define the *CIE L\\*a\\*b\\** colourspace transformations. 

6 

7- :func:`colour.XYZ_to_Lab` 

8- :func:`colour.Lab_to_XYZ` 

9 

10References 

11---------- 

12- :cite:`CIETC1-482004m` : CIE TC 1-48. (2004). CIE 1976 uniform colour 

13 spaces. In CIE 015:2004 Colorimetry, 3rd Edition (p. 24). 

14 ISBN:978-3-901906-33-6 

15""" 

16 

17from __future__ import annotations 

18 

19from colour.colorimetry import ( 

20 CCS_ILLUMINANTS, 

21 intermediate_lightness_function_CIE1976, 

22 intermediate_luminance_function_CIE1976, 

23) 

24from colour.hints import ( # noqa: TC001 

25 ArrayLike, 

26 Domain1, 

27 Domain100, 

28 Range1, 

29 Range100, 

30) 

31from colour.models import xy_to_xyY, xyY_to_XYZ 

32from colour.utilities import ( 

33 from_range_1, 

34 from_range_100, 

35 to_domain_1, 

36 to_domain_100, 

37 tsplit, 

38 tstack, 

39) 

40 

41__author__ = "Colour Developers" 

42__copyright__ = "Copyright 2013 Colour Developers" 

43__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause" 

44__maintainer__ = "Colour Developers" 

45__email__ = "colour-developers@colour-science.org" 

46__status__ = "Production" 

47 

48__all__ = [ 

49 "XYZ_to_Lab", 

50 "Lab_to_XYZ", 

51] 

52 

53 

54def XYZ_to_Lab( 

55 XYZ: Domain1, 

56 illuminant: ArrayLike = CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"][ 

57 "D65" 

58 ], 

59) -> Range100: 

60 """ 

61 Convert from *CIE XYZ* tristimulus values to *CIE L\\*a\\*b\\** 

62 colourspace. 

63 

64 Parameters 

65 ---------- 

66 XYZ 

67 *CIE XYZ* tristimulus values. 

68 illuminant 

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

70 colourspace array. 

71 

72 Returns 

73 ------- 

74 :class:`numpy.ndarray` 

75 *CIE L\\*a\\*b\\** colourspace array. 

76 

77 Notes 

78 ----- 

79 +----------------+-----------------------+-----------------+ 

80 | **Domain** | **Scale - Reference** | **Scale - 1** | 

81 +================+=======================+=================+ 

82 | ``XYZ`` | 1 | 1 | 

83 +----------------+-----------------------+-----------------+ 

84 | ``illuminant`` | 1 | 1 | 

85 +----------------+-----------------------+-----------------+ 

86 

87 +----------------+-----------------------+-----------------+ 

88 | **Range** | **Scale - Reference** | **Scale - 1** | 

89 +================+=======================+=================+ 

90 | ``Lab`` | 100 | 1 | 

91 +----------------+-----------------------+-----------------+ 

92 

93 References 

94 ---------- 

95 :cite:`CIETC1-482004m` 

96 

97 Examples 

98 -------- 

99 >>> import numpy as np 

100 >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) 

101 >>> XYZ_to_Lab(XYZ) # doctest: +ELLIPSIS 

102 array([ 41.5278752..., 52.6385830..., 26.9231792...]) 

103 """ 

104 

105 X, Y, Z = tsplit(to_domain_1(XYZ)) 

106 X_n, Y_n, Z_n = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant))) 

107 

108 f_X_X_n = intermediate_lightness_function_CIE1976(X, X_n) 

109 f_Y_Y_n = intermediate_lightness_function_CIE1976(Y, Y_n) 

110 f_Z_Z_n = intermediate_lightness_function_CIE1976(Z, Z_n) 

111 

112 L = 116 * f_Y_Y_n - 16 

113 a = 500 * (f_X_X_n - f_Y_Y_n) 

114 b = 200 * (f_Y_Y_n - f_Z_Z_n) 

115 

116 Lab = tstack([L, a, b]) 

117 

118 return from_range_100(Lab) 

119 

120 

121def Lab_to_XYZ( 

122 Lab: Domain100, 

123 illuminant: ArrayLike = CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"][ 

124 "D65" 

125 ], 

126) -> Range1: 

127 """ 

128 Convert from *CIE L\\*a\\*b\\** colourspace to *CIE XYZ* tristimulus 

129 values. 

130 

131 Parameters 

132 ---------- 

133 Lab 

134 *CIE L\\*a\\*b\\** colourspace array. 

135 illuminant 

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

137 colourspace array. 

138 

139 Returns 

140 ------- 

141 :class:`numpy.ndarray` 

142 *CIE XYZ* tristimulus values. 

143 

144 Notes 

145 ----- 

146 +----------------+-----------------------+-----------------+ 

147 | **Domain** | **Scale - Reference** | **Scale - 1** | 

148 +================+=======================+=================+ 

149 | ``Lab`` | 100 | 1 | 

150 +----------------+-----------------------+-----------------+ 

151 | ``illuminant`` | 1 | 1 | 

152 +----------------+-----------------------+-----------------+ 

153 

154 +----------------+-----------------------+-----------------+ 

155 | **Range** | **Scale - Reference** | **Scale - 1** | 

156 +================+=======================+=================+ 

157 | ``XYZ`` | 1 | 1 | 

158 +----------------+-----------------------+-----------------+ 

159 

160 References 

161 ---------- 

162 :cite:`CIETC1-482004m` 

163 

164 Examples 

165 -------- 

166 >>> import numpy as np 

167 >>> Lab = np.array([41.52787529, 52.63858304, 26.92317922]) 

168 >>> Lab_to_XYZ(Lab) # doctest: +ELLIPSIS 

169 array([ 0.2065400..., 0.1219722..., 0.0513695...]) 

170 """ 

171 

172 L, a, b = tsplit(to_domain_100(Lab)) 

173 

174 X_n, Y_n, Z_n = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant))) 

175 

176 f_Y_Y_n = (L + 16) / 116 

177 f_X_X_n = a / 500 + f_Y_Y_n 

178 f_Z_Z_n = f_Y_Y_n - b / 200 

179 

180 X = intermediate_luminance_function_CIE1976(f_X_X_n, X_n) 

181 Y = intermediate_luminance_function_CIE1976(f_Y_Y_n, Y_n) 

182 Z = intermediate_luminance_function_CIE1976(f_Z_Z_n, Z_n) 

183 

184 XYZ = tstack([X, Y, Z]) 

185 

186 return from_range_1(XYZ)