Coverage for colour/adaptation/vonkries.py: 100%

31 statements  

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

1""" 

2Von Kries Chromatic Adaptation Model 

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

4 

5Define the *Von Kries* chromatic adaptation model for predicting corresponding 

6colours under different viewing conditions. 

7 

8- :func:`colour.adaptation.matrix_chromatic_adaptation_VonKries` 

9- :func:`colour.adaptation.chromatic_adaptation_VonKries` 

10 

11References 

12---------- 

13- :cite:`Fairchild2013t` : Fairchild, M. D. (2013). Chromatic Adaptation 

14 Models. In Color Appearance Models (3rd ed., pp. 4179-4252). Wiley. 

15 ISBN:B00DAYO8E2 

16""" 

17 

18from __future__ import annotations 

19 

20import typing 

21 

22import numpy as np 

23 

24from colour.adaptation import CHROMATIC_ADAPTATION_TRANSFORMS 

25from colour.algebra import sdiv, sdiv_mode, vecmul 

26 

27if typing.TYPE_CHECKING: 

28 from colour.hints import LiteralChromaticAdaptationTransform 

29 

30from colour.hints import ( # noqa: TC001 

31 ArrayLike, 

32 Domain1, 

33 NDArrayFloat, 

34 Range1, 

35) 

36from colour.utilities import ( 

37 as_float_array, 

38 from_range_1, 

39 row_as_diagonal, 

40 to_domain_1, 

41 validate_method, 

42) 

43 

44__author__ = "Colour Developers" 

45__copyright__ = "Copyright 2013 Colour Developers" 

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

47__maintainer__ = "Colour Developers" 

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

49__status__ = "Production" 

50 

51__all__ = [ 

52 "matrix_chromatic_adaptation_VonKries", 

53 "chromatic_adaptation_VonKries", 

54] 

55 

56 

57def matrix_chromatic_adaptation_VonKries( 

58 XYZ_w: ArrayLike, 

59 XYZ_wr: ArrayLike, 

60 transform: LiteralChromaticAdaptationTransform | str = "CAT02", 

61) -> NDArrayFloat: 

62 """ 

63 Compute the chromatic adaptation matrix from test viewing conditions 

64 to reference viewing conditions. 

65 

66 Parameters 

67 ---------- 

68 XYZ_w 

69 Test viewing conditions *CIE XYZ* tristimulus values of the 

70 whitepoint. 

71 XYZ_wr 

72 Reference viewing conditions *CIE XYZ* tristimulus values of the 

73 whitepoint. 

74 transform 

75 Chromatic adaptation transform. 

76 

77 Returns 

78 ------- 

79 :class:`numpy.ndarray` 

80 Chromatic adaptation matrix :math:`M_{cat}`. 

81 

82 Notes 

83 ----- 

84 +------------+-----------------------+---------------+ 

85 | **Domain** | **Scale - Reference** | **Scale - 1** | 

86 +============+=======================+===============+ 

87 | ``XYZ_w`` | 1 | 1 | 

88 +------------+-----------------------+---------------+ 

89 | ``XYZ_wr`` | 1 | 1 | 

90 +------------+-----------------------+---------------+ 

91 

92 References 

93 ---------- 

94 :cite:`Fairchild2013t` 

95 

96 Examples 

97 -------- 

98 >>> XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775]) 

99 >>> XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460]) 

100 >>> matrix_chromatic_adaptation_VonKries(XYZ_w, XYZ_wr) 

101 ... # doctest: +ELLIPSIS 

102 array([[ 1.0425738..., 0.0308910..., -0.0528125...], 

103 [ 0.0221934..., 1.0018566..., -0.0210737...], 

104 [-0.0011648..., -0.0034205..., 0.7617890...]]) 

105 

106 Using *Bradford* transform: 

107 

108 >>> XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775]) 

109 >>> XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460]) 

110 >>> transform = "Bradford" 

111 >>> matrix_chromatic_adaptation_VonKries(XYZ_w, XYZ_wr, transform) 

112 ... # doctest: +ELLIPSIS 

113 array([[ 1.0479297..., 0.0229468..., -0.0501922...], 

114 [ 0.0296278..., 0.9904344..., -0.0170738...], 

115 [-0.0092430..., 0.0150551..., 0.7518742...]]) 

116 """ 

