Coverage for models/din99.py: 60%

53 statements  

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

1""" 

2DIN99 Colourspace and DIN99b, DIN99c, DIN99d Refined Formulas 

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

4 

5Define the *DIN99* colourspace and *DIN99b*, *DIN99c*, *DIN99d* refined 

6formulas transformations. 

7 

8- :func:`colour.Lab_to_DIN99` 

9- :func:`colour.DIN99_to_Lab` 

10- :func:`colour.XYZ_to_DIN99` 

11- :func:`colour.DIN99_to_XYZ` 

12 

13References 

14---------- 

15- :cite:`ASTMInternational2007` : ASTM International. (2007). ASTM D2244-07 - 

16 Standard Practice for Calculation of Color Tolerances and Color Differences 

17 from Instrumentally Measured Color Coordinates: Vol. i (pp. 1-10). 

18 doi:10.1520/D2244-16 

19- :cite:`Cui2002` : Cui, G., Luo, M. R., Rigg, B., Roesler, G., & Witt, K. 

20 (2002). Uniform colour spaces based on the DIN99 colour-difference formula. 

21 Color Research & Application, 27(4), 282-290. doi:10.1002/col.10066 

22""" 

23 

24from __future__ import annotations 

25 

26import typing 

27 

28import numpy as np 

29 

30from colour.algebra import spow 

31from colour.colorimetry import CCS_ILLUMINANTS 

32 

33if typing.TYPE_CHECKING: 

34 from colour.hints import Literal 

35 

36from colour.hints import ( # noqa: TC001 

37 ArrayLike, 

38 Domain1, 

39 Domain100, 

40 Range1, 

41 Range100, 

42) 

43from colour.models import Lab_to_XYZ, XYZ_to_Lab 

44from colour.utilities import ( 

45 CanonicalMapping, 

46 from_range_100, 

47 to_domain_100, 

48 tsplit, 

49 tstack, 

50 validate_method, 

51) 

52 

53__author__ = "Colour Developers" 

54__copyright__ = "Copyright 2013 Colour Developers" 

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

56__maintainer__ = "Colour Developers" 

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

58__status__ = "Production" 

59 

60__all__ = [ 

61 "DIN99_METHODS", 

62 "Lab_to_DIN99", 

63 "DIN99_to_Lab", 

64 "XYZ_to_DIN99", 

65 "DIN99_to_XYZ", 

66] 

67 

68DIN99_METHODS: CanonicalMapping = CanonicalMapping( 

69 { 

70 "ASTMD2244-07": np.array( 

71 [105.509, 0.0158, 16.0, 0.7, 1, 9 / 200, 0.0, 9 / 200] 

72 ), 

73 "DIN99": np.array([105.509, 0.0158, 16.0, 0.7, 1, 9 / 200, 0.0, 9 / 200]), 

74 "DIN99b": np.array([303.67, 0.0039, 26.0, 0.83, 23.0, 0.075, 26.0, 1]), 

75 "DIN99c": np.array([317.65, 0.0037, 0.0, 0.94, 23.0, 0.066, 0.0, 1]), 

76 "DIN99d": np.array([325.22, 0.0036, 50.0, 1.14, 22.5, 0.06, 50.0, 1]), 

77 } 

78) 

79""" 

80Supported *DIN99* colourspace methods, i.e., the coefficients for the *DIN99b*, 

81*DIN99c*, and *DIN99d* refined formulas according to *Cui et al. (2002)*. 

82 

83References 

84---------- 

85:cite:`ASTMInternational2007`, :cite:`Cui2002` 

86""" 

87 

88 

89def Lab_to_DIN99( 

90 Lab: Domain100, 

91 k_E: float = 1, 

92 k_CH: float = 1, 

93 method: ( 

94 Literal["ASTMD2244-07", "DIN99", "DIN99b", "DIN99c", "DIN99d"] | str 

95 ) = "DIN99", 

96) -> Range100: 

97 """ 

98 Convert from *CIE L\\*a\\*b\\** colourspace to *DIN99* colourspace or one 

99 of the *DIN99b*, *DIN99c*, *DIN99d* refined formulas according to 

100 *Cui et al. (2002)*. 

101 

102 Parameters 

103 ---------- 

104 Lab 

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

106 k_E 

107 Parametric factor :math:`K_E` used to compensate for texture and 

108 other specimen presentation effects. 

109 k_CH 

110 Parametric factor :math:`K_{CH}` used to compensate for texture 

111 and other specimen presentation effects. 

112 method 

113 Computation method. 

114 

115 Returns 

116 ------- 

117 :class:`numpy.ndarray` 

118 *DIN99* colourspace array. 

119 

120 Notes 

121 ----- 

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

123 | **Domain** | **Scale - Reference** | **Scale - 1** | 

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

125 | ``Lab`` | 100 | 1 | 

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

127 

128 +------------+------------------------+--------------------+ 

129 | **Range** | **Scale - Reference** | **Scale - 1** | 

130 +============+========================+====================+ 

131 | ``Lab_99`` | 100 | 1 | 

132 +------------+------------------------+--------------------+ 

133 

134 References 

135 ---------- 

136 :cite:`ASTMInternational2007`, :cite:`Cui2002` 

137 

138 Examples 

139 -------- 

140 >>> import numpy as np 

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

142 >>> Lab_to_DIN99(Lab) # doctest: +ELLIPSIS 

143 array([ 53.2282198..., 28.4163465..., 3.8983955...]) 

144 """ 

