Coverage for appearance/hke.py: 42%

31 statements  

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

1""" 

2Helmholtz—Kohlrausch Effect 

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

4 

5Define methods for estimating the Helmholtz—Kohlrausch effect (HKE). 

6 

7- :attr:`colour.HKE_NAYATANI1997_METHODS`: *Nayatani (1997)* HKE 

8 computation methods, choice between variable achromatic colour (VAC) 

9 and variable chromatic colour (VCC). 

10- :func:`colour.HelmholtzKohlrausch_effect_object_Nayatani1997`: 

11 Compute HKE value for object colours using *Nayatani (1997)* method. 

12- :func:`colour.HelmholtzKohlrausch_effect_luminous_Nayatani1997`: 

13 Compute HKE value for luminous colours using *Nayatani (1997)* method. 

14- :func:`colour.appearance.coefficient_q_Nayatani1997`: 

15 Calculate :math:`q` coefficient for *Nayatani (1997)* HKE estimation. 

16- :func:`colour.appearance.coefficient_K_Br_Nayatani1997`: 

17 Calculate :math:`K_{Br}` coefficient for *Nayatani (1997)* HKE 

18 estimation. 

19 

20References 

21---------- 

22- :cite:`Nayatani1997` : Nayatani, Y. (1997). Simple estimation methods for 

23 the Helmholtz—Kohlrausch effect. Color Research & Application, 22(6), 

24 385-401. doi:10.1002/(SICI)1520-6378(199712)22:6<385::AID-COL6>3.0.CO;2-R 

25""" 

26 

27from __future__ import annotations 

28 

29import typing 

30 

31import numpy as np 

32 

33from colour.algebra import spow 

34 

35if typing.TYPE_CHECKING: 

36 from colour.hints import ArrayLike, DTypeFloat, Literal, NDArray, NDArrayFloat 

37 

38from colour.utilities import CanonicalMapping, as_float_array, tsplit, validate_method 

39 

40__author__ = "Ilia Sibiryakov" 

41__copyright__ = "Copyright 2013 Colour Developers" 

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

43__maintainer__ = "Colour Developers" 

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

45__status__ = "Production" 

46 

47__all__ = [ 

48 "HKE_NAYATANI1997_METHODS", 

49 "HelmholtzKohlrausch_effect_object_Nayatani1997", 

50 "HelmholtzKohlrausch_effect_luminous_Nayatani1997", 

51 "coefficient_q_Nayatani1997", 

52 "coefficient_K_Br_Nayatani1997", 

53] 

54 

55HKE_NAYATANI1997_METHODS = CanonicalMapping( 

56 { 

57 "VAC": -0.1340, 

58 "VCC": -0.8660, 

59 } 

60) 

61HKE_NAYATANI1997_METHODS.__doc__ = """ 

62Define *Nayatani (1997)* *Helmholtz-Kohlrausch effect* (HKE) computation 

63methods: variable achromatic colour ('VAC') and variable chromatic 

64colour ('VCC'). 

65 

66References 

67---------- 

68:cite:`Nayatani1997` 

69""" 

70 

71 

72def HelmholtzKohlrausch_effect_object_Nayatani1997( 

73 uv: ArrayLike, 

74 uv_c: ArrayLike, 

75 L_a: ArrayLike, 

76 method: Literal["VAC", "VCC"] | str = "VCC", 

77) -> NDArrayFloat: 