117 

118 XYZ_w = as_float_array(XYZ_w) 

119 XYZ_wr = as_float_array(XYZ_wr) 

120 

121 transform = validate_method( 

122 transform, 

123 tuple(CHROMATIC_ADAPTATION_TRANSFORMS), 

124 '"{0}" chromatic adaptation transform is invalid, it must be one of {1}!', 

125 ) 

126 

127 M = CHROMATIC_ADAPTATION_TRANSFORMS[transform] 

128 

129 RGB_w = vecmul(M, XYZ_w) 

130 RGB_wr = vecmul(M, XYZ_wr) 

131 

132 with sdiv_mode(): 

133 D = sdiv(RGB_wr, RGB_w) 

134 

135 D = row_as_diagonal(D) 

136 

137 M_CAT = np.matmul(np.linalg.inv(M), D) 

138 

139 return np.matmul(M_CAT, M) 

140 

141 

142def chromatic_adaptation_VonKries( 

143 XYZ: Domain1, 

144 XYZ_w: ArrayLike, 

145 XYZ_wr: ArrayLike, 

146 transform: LiteralChromaticAdaptationTransform | str = "CAT02", 

147) -> Range1: 

148 """ 

149 Adapt the specified stimulus *CIE XYZ* tristimulus values from test 

150 viewing conditions to reference viewing conditions using the *Von Kries* 

151 chromatic adaptation model. 

152 

153 Parameters 

154 ---------- 

155 XYZ 

156 *CIE XYZ* tristimulus values of the stimulus to adapt. 

157 XYZ_w 

158 Test viewing conditions *CIE XYZ* tristimulus values of the 

159 whitepoint. 

160 XYZ_wr 

161 Reference viewing conditions *CIE XYZ* tristimulus values of the 

162 whitepoint. 

163 transform 

164 Chromatic adaptation transform. 

165 

166 Returns 

167 ------- 

168 :class:`numpy.ndarray` 

169 *CIE XYZ* tristimulus values of the stimulus corresponding colour. 

170 

171 Notes 

172 ----- 

173 +------------+-----------------------+---------------+ 

174 | **Domain** | **Scale - Reference** | **Scale - 1** | 

175 +============+=======================+===============+ 

176 | ``XYZ`` | 1 | 1 | 

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

178 | ``XYZ_n`` | 1 | 1 | 

179 +------------+-----------------------+---------------+ 

180 | ``XYZ_r`` | 1 | 1 | 

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

182 

183 +------------+-----------------------+---------------+ 

184 | **Range** | **Scale - Reference** | **Scale - 1** | 

185 +============+=======================+===============+ 

186 | ``XYZ_a`` | 1 | 1 | 

187 +------------+-----------------------+---------------+ 

188 

189 References 

190 ---------- 

191 :cite:`Fairchild2013t` 

192 

193 Examples 

194 -------- 

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

196 >>> XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775]) 

197 >>> XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460]) 

198 >>> chromatic_adaptation_VonKries(XYZ, XYZ_w, XYZ_wr) # doctest: +ELLIPSIS 

199 array([ 0.2163881..., 0.1257 , 0.0384749...]) 

200 

201 Using *Bradford* transform: 

202 

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

204 >>> XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775]) 

205 >>> XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460]) 

206 >>> transform = "Bradford" 

207 >>> chromatic_adaptation_VonKries(XYZ, XYZ_w, XYZ_wr, transform) 

208 ... # doctest: +ELLIPSIS 

209 array([ 0.2166600..., 0.1260477..., 0.0385506...]) 

210 """ 

211 

212 XYZ = to_domain_1(XYZ) 

213 

214 M_CAT = matrix_chromatic_adaptation_VonKries(XYZ_w, XYZ_wr, transform) 

215 XYZ_a = vecmul(M_CAT, XYZ) 

216 

217 return from_range_1(XYZ_a)