Coverage for adaptation/fairchild2020.py: 43%

1"""

2 Von Kries 2020 (vK20) Chromatic Adaptation Model

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

4

5 Define the *Von Kries 2020* (*vK20*) chromatic adaptation model for predicting

6 corresponding colours under different viewing conditions.

7

8- :attr:`colour.adaptation.CONDITIONS_DEGREE_OF_ADAPTATION_VK20`

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

10- :func:`colour.adaptation.chromatic_adaptation_vK20`

11

12 References

13----------

14- :cite:`Fairchild2020` : Fairchild, M. D. (2020). Von Kries 2020:

15 Evolution of degree of chromatic adaptation. Color and Imaging

16 Conference, 28(1), 252-257. doi:10.2352/issn.2169-2629.2020.28.40

17"""

18

19 from __future__ import annotations

20

21 import typing

22 from dataclasses import dataclass

23

24 import numpy as np

25

26 from colour.adaptation import CHROMATIC_ADAPTATION_TRANSFORMS

27 from colour.algebra import sdiv, sdiv_mode, vecmul

28

29 if typing.TYPE_CHECKING:

30 from colour.hints import Literal

31

32 from colour.hints import ( # noqa: TC001

33 ArrayLike,

34 Domain1,

35 NDArrayFloat,

36 Range1,

37)

38 from colour.utilities import (

39 CanonicalMapping,

40 MixinDataclassIterable,

41 as_float_array,

42 from_range_1,

43 get_domain_range_scale,

44 optional,

45 row_as_diagonal,

46 to_domain_1,

47 validate_method,

48)

49

50 __author__ = "Colour Developers"

51 __copyright__ = "Copyright 2013 Colour Developers"

52 __license__ = "New BSD License - https://opensource.org/licenses/BSD-3-Clause"

53 __maintainer__ = "Colour Developers"

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

55 __status__ = "Production"

56

57 __all__ = [

58 "Coefficients_DegreeOfAdaptation_vK20",

59 "CONDITIONS_DEGREE_OF_ADAPTATION_VK20",

60 "TVS_XYZ_R_VK20",

61 "matrix_chromatic_adaptation_vk20",

62 "chromatic_adaptation_vK20",

63]

64

65

66@dataclass(frozen=True)

67 class Coefficients_DegreeOfAdaptation_vK20(MixinDataclassIterable):

68 """

69 Define the degree of adaptation coefficients for the *Von Kries 2020*

70 (*vK20*) chromatic adaptation model.

71

72 Parameters

73 ----------

74 D_n

75 Degree of adaptation for the adapting illuminant.

76 D_r

77 Degree of adaptation for the reference illuminant.

78 D_p

79 Degree of adaptation for the previous illuminant.

80

81 References

82 ----------

83 :cite:`Fairchild2020`

84 """

85

86 D_n: float

87 D_r: float

88 D_p: float

89

90

91 CONDITIONS_DEGREE_OF_ADAPTATION_VK20: CanonicalMapping = CanonicalMapping(

92 {

93 "Fairchild": Coefficients_DegreeOfAdaptation_vK20(0.7, 0.3, 0),

94 "Hands": Coefficients_DegreeOfAdaptation_vK20(0.95, 0.05, 0),

95 "No Hands": Coefficients_DegreeOfAdaptation_vK20(0.85, 0.15, 0),

96 "Ordinal 1st": Coefficients_DegreeOfAdaptation_vK20(0.9, 0.1, 0),

97 "Ordinal 2nd": Coefficients_DegreeOfAdaptation_vK20(0.8, 0.1, 0.1),

98 "Reversibility Trial 1st": Coefficients_DegreeOfAdaptation_vK20(0.7, 0.3, 0.1),

99 "Reversibility Trial 2nd": Coefficients_DegreeOfAdaptation_vK20(0.6, 0.3, 0.1),

100 "Ma et al.": Coefficients_DegreeOfAdaptation_vK20(1 / 3, 1 / 3, 1 / 3),

101 "Hunt & Winter": Coefficients_DegreeOfAdaptation_vK20(0.6, 0.2, 0.2),

102 "Hurvich & Jameson": Coefficients_DegreeOfAdaptation_vK20(0.7, 0.3, 0),

103 "Simple von Kries": Coefficients_DegreeOfAdaptation_vK20(1, 0, 0),

104 }

105)