78 """ 

79 Compute the *Helmholtz-Kohlrausch effect* (HKE) value for object 

80 colours using the *Nayatani (1997)* method. 

81 

82 Parameters 

83 ---------- 

84 uv 

85 *CIE L\\*u\\*v\\** colourspace :math:`uv^p` chromaticity coordinates 

86 of the test samples. 

87 uv_c 

88 *CIE L\\*u\\*v\\** colourspace :math:`uv^p` chromaticity coordinates 

89 of the reference white. 

90 L_a 

91 Adapting luminance in :math:`cd/m^2`. 

92 method 

93 Estimation method to use: *VCC* (Variable-Chromatic-Colour) or 

94 *VAC* (Variable-Achromatic-Colour). 

95 

96 Returns 

97 ------- 

98 :class:`numpy.ndarray` 

99 Luminance factor (:math:`\\Gamma`) values computed using the 

100 *Nayatani (1997)* object colour estimation method. 

101 

102 References 

103 ---------- 

104 :cite:`Nayatani1997` 

105 

106 Examples 

107 -------- 

108 >>> import colour 

109 >>> white = colour.xy_to_Luv_uv(colour.temperature.CCT_to_xy_CIE_D(6504)) 

110 >>> colours = colour.XYZ_to_xy( 

111 ... [colour.wavelength_to_XYZ(430 + i * 50) for i in range(5)] 

112 ... ) 

113 >>> L_adapting = 65 

114 >>> HelmholtzKohlrausch_effect_object_Nayatani1997( # doctest: +ELLIPSIS 

115 ... colour.xy_to_Luv_uv(colours), white, L_adapting 

116 ... ) 

117 array([ 2.2468383..., 1.4619799..., 1.1801658..., 0.9031318..., \ 

1181.7999376...]) 

119 """ 

120 

121 u, v = tsplit(uv) 

122 u_c, v_c = tsplit(uv_c) 

123 

124 method = validate_method(method, tuple(HKE_NAYATANI1997_METHODS)) 

125 

126 K_Br = coefficient_K_Br_Nayatani1997(L_a) 

127 q = coefficient_q_Nayatani1997(np.arctan2(v - v_c, u - u_c)) 

128 S_uv = 13 * np.sqrt((u - u_c) ** 2 + (v - v_c) ** 2) 

129 

130 return 1 + (HKE_NAYATANI1997_METHODS[method] * q + 0.0872 * K_Br) * S_uv 

131 

132 

133def HelmholtzKohlrausch_effect_luminous_Nayatani1997( 

134 uv: ArrayLike, 

135 uv_c: ArrayLike, 

136 L_a: ArrayLike, 

137 method: Literal["VAC", "VCC"] | str = "VCC", 

138) -> NDArrayFloat: 

139 """ 

140 Compute the *HKE* factor for luminous colours using the 

141 *Nayatani (1997)* method. 

142 

143 Parameters 

144 ---------- 

145 uv 

146 *CIE L\\*u\\*v\\** colourspace :math:`uv^p` chromaticity coordinates of 

147 test samples. 

148 uv_c 

149 *CIE L\\*u\\*v\\** colourspace :math:`uv^p` chromaticity coordinates of 

150 reference white. 

151 L_a 

152 Adapting luminance in :math:`cd/m^2`. 

153 method 

154 Estimation method to use: *VCC* (Variable-Chromatic-Colour) or 

155 *VAC* (Variable-Achromatic-Colour). 

156 

157 Returns 

158 ------- 

159 :class:`numpy.ndarray` 

160 Luminance factor (:math:`\\Gamma`) values computed using the 

161 Nayatani luminous colour estimation method. 

162 

163 References 

164 ---------- 

165 :cite:`Nayatani1997` 

166 

167 Examples 

168 -------- 

169 >>> import colour 

170 >>> white = colour.xy_to_Luv_uv(colour.temperature.CCT_to_xy_CIE_D(6504)) 

171 >>> colours = colour.XYZ_to_xy( 

172 ... [colour.wavelength_to_XYZ(430 + i * 50) for i in range(5)] 

173 ... ) 

174 >>> L_adapting = 65 

175 >>> HelmholtzKohlrausch_effect_luminous_Nayatani1997( # doctest: +ELLIPSIS 

176 ... colour.xy_to_Luv_uv(colours), white, L_adapting 

177 ... ) 

178 array([ 7.4460471..., 2.4767159..., 1.4723422..., 0.7938695..., \ 

1794.1828629...]) 

180 """ 

181 

182 return ( 

183 0.4462 

184 * ( 

185 HelmholtzKohlrausch_effect_object_Nayatani1997(uv, uv_c, L_a, method) 

186 + 0.3086 

187 ) 

188 ** 3 

189 ) 

190 

191 

192def coefficient_q_Nayatani1997( 

193 theta: ArrayLike, 

194) -> NDArrayFloat: 