145 

146 c_1, c_2, c_3, c_4, c_5, c_6, c_7, c_8 = DIN99_METHODS[ 

147 validate_method(method, tuple(DIN99_METHODS)) 

148 ] 

149 

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

151 

152 cos_c = np.cos(np.radians(c_3)) 

153 sin_c = np.sin(np.radians(c_3)) 

154 

155 e = cos_c * a + sin_c * b 

156 f = c_4 * (-sin_c * a + cos_c * b) 

157 G = spow(e**2 + f**2, 0.5) 

158 h_ef = np.arctan2(f, e) + np.radians(c_7) 

159 

160 C_99 = c_5 * (np.log1p(c_6 * G)) / (c_8 * k_CH * k_E) 

161 # Hue angle is unused currently. 

162 # h_99 = np.degrees(h_ef) 

163 a_99 = C_99 * np.cos(h_ef) 

164 b_99 = C_99 * np.sin(h_ef) 

165 L_99 = c_1 * (np.log1p(c_2 * L)) * k_E 

166 

167 Lab_99 = tstack([L_99, a_99, b_99]) 

168 

169 return from_range_100(Lab_99) 

170 

171 

172def DIN99_to_Lab( 

173 Lab_99: Domain100, 

174 k_E: float = 1, 

175 k_CH: float = 1, 

176 method: ( 

177 Literal["ASTMD2244-07", "DIN99", "DIN99b", "DIN99c", "DIN99d"] | str 

178 ) = "DIN99", 

179) -> Range100: 

180 """ 

181 Convert from *DIN99* colourspace or one of the *DIN99b*, *DIN99c*, *DIN99d* 

182 refined formulas according to *Cui et al. (2002)* to *CIE L\\*a\\*b\\** 

183 colourspace. 

184 

185 Parameters 

186 ---------- 

187 Lab_99 

188 *DIN99* colourspace array. 

189 k_E 

190 Parametric factor :math:`K_E` used to compensate for texture 

191 and other specimen presentation effects. 

192 k_CH 

193 Parametric factor :math:`K_{CH}` used to compensate for texture 

194 and other specimen presentation effects. 

195 method 

196 Computation method. 

197 

198 Returns 

199 ------- 

200 :class:`numpy.ndarray` 

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

202 

203 Notes 

204 ----- 

205 +------------+------------------------+--------------------+ 

206 | **Domain** | **Scale - Reference** | **Scale - 1** | 

207 +============+========================+====================+ 

208 | ``Lab_99`` | 100 | 1 | 

209 +------------+------------------------+--------------------+ 

210 

211 +------------+------------------------+--------------------+ 

212 | **Range** | **Scale - Reference** | **Scale - 1** | 

213 +============+========================+====================+ 

214 | ``Lab`` | 100 | 1 | 

215 +------------+------------------------+--------------------+ 

216 

217 References 

218 ---------- 

219 :cite:`ASTMInternational2007`, :cite:`Cui2002` 

220 

221 Examples 

222 -------- 

223 >>> import numpy as np 

224 >>> Lab_99 = np.array([53.22821988, 28.41634656, 3.89839552]) 

225 >>> DIN99_to_Lab(Lab_99) # doctest: +ELLIPSIS 

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

227 """ 

228 

229 c_1, c_2, c_3, c_4, c_5, c_6, c_7, c_8 = DIN99_METHODS[ 

230 validate_method(method, tuple(DIN99_METHODS)) 

231 ] 

232 

233 L_99, a_99, b_99 = tsplit(to_domain_100(Lab_99)) 

234 

235 cos = np.cos(np.radians(c_3)) 

236 sin = np.sin(np.radians(c_3)) 

237 

238 h_99 = np.arctan2(b_99, a_99) - np.radians(c_7) 

239 

240 C_99 = np.hypot(a_99, b_99) 

241 G = np.expm1((c_8 / c_5) * C_99 * k_CH * k_E) / c_6 

242 

243 e = G * np.cos(h_99) 

244 f = G * np.sin(h_99) 

245 

246 a = e * cos - (f / c_4) * sin 

247 b = e * sin + (f / c_4) * cos 

248 L = np.expm1(L_99 * k_E / c_1) / c_2 

249 

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

251 

252 return from_range_100(Lab) 

253 

254 