106 CONDITIONS_DEGREE_OF_ADAPTATION_VK20.__doc__ = """

107 Define the degree of adaptation coefficient conditions for the *Von Kries 2020*

108(*vK20*) chromatic adaptation model.

109

110 References

111----------

112:cite:`Fairchild2020`

113"""

114

115 TVS_XYZ_R_VK20 = np.array([0.97941176, 1.00000000, 1.73235294])

116"""

117*Von Kries 2020* (*vK20*) reference illuminant (taken to be

118 u' = 0.185, v' = 0.425, approximately 15000K, sky blue).

119

120 References

121----------

122:cite:`Fairchild2020`

123"""

124

125

126 def matrix_chromatic_adaptation_vk20(

127 XYZ_p: ArrayLike,

128 XYZ_n: ArrayLike,

129 XYZ_r: ArrayLike = TVS_XYZ_R_VK20,

130 transform: Literal[

131 "Bianco 2010",

132 "Bianco PC 2010",

133 "Bradford",

134 "CAT02 Brill 2008",

135 "CAT02",

136 "CAT16",

137 "CMCCAT2000",

138 "CMCCAT97",

139 "Fairchild",

140 "Sharp",

141 "Von Kries",

142 "XYZ Scaling",

143 ]

144 | str = "CAT02",

145 coefficients: Coefficients_DegreeOfAdaptation_vK20 = (

146 CONDITIONS_DEGREE_OF_ADAPTATION_VK20["Fairchild"]

147 ),

148) -> NDArrayFloat:

149 """

150 Compute the chromatic adaptation matrix from previous viewing conditions

151 to adapting viewing conditions using the *Von Kries 2020* (*vK20*)

152 method.

153

154 Parameters

155 ----------

156 XYZ_p

157 *CIE XYZ* tristimulus values of the whitepoint under previous viewing

158 conditions.

159 XYZ_n

160 *CIE XYZ* tristimulus values of the whitepoint under adapting viewing

161 conditions.

162 XYZ_r

163 *CIE XYZ* tristimulus values of the whitepoint under reference viewing

164 conditions.

165 transform

166 Chromatic adaptation transform.

167 coefficients

168 *vK20* degree of adaptation coefficients.

169

170 Returns

171 -------

172 :class:`numpy.ndarray`

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

174

175 Notes

176 -----

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

178 | **Domain** | **Scale - Reference** | **Scale - 1** |

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

180 | ``XYZ_p`` | 1 | 1 |

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

182 | ``XYZ_n`` | 1 | 1 |

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

184 | ``XYZ_r`` | 1 | 1 |

185 +------------+-----------------------+---------------+

186

187 References

188 ----------

189 :cite:`Fairchild2020`

190

191 Examples

192 --------

193 >>> XYZ_p = np.array([0.95045593, 1.00000000, 1.08905775])

194 >>> XYZ_n = np.array([0.96429568, 1.00000000, 0.82510460])

195 >>> matrix_chromatic_adaptation_vk20(XYZ_p, XYZ_n)

196 ... # doctest: +ELLIPSIS

197 array([[ 1.0279139...e+00, 2.9137117...e-02, -2.2794068...e-02],

198 [ 2.0702840...e-02, 9.9005316...e-01, -9.2143464...e-03],

199 [ -6.3758553...e-04, -1.1577319...e-03, 9.1296320...e-01]])

200

201 Using *Bradford* transform:

202

203 >>> XYZ_p = np.array([0.95045593, 1.00000000, 1.08905775])

204 >>> XYZ_n = np.array([0.96429568, 1.00000000, 0.82510460])

205 >>> transform = "Bradford"

206 >>> matrix_chromatic_adaptation_vk20(XYZ_p, XYZ_n, transform=transform)

207 ... # doctest: +ELLIPSIS

208 array([[ 1.0367230..., 0.0195580..., -0.0219321...],

209 [ 0.0276321..., 0.9822296..., -0.0082419...],

210 [-0.0029508..., 0.0040690..., 0.9102430...]])

211 """

212

213 XYZ_n = as_float_array(XYZ_n)

214 XYZ_r = as_float_array(XYZ_r)

215 XYZ_p = as_float_array(XYZ_p)

216

217 transform = validate_method(

218 transform,

219 tuple(CHROMATIC_ADAPTATION_TRANSFORMS),

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

221 )

222

223 M = CHROMATIC_ADAPTATION_TRANSFORMS[transform]

224

225 D_n, D_r, D_p = coefficients.values

226

227 LMS_n = vecmul(M, XYZ_n)

