Coverage for difference/delta_e.py: 76%
134 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 22:49 +1300
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 22:49 +1300
1"""
2:math:`\\Delta E^*_{ab}` - Delta E Colour Difference
3====================================================
5Define the :math:`\\Delta E^*_{ab}` colour difference computation objects.
7- :attr:`colour.difference.JND_CIE1976`
8- :func:`colour.difference.delta_E_CIE1976`
9- :func:`colour.difference.delta_E_CIE1994`
10- :func:`colour.difference.delta_E_CIE2000`
11- :func:`colour.difference.delta_E_CMC`
12- :func:`colour.difference.delta_E_ITP`
13- :func:`colour.difference.delta_E_HyAB`
14- :func:`colour.difference.delta_E_HyCH`
16References
17----------
18- :cite:`Abasi2020a` : Abasi, S., Amani Tehran, M., & Fairchild, M. D. (2020).
19 Distance metrics for very large color differences. Color Research &
20 Application, 45(2), 208-223. doi:10.1002/col.22451
21- :cite:`InternationalTelecommunicationUnion2019` : International
22 Telecommunication Union. (2019). Recommendation ITU-R BT.2124-0 -
23 Objective metric for the assessment of the potential visibility of colour
24 differences in television (pp. 1-36).
25 https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2124-0-201901-I!!PDF-E.pdf
26- :cite:`Lindbloom2003c` : Lindbloom, B. (2003). Delta E (CIE 1976).
27 Retrieved February 24, 2014, from
28 http://brucelindbloom.com/Eqn_DeltaE_CIE76.html
29- :cite:`Lindbloom2009f` : Lindbloom, B. (2009). Delta E (CMC). Retrieved
30 February 24, 2014, from http://brucelindbloom.com/Eqn_DeltaE_CMC.html
31- :cite:`Lindbloom2011a` : Lindbloom, B. (2011). Delta E (CIE 1994).
32 Retrieved February 24, 2014, from
33 http://brucelindbloom.com/Eqn_DeltaE_CIE94.html
34- :cite:`Melgosa2013b` : Melgosa, M. (2013). CIE / ISO new standard:
35 CIEDE2000. http://www.color.org/events/colorimetry/\
36Melgosa_CIEDE2000_Workshop-July4.pdf
37- :cite:`Sharma2005b` : Sharma, G., Wu, W., & Dalal, E. N. (2005). The
38 CIEDE2000 color-difference formula: Implementation notes, supplementary
39 test data, and mathematical observations. Color Research & Application,
40 30(1), 21-30. doi:10.1002/col.20070
41- :cite:`Mokrzycki2011` : Mokrzycki, W., & Tatol, M. (2011). Color difference
42 Delta E - A survey. Machine Graphics and Vision, 20, 383-411.
43"""
45from __future__ import annotations
47from dataclasses import astuple, dataclass, field
49import numpy as np
51from colour.algebra import euclidean_distance
52from colour.hints import ( # noqa: TC001
53 Domain1,
54 Domain100,
55 NDArrayFloat,
56)
57from colour.utilities import (
58 MixinDataclassArithmetic,
59 as_float,
60 to_domain_100,
61 tsplit,
62 zeros,
63)
64from colour.utilities.documentation import DocstringFloat, is_documentation_building
66__author__ = "Colour Developers"
67__copyright__ = "Copyright 2013 Colour Developers"
68__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
69__maintainer__ = "Colour Developers"
70__email__ = "colour-developers@colour-science.org"
71__status__ = "Production"
73__all__ = [
74 "JND_CIE1976",
75 "delta_E_CIE1976",
76 "delta_E_CIE1994",
77 "intermediate_attributes_CIE2000",
78 "delta_E_CIE2000",
79 "delta_E_CMC",
80 "delta_E_ITP",
81 "delta_E_HyAB",
82 "delta_E_HyCH",
83]
85JND_CIE1976 = 2.3
86if is_documentation_building(): # pragma: no cover
87 JND_CIE1976 = DocstringFloat(JND_CIE1976)
88 JND_CIE1976.__doc__ = """
89Just Noticeable Difference (JND) according to *CIE 1976* colour difference
90formula, i.e., Euclidean distance in *CIE L\\*a\\*b\\** colourspace.
92Notes
93-----
94A standard observer sees the difference in colour as follows:
96- 0 < :math:`\\Delta E^*_{ab}` < 1 : Observer does not notice the difference.
97- 1 < :math:`\\Delta E^*_{ab}` < 2 : Only experienced observer can notice the
98 difference.
99- 2 < :math:`\\Delta E^*_{ab}` < 3:5 : Unexperienced observer also notices
100 the difference.
101- 3:5 < :math:`\\Delta E^*_{ab}` < 5 : Clear difference in colour is noticed.
102- 5 < :math:`\\Delta E^*_{ab}` : Observer notices two different colours.
104References
105----------
106:cite:`Mokrzycki2011`
107"""
110def delta_E_CIE1976(Lab_1: Domain100, Lab_2: Domain100) -> NDArrayFloat:
111 """
112 Compute the colour difference :math:`\\Delta E_{76}` between two
113 specified *CIE L\\*a\\*b\\** colourspace arrays using the *CIE 1976*
114 recommendation.
116 Parameters
117 ----------
118 Lab_1
119 *CIE L\\*a\\*b\\** colourspace array 1.
120 Lab_2
121 *CIE L\\*a\\*b\\** colourspace array 2.
123 Returns
124 -------
125 :class:`numpy.ndarray`
126 Colour difference :math:`\\Delta E_{76}`.
128 Notes
129 -----
130 +------------+-----------------------+-------------------+
131 | **Domain** | **Scale - Reference** | **Scale - 1** |
132 +============+=======================+===================+
133 | ``Lab_1`` | 100 | 1 |
134 +------------+-----------------------+-------------------+
135 | ``Lab_2`` | 100 | 1 |
136 +------------+-----------------------+-------------------+
138 References
139 ----------
140 :cite:`Lindbloom2003c`
142 Examples
143 --------
144 >>> Lab_1 = np.array([48.99183622, -0.10561667, 400.65619925])
145 >>> Lab_2 = np.array([50.65907324, -0.11671910, 402.82235718])
146 >>> delta_E_CIE1976(Lab_1, Lab_2) # doctest: +ELLIPSIS
147 2.7335037...
148 """
150 return euclidean_distance(to_domain_100(Lab_1), to_domain_100(Lab_2))
153def delta_E_CIE1994(
154 Lab_1: Domain100,
155 Lab_2: Domain100,
156 textiles: bool = False,
157) -> NDArrayFloat:
158 """
159 Compute the colour difference :math:`\\Delta E_{94}` between two specified
160 *CIE L\\*a\\*b\\** colourspace arrays using the *CIE 1994* recommendation.
162 Parameters
163 ----------
164 Lab_1
165 *CIE L\\*a\\*b\\** colourspace array 1.
166 Lab_2
167 *CIE L\\*a\\*b\\** colourspace array 2.
168 textiles
169 Textiles application specific parametric factors,
170 :math:`k_L=2,\\ k_C=k_H=1,\\ k_1=0.048,\\ k_2=0.014` weights are used
171 instead of :math:`k_L=k_C=k_H=1,\\ k_1=0.045,\\ k_2=0.015`.
173 Returns
174 -------
175 :class:`numpy.ndarray`
176 Colour difference :math:`\\Delta E_{94}`.
178 Notes
179 -----
180 +------------+-----------------------+-------------------+
181 | **Domain** | **Scale - Reference** | **Scale - 1** |
182 +============+=======================+===================+
183 | ``Lab_1`` | 100 | 1 |
184 +------------+-----------------------+-------------------+
185 | ``Lab_2`` | 100 | 1 |
186 +------------+-----------------------+-------------------+
188 - *CIE 1994* colour differences are not symmetrical: difference between
189 ``Lab_1`` and ``Lab_2`` may not be the same as difference between
190 ``Lab_2`` and ``Lab_1`` thus one colour must be understood to be the
191 reference against which a sample colour is compared.
193 References
194 ----------
195 :cite:`Lindbloom2011a`
197 Examples
198 --------
199 >>> Lab_1 = np.array([48.99183622, -0.10561667, 400.65619925])
200 >>> Lab_2 = np.array([50.65907324, -0.11671910, 402.82235718])
201 >>> delta_E_CIE1994(Lab_1, Lab_2) # doctest: +ELLIPSIS
202 1.6711191...
203 >>> delta_E_CIE1994(Lab_1, Lab_2, textiles=True) # doctest: +ELLIPSIS
204 0.8404677...
205 """
207 L_1, a_1, b_1 = tsplit(to_domain_100(Lab_1))
208 L_2, a_2, b_2 = tsplit(to_domain_100(Lab_2))
210 k_1 = 0.048 if textiles else 0.045
211 k_2 = 0.014 if textiles else 0.015
212 k_L = 2 if textiles else 1
213 k_C = 1
214 k_H = 1
216 C_1 = np.hypot(a_1, b_1)
217 C_2 = np.hypot(a_2, b_2)
219 s_L = 1
220 s_C = 1 + k_1 * C_1
221 s_H = 1 + k_2 * C_1
223 delta_L = L_1 - L_2
224 delta_C = C_1 - C_2
225 delta_A = a_1 - a_2
226 delta_B = b_1 - b_2
228 radical = delta_A**2 + delta_B**2 - delta_C**2
229 delta_H = zeros(radical.shape)
230 delta_H[radical > 0] = np.sqrt(radical[radical > 0])
232 L = (delta_L / (k_L * s_L)) ** 2
233 C = (delta_C / (k_C * s_C)) ** 2
234 H = (delta_H / (k_H * s_H)) ** 2
236 d_E = np.sqrt(L + C + H)
238 return as_float(d_E)
241@dataclass
242class Attributes_Specification_CIE2000(MixinDataclassArithmetic):
243 """
244 Define the *CIE 2000* colour-difference formula attribute specification.
246 Parameters
247 ----------
248 J
249 Correlate of *lightness* :math:`J`.
250 C
251 Correlate of *chroma* :math:`C`.
252 h
253 *Hue* angle :math:`h` in degrees.
254 s
255 Correlate of *saturation* :math:`s`.
256 Q
257 Correlate of *brightness* :math:`Q`.
258 M
259 Correlate of *colourfulness* :math:`M`.
260 H
261 *Hue* :math:`h` quadrature :math:`H`.
262 HC
263 *Hue* :math:`h` composition :math:`H^C`.
264 """
266 S_L: float | NDArrayFloat | None = field(default_factory=lambda: None)
267 S_C: float | NDArrayFloat | None = field(default_factory=lambda: None)
268 S_H: float | NDArrayFloat | None = field(default_factory=lambda: None)
269 delta_L_p: float | NDArrayFloat | None = field(default_factory=lambda: None)
270 delta_C_p: float | NDArrayFloat | None = field(default_factory=lambda: None)
271 delta_H_p: float | NDArrayFloat | None = field(default_factory=lambda: None)
272 R_T: float | NDArrayFloat | None = field(default_factory=lambda: None)
275def intermediate_attributes_CIE2000(
276 Lab_1: Domain100, Lab_2: Domain100
277) -> Attributes_Specification_CIE2000:
278 """
279 Compute intermediate attributes for CIE 2000 colour difference calculation
280 between two specified *CIE L\\*a\\*b\\** colourspace arrays.
282 The intermediate attributes include the lightness, chroma, and hue
283 weighting functions (S_L, S_C, S_H), as well as the adjusted colour
284 differences (delta_L_p, delta_C_p, delta_H_p) and the rotation term (R_T)
285 required for computing :math:`\\Delta E_{00}`.
287 Parameters
288 ----------
289 Lab_1
290 *CIE L\\*a\\*b\\** colourspace array 1.
291 Lab_2
292 *CIE L\\*a\\*b\\** colourspace array 2.
294 Returns
295 -------
296 :class:`numpy.ndarray`
297 Intermediate attributes to compute the difference :math:`\\Delta E_{00}`.
299 Notes
300 -----
301 +------------+-----------------------+-------------------+
302 | **Domain** | **Scale - Reference** | **Scale - 1** |
303 +============+=======================+===================+
304 | ``Lab_1`` | 100 | 1 |
305 +------------+-----------------------+-------------------+
306 | ``Lab_2`` | 100 | 1 |
307 +------------+-----------------------+-------------------+
309 References
310 ----------
311 :cite:`Melgosa2013b`, :cite:`Sharma2005b`
313 Examples
314 --------
315 >>> Lab_1 = np.array([48.99183622, -0.10561667, 400.65619925])
316 >>> Lab_2 = np.array([50.65907324, -0.11671910, 402.82235718])
317 >>> intermediate_attributes_CIE2000(Lab_1, Lab_2) # doctest: +ELLIPSIS
318 Attributes_Specification_CIE2000(S_L=1.0001021..., S_C=19.0782682..., \
319S_H=4.7226695..., delta_L_p=1.6672370..., delta_C_p=2.1661609..., \
320delta_H_p=0.0105030..., R_T=-3...)
321 """
323 L_1, a_1, b_1 = tsplit(to_domain_100(Lab_1))
324 L_2, a_2, b_2 = tsplit(to_domain_100(Lab_2))
326 C_1_ab = np.hypot(a_1, b_1)
327 C_2_ab = np.hypot(a_2, b_2)
329 C_bar_ab = (C_1_ab + C_2_ab) / 2
330 C_bar_ab_7 = C_bar_ab**7
332 G = 0.5 * (1 - np.sqrt(C_bar_ab_7 / (C_bar_ab_7 + 25**7)))
334 a_p_1 = (1 + G) * a_1
335 a_p_2 = (1 + G) * a_2
337 C_p_1 = np.hypot(a_p_1, b_1)
338 C_p_2 = np.hypot(a_p_2, b_2)
340 h_p_1 = np.where(
341 np.logical_and(b_1 == 0, a_p_1 == 0),
342 0,
343 np.degrees(np.arctan2(b_1, a_p_1)) % 360,
344 )
345 h_p_2 = np.where(
346 np.logical_and(b_2 == 0, a_p_2 == 0),
347 0,
348 np.degrees(np.arctan2(b_2, a_p_2)) % 360,
349 )
351 delta_L_p = L_2 - L_1
353 delta_C_p = C_p_2 - C_p_1
355 h_p_2_s_1 = h_p_2 - h_p_1
356 C_p_1_m_2 = C_p_1 * C_p_2
357 delta_h_p = np.select(
358 [
359 C_p_1_m_2 == 0,
360 np.fabs(h_p_2_s_1) <= 180,
361 h_p_2_s_1 > 180,
362 h_p_2_s_1 < -180,
363 ],
364 [
365 0,
366 h_p_2_s_1,
367 h_p_2_s_1 - 360,
368 h_p_2_s_1 + 360,
369 ],
370 )
372 delta_H_p = 2 * np.sqrt(C_p_1_m_2) * np.sin(np.deg2rad(delta_h_p / 2))
374 L_bar_p = (L_1 + L_2) / 2
376 C_bar_p = (C_p_1 + C_p_2) / 2
378 a_h_p_1_s_2 = np.fabs(h_p_1 - h_p_2)
379 h_p_1_a_2 = h_p_1 + h_p_2
380 h_bar_p = np.select(
381 [
382 C_p_1_m_2 == 0,
383 a_h_p_1_s_2 <= 180,
384 np.logical_and(a_h_p_1_s_2 > 180, h_p_1_a_2 < 360),
385 np.logical_and(a_h_p_1_s_2 > 180, h_p_1_a_2 >= 360),
386 ],
387 [
388 h_p_1_a_2,
389 h_p_1_a_2 / 2,
390 (h_p_1_a_2 + 360) / 2,
391 (h_p_1_a_2 - 360) / 2,
392 ],
393 )
395 T = (
396 1
397 - 0.17 * np.cos(np.deg2rad(h_bar_p - 30))
398 + 0.24 * np.cos(np.deg2rad(2 * h_bar_p))
399 + 0.32 * np.cos(np.deg2rad(3 * h_bar_p + 6))
400 - 0.20 * np.cos(np.deg2rad(4 * h_bar_p - 63))
401 )
403 delta_theta = 30 * np.exp(-(((h_bar_p - 275) / 25) ** 2))
405 C_bar_p_7 = C_bar_p**7
406 R_C = 2 * np.sqrt(C_bar_p_7 / (C_bar_p_7 + 25**7))
408 L_bar_p_2 = (L_bar_p - 50) ** 2
409 S_L = 1 + ((0.015 * L_bar_p_2) / np.sqrt(20 + L_bar_p_2))
411 S_C = 1 + 0.045 * C_bar_p
413 S_H = 1 + 0.015 * C_bar_p * T
415 R_T = -np.sin(np.deg2rad(2 * delta_theta)) * R_C
417 return Attributes_Specification_CIE2000(
418 S_L,
419 S_C,
420 S_H,
421 delta_L_p,
422 delta_C_p,
423 delta_H_p,
424 R_T,
425 )
428def delta_E_CIE2000(
429 Lab_1: Domain100,
430 Lab_2: Domain100,
431 textiles: bool = False,
432) -> NDArrayFloat:
433 """
434 Compute the colour difference :math:`\\Delta E_{00}` between two specified
435 *CIE L\\*a\\*b\\** colourspace arrays using the *CIE 2000* recommendation.
437 Parameters
438 ----------
439 Lab_1
440 *CIE L\\*a\\*b\\** colourspace array 1.
441 Lab_2
442 *CIE L\\*a\\*b\\** colourspace array 2.
443 textiles
444 Textiles application specific parametric factors.
445 :math:`k_L=2,\\ k_C=k_H=1` weights are used instead of
446 :math:`k_L=k_C=k_H=1`.
448 Returns
449 -------
450 :class:`numpy.ndarray`
451 Colour difference :math:`\\Delta E_{00}`.
453 Notes
454 -----
455 +------------+-----------------------+-------------------+
456 | **Domain** | **Scale - Reference** | **Scale - 1** |
457 +============+=======================+===================+
458 | ``Lab_1`` | 100 | 1 |
459 +------------+-----------------------+-------------------+
460 | ``Lab_2`` | 100 | 1 |
461 +------------+-----------------------+-------------------+
463 - Parametric factors :math:`k_L=k_C=k_H=1` weights under
464 *reference conditions*:
466 - Illumination: D65 source
467 - Illuminance: 1000 lx
468 - Observer: Normal colour vision
469 - Background field: Uniform, neutral gray with :math:`L^*=50`
470 - Viewing mode: Object
471 - Sample size: Greater than 4 degrees
472 - Sample separation: Direct edge contact
473 - Sample colour-difference magnitude: Lower than 5.0
474 :math:`\\Delta E_{00}`
475 - Sample structure: Homogeneous (without texture)
477 References
478 ----------
479 :cite:`Melgosa2013b`, :cite:`Sharma2005b`
481 Examples
482 --------
483 >>> Lab_1 = np.array([48.99183622, -0.10561667, 400.65619925])
484 >>> Lab_2 = np.array([50.65907324, -0.11671910, 402.82235718])
485 >>> delta_E_CIE2000(Lab_1, Lab_2) # doctest: +ELLIPSIS
486 1.6709303...
487 >>> delta_E_CIE2000(Lab_1, Lab_2, textiles=True) # doctest: +ELLIPSIS
488 0.8412338...
489 """
491 S_L, S_C, S_H, delta_L_p, delta_C_p, delta_H_p, R_T = astuple(
492 intermediate_attributes_CIE2000(Lab_1, Lab_2)
493 )
495 k_L = 2 if textiles else 1
496 k_C = 1
497 k_H = 1
499 d_E = np.sqrt(
500 (delta_L_p / (k_L * S_L)) ** 2
501 + (delta_C_p / (k_C * S_C)) ** 2
502 + (delta_H_p / (k_H * S_H)) ** 2
503 + R_T * (delta_C_p / (k_C * S_C)) * (delta_H_p / (k_H * S_H))
504 )
506 return as_float(d_E)
509def delta_E_CMC(
510 Lab_1: Domain100,
511 Lab_2: Domain100,
512 l: float = 2, # noqa: E741
513 c: float = 1,
514) -> NDArrayFloat:
515 """
516 Compute the colour difference :math:`\\Delta E_{CMC}` between two
517 specified *CIE L\\*a\\*b\\** colourspace arrays using the *Colour
518 Measurement Committee* recommendation.
520 The quasimetric has two parameters: *lightness* (l) and *chroma* (c),
521 allowing users to weight the difference based on the ratio of l:c.
522 Commonly used values are 2:1 for acceptability and 1:1 for the
523 threshold of imperceptibility.
525 Parameters
526 ----------
527 Lab_1
528 *CIE L\\*a\\*b\\** colourspace array 1.
529 Lab_2
530 *CIE L\\*a\\*b\\** colourspace array 2.
531 l
532 *Lightness* weighting factor.
533 c
534 *Chroma* weighting factor.
536 Returns
537 -------
538 :class:`numpy.ndarray`
539 Colour difference :math:`\\Delta E_{CMC}`.
541 Notes
542 -----
543 +------------+-----------------------+-------------------+
544 | **Domain** | **Scale - Reference** | **Scale - 1** |
545 +============+=======================+===================+
546 | ``Lab_1`` | 100 | 1 |
547 +------------+-----------------------+-------------------+
548 | ``Lab_2`` | 100 | 1 |
549 +------------+-----------------------+-------------------+
551 References
552 ----------
553 :cite:`Lindbloom2009f`
555 Examples
556 --------
557 >>> Lab_1 = np.array([48.99183622, -0.10561667, 400.65619925])
558 >>> Lab_2 = np.array([50.65907324, -0.11671910, 402.82235718])
559 >>> delta_E_CMC(Lab_1, Lab_2) # doctest: +ELLIPSIS
560 0.8996999...
561 """
563 L_1, a_1, b_1 = tsplit(to_domain_100(Lab_1))
564 L_2, a_2, b_2 = tsplit(to_domain_100(Lab_2))
566 C_1 = np.hypot(a_1, b_1)
567 C_2 = np.hypot(a_2, b_2)
568 s_L = np.where(L_1 < 16, 0.511, (0.040975 * L_1) / (1 + 0.01765 * L_1))
569 s_C = 0.0638 * C_1 / (1 + 0.0131 * C_1) + 0.638
570 h_1 = np.degrees(np.arctan2(b_1, a_1)) % 360
572 t = np.where(
573 np.logical_and(h_1 >= 164, h_1 <= 345),
574 0.56 + np.fabs(0.2 * np.cos(np.deg2rad(h_1 + 168))),
575 0.36 + np.fabs(0.4 * np.cos(np.deg2rad(h_1 + 35))),
576 )
578 C_4 = C_1 * C_1 * C_1 * C_1
579 f = np.sqrt(C_4 / (C_4 + 1900))
580 s_h = s_C * (f * t + 1 - f)
582 delta_L = L_1 - L_2
583 delta_C = C_1 - C_2
584 delta_A = a_1 - a_2
585 delta_B = b_1 - b_2
586 delta_H2 = delta_A**2 + delta_B**2 - delta_C**2
588 v_1 = delta_L / (l * s_L)
589 v_2 = delta_C / (c * s_C)
590 v_3 = s_h
592 d_E = np.sqrt(v_1**2 + v_2**2 + (delta_H2 / (v_3 * v_3)))
594 return as_float(d_E)
597def delta_E_ITP(ICtCp_1: Domain1, ICtCp_2: Domain1) -> NDArrayFloat:
598 """
599 Compute the colour difference :math:`\\Delta E_{ITP}` between two specified
600 :math:`IC_TC_P` colour encoding arrays using the
601 *Recommendation ITU-R BT.2124*.
603 Parameters
604 ----------
605 ICtCp_1
606 :math:`IC_TC_P` colour encoding array 1.
607 ICtCp_2
608 :math:`IC_TC_P` colour encoding array 2.
610 Returns
611 -------
612 :class:`numpy.ndarray`
613 Colour difference :math:`\\Delta E_{ITP}`.
615 Notes
616 -----
617 - A value of 1 is equivalent to a just noticeable difference when viewed
618 in the most critical adaptation state.
620 +--------------+-----------------------+--------------------+
621 | **Domain** | **Scale - Reference** | **Scale - 1** |
622 +==============+=======================+====================+
623 | ``ICtCp_1`` | 1 | 1 |
624 +--------------+-----------------------+--------------------+
625 | ``ICtCp_2`` | 1 | 1 |
626 +--------------+-----------------------+--------------------+
628 References
629 ----------
630 :cite:`InternationalTelecommunicationUnion2019`
632 Examples
633 --------
634 >>> ICtCp_1 = np.array([0.4885468072, -0.04739350675, 0.07475401302])
635 >>> ICtCp_2 = np.array([0.4899203231, -0.04567508203, 0.07361341775])
636 >>> delta_E_ITP(ICtCp_1, ICtCp_2) # doctest: +ELLIPSIS
637 1.42657228...
638 """
640 I_1, T_1, P_1 = tsplit(ICtCp_1)
641 T_1 *= 0.5
643 I_2, T_2, P_2 = tsplit(ICtCp_2)
644 T_2 *= 0.5
646 d_E_ITP = 720 * np.sqrt(
647 ((I_2 - I_1) ** 2) + ((T_2 - T_1) ** 2) + ((P_2 - P_1) ** 2)
648 )
650 return as_float(d_E_ITP)
653def delta_E_HyAB(Lab_1: Domain100, Lab_2: Domain100) -> NDArrayFloat:
654 """
655 Compute the colour difference between two *CIE L\\*a\\*b\\** colourspace arrays
656 using a combination of a Euclidean metric in hue and chroma with a
657 city-block metric to incorporate lightness differences.
659 This metric is intended for large colour differences, on the order of 10
660 *CIE L\\*a\\*b\\** units or greater.
662 Parameters
663 ----------
664 Lab_1
665 *CIE L\\*a\\*b\\** colourspace array 1.
666 Lab_2
667 *CIE L\\*a\\*b\\** colourspace array 2.
669 Returns
670 -------
671 :class:`numpy.ndarray`
672 Colour difference :math:`\\Delta E_{HyAB}`.
674 Notes
675 -----
676 +------------+-----------------------+-------------------+
677 | **Domain** | **Scale - Reference** | **Scale - 1** |
678 +============+=======================+===================+
679 | ``Lab_1`` | 100 | 1 |
680 +------------+-----------------------+-------------------+
681 | ``Lab_2`` | 100 | 1 |
682 +------------+-----------------------+-------------------+
684 References
685 ----------
686 :cite:`Abasi2020a`
688 Examples
689 --------
690 >>> Lab_1 = np.array([39.91531343, 51.16658481, 146.12933781])
691 >>> Lab_2 = np.array([53.12207516, -39.92365056, 249.54831278])
692 >>> delta_E_HyAB(Lab_1, Lab_2) # doctest: +ELLIPSIS
693 151.0215481...
694 """
696 dLab = to_domain_100(Lab_1) - to_domain_100(Lab_2)
697 dL, da, db = tsplit(dLab)
698 HyAB = np.abs(dL) + np.hypot(da, db)
700 return as_float(HyAB)
703def delta_E_HyCH(
704 Lab_1: Domain100,
705 Lab_2: Domain100,
706 textiles: bool = False,
707) -> NDArrayFloat:
708 """
709 Compute the colour difference between two *CIE L\\*a\\*b\\** colourspace
710 arrays using a combination of Euclidean metric in hue and chroma with a
711 city-block metric to incorporate lightness differences based on
712 *CIE 2000* recommendation attributes.
714 This metric is intended for large colour differences, on the order of 10
715 *CIE L\\*a\\*b\\** units or greater.
717 Parameters
718 ----------
719 Lab_1
720 *CIE L\\*a\\*b\\** colourspace array 1.
721 Lab_2
722 *CIE L\\*a\\*b\\** colourspace array 2.
723 textiles
724 Whether to use the textile-specific parametrization.
726 Returns
727 -------
728 :class:`numpy.ndarray`
729 Colour difference :math:`\\Delta E_{HyCH}`.
731 Notes
732 -----
733 +------------+-----------------------+-------------------+
734 | **Domain** | **Scale - Reference** | **Scale - 1** |
735 +============+=======================+===================+
736 | ``Lab_1`` | 100 | 1 |
737 +------------+-----------------------+-------------------+
738 | ``Lab_2`` | 100 | 1 |
739 +------------+-----------------------+-------------------+
741 References
742 ----------
743 :cite:`Abasi2020a`
745 Examples
746 --------
747 >>> Lab_1 = np.array([39.91531343, 51.16658481, 146.12933781])
748 >>> Lab_2 = np.array([53.12207516, -39.92365056, 249.54831278])
749 >>> delta_E_HyCH(Lab_1, Lab_2) # doctest: +ELLIPSIS
750 48.664279419760369...
751 """
753 S_L, S_C, S_H, delta_L_p, delta_C_p, delta_H_p, R_T = astuple(
754 intermediate_attributes_CIE2000(Lab_1, Lab_2)
755 )
757 k_L = 2 if textiles else 1
758 k_C = 1
759 k_H = 1
761 HyCH = np.abs(delta_L_p / (k_L * S_L)) + np.sqrt(
762 (delta_C_p / (k_C * S_C)) ** 2 + (delta_H_p / (k_H * S_H)) ** 2
763 )
765 return as_float(HyCH)