195 """ 

196 Compute the :math:`q(\\theta)` coefficient for *Nayatani (1997)* *HKE* 

197 computations. 

198 

199 The hue angle :math:`\\theta` can be computed as follows: 

200 

201 :math:`tan^{-1}\\cfrac{v' - v'_c}{u' - u'_c}` 

202 

203 where :math:`u'` and :math:`v'` are the *CIE L\\*u\\*v\\** colourspace 

204 :math:`uv^p` chromaticity coordinates of the test chromatic light and 

205 :math:`u'_c` and :math:`v'_c` are the *CIE L\\*u\\*v\\** 

206 colourspace :math:`uv^p` chromaticity coordinates of the reference 

207 white light. 

208 

209 Parameters 

210 ---------- 

211 theta 

212 Hue angle (:math:`\\theta`) in radians. 

213 

214 Returns 

215 ------- 

216 :class:`numpy.ndarray` 

217 :math:`q` coefficient for *Nayatani (1997)* *HKE* methods. 

218 

219 References 

220 ---------- 

221 :cite:`Nayatani1997` 

222 

223 Examples 

224 -------- 

225 This recreates *FIG. A-1*. 

226 

227 >>> import matplotlib.pyplot as plt 

228 >>> angles = [(np.pi * 2 / 100 * i) for i in range(100)] 

229 >>> q_values = coefficient_q_Nayatani1997(angles) 

230 >>> plt.plot(np.array(angles), q_values / (np.pi * 2) * 180) 

231 ... # doctest: +ELLIPSIS 

232 [<matplotlib.lines.Line2D object at 0x...>] 

233 >>> plt.show() # doctest: +SKIP 

234 """ 

235 

236 theta = as_float_array(theta) 

237 

238 theta_2, theta_3, theta_4 = 2 * theta, 3 * theta, 4 * theta 

239 

240 return ( 

241 -0.01585 

242 - 0.03017 * np.cos(theta) 

243 - 0.04556 * np.cos(theta_2) 

244 - 0.02667 * np.cos(theta_3) 

245 - 0.00295 * np.cos(theta_4) 

246 + 0.14592 * np.sin(theta) 

247 + 0.05084 * np.sin(theta_2) 

248 - 0.01900 * np.sin(theta_3) 

249 - 0.00764 * np.sin(theta_4) 

250 ) 

251 

252 

253@typing.overload 

254def coefficient_K_Br_Nayatani1997(L_a: float | DTypeFloat) -> DTypeFloat: ... 

255@typing.overload 

256def coefficient_K_Br_Nayatani1997(L_a: NDArray) -> NDArrayFloat: ... 

257@typing.overload 

258def coefficient_K_Br_Nayatani1997(L_a: ArrayLike) -> DTypeFloat | NDArrayFloat: ... 

259def coefficient_K_Br_Nayatani1997(L_a: ArrayLike) -> DTypeFloat | NDArrayFloat: 

260 """ 

261 Compute the :math:`K_{Br}` coefficient for *Nayatani (1997)* *HKE* 

262 computations. 

263 

264 Parameters 

265 ---------- 

266 L_a 

267 Adapting luminance in :math:`cd/m^2`. 

268 

269 Returns 

270 ------- 

271 :class:`numpy.ndarray` 

272 :math:`K_{Br}` coefficient for *Nayatani (1997)* *HKE* methods. 

273 

274 Notes 

275 ----- 

276 - The :math:`K_{Br}` coefficient is normalised to unity around 

277 :math:`63.66cd/m^2`. 

278 

279 References 

280 ---------- 

281 :cite:`Nayatani1997` 

282 

283 Examples 

284 -------- 

285 >>> L_a_values = [10 + i * 20 for i in range(5)] 

286 >>> coefficient_K_Br_Nayatani1997(L_a_values) # doctest: +ELLIPSIS 

287 array([ 0.7134481..., 0.8781172..., 0.9606248..., 1.0156689..., \ 

2881.0567008...]) 

289 >>> coefficient_K_Br_Nayatani1997(63.66) # doctest: +ELLIPSIS 

290 1.0001284... 

291 """ 

292 

293 L_a_4495 = spow(L_a, 0.4495) 

294 

295 return (L_a_4495 * 6.362 + 6.469) * 0.2717 / (L_a_4495 + 6.469)