255def XYZ_to_DIN99( 

256 XYZ: Domain1, 

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

258 "D65" 

259 ], 

260 k_E: float = 1, 

261 k_CH: float = 1, 

262 method: ( 

263 Literal["ASTMD2244-07", "DIN99", "DIN99b", "DIN99c", "DIN99d"] | str 

264 ) = "DIN99", 

265) -> Range100: 

266 """ 

267 Convert from *CIE XYZ* tristimulus values to *DIN99* colourspace or one 

268 of the *DIN99b*, *DIN99c*, *DIN99d* refined formulas according to 

269 *Cui et al. (2002)*. 

270 

271 Parameters 

272 ---------- 

273 XYZ 

274 *CIE XYZ* tristimulus values. 

275 illuminant 

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

277 colourspace array. 

278 k_E 

279 Parametric factor :math:`K_E` used to compensate for texture and 

280 other specimen presentation effects. 

281 k_CH 

282 Parametric factor :math:`K_{CH}` used to compensate for texture and 

283 other specimen presentation effects. 

284 method 

285 Computation method. 

286 

287 Returns 

288 ------- 

289 :class:`numpy.ndarray` 

290 *DIN99* colourspace array. 

291 

292 Notes 

293 ----- 

294 +----------------+-----------------------+-----------------+ 

295 | **Domain** | **Scale - Reference** | **Scale - 1** | 

296 +================+=======================+=================+ 

297 | ``XYZ`` | 1 | 1 | 

298 +----------------+-----------------------+-----------------+ 

299 | ``illuminant`` | 1 | 1 | 

300 +----------------+-----------------------+-----------------+ 

301 

302 +------------+------------------------+--------------------+ 

303 | **Range** | **Scale - Reference** | **Scale - 1** | 

304 +============+========================+====================+ 

305 | ``Lab_99`` | 100 | 1 | 

306 +------------+------------------------+--------------------+ 

307 

308 References 

309 ---------- 

310 :cite:`ASTMInternational2007` 

311 

312 Examples 

313 -------- 

314 >>> import numpy as np 

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

316 >>> XYZ_to_DIN99(XYZ) # doctest: +ELLIPSIS 

317 array([ 53.2282198..., 28.4163465..., 3.8983955...]) 

318 """ 

319 

320 Lab = XYZ_to_Lab(XYZ, illuminant) 

321 

322 return Lab_to_DIN99(Lab, k_E, k_CH, method) 

323 

324 

325def DIN99_to_XYZ( 

326 Lab_99: Domain100, 

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

328 "D65" 

329 ], 

330 k_E: float = 1, 

331 k_CH: float = 1, 

332 method: ( 

333 Literal["ASTMD2244-07", "DIN99", "DIN99b", "DIN99c", "DIN99d"] | str 

334 ) = "DIN99", 

335) -> Range1: 

336 """ 

337 Convert from *DIN99* colourspace or one of the *DIN99b*, *DIN99c*, 

338 *DIN99d* refined formulas according to *Cui et al. (2002)* to 

339 *CIE XYZ* tristimulus values. 

340 

341 Parameters 

342 ---------- 

343 Lab_99 

344 *DIN99* colourspace array. 

345 illuminant 

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

347 colourspace array. 

348 k_E 

349 Parametric factor :math:`K_E` used to compensate for texture 

350 and other specimen presentation effects. 

351 k_CH 

352 Parametric factor :math:`K_{CH}` used to compensate for texture 

353 and other specimen presentation effects. 

354 method 

355 Computation method. 

356 

357 Returns 

358 ------- 

359 :class:`numpy.ndarray` 

360 *CIE XYZ* tristimulus values. 

361 

362 Notes 

363 ----- 

364 +----------------+------------------------+--------------------+ 

365 | **Domain** | **Scale - Reference** | **Scale - 1** | 

366 +================+========================+====================+ 

367 | ``Lab_99`` | 100 | 1 | 

368 +----------------+------------------------+--------------------+ 

369 | ``illuminant`` | 1 | 1 | 

370 +----------------+------------------------+--------------------+ 

371 

372 +----------------+-----------------------+---------------------+ 

373 | **Range** | **Scale - Reference** | **Scale - 1** | 

374 +================+=======================+=====================+ 

375 | ``XYZ`` | 1 | 1 | 

376 +----------------+-----------------------+---------------------+ 

377 

378 References 

379 ---------- 

380 :cite:`ASTMInternational2007` 

381 

382 Examples 

383 -------- 

384 >>> import numpy as np 

385 >>> Lab_99 = np.array([53.22821989, 28.41634656, 3.89839552]) 

386 >>> DIN99_to_XYZ(Lab_99) # doctest: +ELLIPSIS 

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

388 """ 

389 

390 Lab = DIN99_to_Lab(Lab_99, k_E, k_CH, method) 

391 

392 return Lab_to_XYZ(Lab, illuminant)