228 LMS_r = vecmul(M, XYZ_r)

229 LMS_p = vecmul(M, XYZ_p)

230

231 with sdiv_mode():

232 D = row_as_diagonal(sdiv(1, (D_n * LMS_n + D_r * LMS_r + D_p * LMS_p)))

233

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

235

236 return np.matmul(M_CAT, M)

237

238

239 def chromatic_adaptation_vK20(

240 XYZ: Domain1,

241 XYZ_p: Domain1,

242 XYZ_n: Domain1,

243 XYZ_r: ArrayLike | None = None,

244 transform: Literal[

245 "Bianco 2010",

246 "Bianco PC 2010",

247 "Bradford",

248 "CAT02 Brill 2008",

249 "CAT02",

250 "CAT16",

251 "CMCCAT2000",

252 "CMCCAT97",

253 "Fairchild",

254 "Sharp",

255 "Von Kries",

256 "XYZ Scaling",

257 ]

258 | str = "CAT02",

259 coefficients: Coefficients_DegreeOfAdaptation_vK20 = (

260 CONDITIONS_DEGREE_OF_ADAPTATION_VK20["Fairchild"]

261 ),

262) -> Range1:

263 """

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

265 viewing conditions to reference viewing conditions using the

266 *Von Kries 2020* (*vK20*) chromatic adaptation model.

267

268 Parameters

269 ----------

270 XYZ

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

272 XYZ_p

273 Previous viewing conditions *CIE XYZ* tristimulus values of the

274 whitepoint.

275 XYZ_n

276 Adapting viewing conditions *CIE XYZ* tristimulus values of the

277 whitepoint.

278 XYZ_r

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

280 whitepoint.

281 transform

282 Chromatic adaptation transform.

283 coefficients

284 *vK20* degree of adaptation coefficients.

285

286 Returns

287 -------

288 :class:`numpy.ndarray`

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

290

291 Notes

292 -----

293 +------------+-----------------------+---------------+

294 | **Domain** | **Scale - Reference** | **Scale - 1** |

295 +============+=======================+===============+

296 | ``XYZ`` | 1 | 1 |

297 +------------+-----------------------+---------------+

298 | ``XYZ_p`` | 1 | 1 |

299 +------------+-----------------------+---------------+

300 | ``XYZ_n`` | 1 | 1 |

301 +------------+-----------------------+---------------+

302 | ``XYZ_r`` | 1 | 1 |

303 +------------+-----------------------+---------------+

304

305 +------------+-----------------------+---------------+

306 | **Range** | **Scale - Reference** | **Scale - 1** |

307 +============+=======================+===============+

308 | ``XYZ_a`` | 1 | 1 |

309 +------------+-----------------------+---------------+

310

311 References

312 ----------

313 :cite:`Fairchild2020`

314

315 Examples

316 --------

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

318 >>> XYZ_p = np.array([0.95045593, 1.00000000, 1.08905775])

319 >>> XYZ_n = np.array([0.96429568, 1.00000000, 0.82510460])

320 >>> chromatic_adaptation_vK20(XYZ, XYZ_p, XYZ_n)

321 ... # doctest: +ELLIPSIS

322 array([ 0.2146884..., 0.1245616..., 0.0466255...])

323

324 Using *Bradford* transform:

325

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

327 >>> XYZ_p = np.array([0.95045593, 1.00000000, 1.08905775])

328 >>> XYZ_n = np.array([0.96429568, 1.00000000, 0.82510460])

329 >>> transform = "Bradford"

330 >>> chromatic_adaptation_vK20(XYZ, XYZ_p, XYZ_n, transform=transform)

331 ... # doctest: +ELLIPSIS

332 array([ 0.2153837..., 0.1250885..., 0.0466455...])

333 """

334

335 XYZ = to_domain_1(XYZ)

336 XYZ_p = to_domain_1(XYZ_p)

337 XYZ_n = to_domain_1(XYZ_n)

338 XYZ_r = to_domain_1(

339 optional(

340 XYZ_r,

341 TVS_XYZ_R_VK20

342 if get_domain_range_scale() == "reference"

343 else TVS_XYZ_R_VK20 / 100,

344 )

345 )

346

347 M_CAT = matrix_chromatic_adaptation_vk20(

348 XYZ_p, XYZ_n, XYZ_r, transform, coefficients

349 )

350 XYZ_a = vecmul(M_CAT, XYZ)

351

352 return from_range_1(XYZ_a)