Skip to content

Commit 9671764

Browse files
committed
Use "Sharma et al. (2004)" exact implementation for "CIE Delta E 2000".
1 parent 995f56c commit 9671764

File tree

3 files changed

+126
-63
lines changed

3 files changed

+126
-63
lines changed

BIBLIOGRAPHY.bib

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2132,12 +2132,6 @@ @misc{Lindbloom2009d
21322132
year = 2009,
21332133
howpublished = {http://www.brucelindbloom.com/Eqn\_xyY\_to\_XYZ.html},
21342134
}
2135-
@misc{Lindbloom2009e,
2136-
title = {Delta {{E}} ({{CIE}} 2000)},
2137-
author = {Lindbloom, Bruce},
2138-
year = 2009,
2139-
howpublished = {http://brucelindbloom.com/Eqn\_DeltaE\_CIE2000.html},
2140-
}
21412135
@misc{Lindbloom2009f,
21422136
title = {Delta {{E}} ({{CMC}})},
21432137
author = {Lindbloom, Bruce},

colour/difference/delta_e.py

Lines changed: 83 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
- :cite:`Lindbloom2003c` : Lindbloom, B. (2003). Delta E (CIE 1976).
2424
Retrieved February 24, 2014, from
2525
http://brucelindbloom.com/Eqn_DeltaE_CIE76.html
26-
- :cite:`Lindbloom2009e` : Lindbloom, B. (2009). Delta E (CIE 2000).
27-
Retrieved February 24, 2014, from
28-
http://brucelindbloom.com/Eqn_DeltaE_CIE2000.html
2926
- :cite:`Lindbloom2009f` : Lindbloom, B. (2009). Delta E (CMC). Retrieved
3027
February 24, 2014, from http://brucelindbloom.com/Eqn_DeltaE_CMC.html
3128
- :cite:`Lindbloom2011a` : Lindbloom, B. (2011). Delta E (CIE 1994).
@@ -34,6 +31,10 @@
3431
- :cite:`Melgosa2013b` : Melgosa, M. (2013). CIE / ISO new standard:
3532
CIEDE2000. http://www.color.org/events/colorimetry/\
3633
Melgosa_CIEDE2000_Workshop-July4.pdf
34+
- :cite:`Sharma2005b` : Sharma, G., Wu, W., & Dalal, E. N. (2005). The
35+
CIEDE2000 color-difference formula: Implementation notes, supplementary
36+
test data, and mathematical observations. Color Research & Application,
37+
30(1), 21-30. doi:10.1002/col.20070
3738
- :cite:`Mokrzycki2011` : Mokrzycki, W., & Tatol, M. (2011). Color difference
3839
Delta E - A survey. Machine Graphics and Vision, 20, 383-411.
3940
"""
@@ -292,7 +293,7 @@ def delta_E_CIE2000(
292293
293294
References
294295
----------
295-
:cite:`Lindbloom2009e`, :cite:`Melgosa2013b`
296+
:cite:`Melgosa2013b`, :cite:`Sharma2005b`
296297
297298
Examples
298299
--------
@@ -314,72 +315,102 @@ def delta_E_CIE2000(
314315
k_C = 1
315316
k_H = 1
316317

317-
l_bar_prime = 0.5 * (L_1 + L_2)
318+
C_1_ab = np.hypot(a_1, b_1)
319+
C_2_ab = np.hypot(a_2, b_2)
318320

319-
c_1 = np.hypot(a_1, b_1)
320-
c_2 = np.hypot(a_2, b_2)
321+
C_bar_ab = (C_1_ab + C_2_ab) / 2
322+
C_bar_ab_7 = C_bar_ab**7
321323

322-
c_bar = 0.5 * (c_1 + c_2)
323-
c_bar7 = c_bar**7
324+
G = 0.5 * (1 - np.sqrt(C_bar_ab_7 / (C_bar_ab_7 + 25**7)))
324325

325-
g = 0.5 * (1 - np.sqrt(c_bar7 / (c_bar7 + 25**7)))
326+
a_p_1 = (1 + G) * a_1
327+
a_p_2 = (1 + G) * a_2
326328

327-
a_1_prime = a_1 * (1 + g)
328-
a_2_prime = a_2 * (1 + g)
329-
c_1_prime = np.hypot(a_1_prime, b_1)
330-
c_2_prime = np.hypot(a_2_prime, b_2)
331-
c_bar_prime = 0.5 * (c_1_prime + c_2_prime)
329+
C_p_1 = np.hypot(a_p_1, b_1)
330+
C_p_2 = np.hypot(a_p_2, b_2)
331+
332+
h_p_1 = np.where(
333+
np.logical_and(b_1 == 0, a_p_1 == 0),
334+
0,
335+
np.degrees(np.arctan2(b_1, a_p_1)) % 360,
336+
)
337+
h_p_2 = np.where(
338+
np.logical_and(b_2 == 0, a_p_2 == 0),
339+
0,
340+
np.degrees(np.arctan2(b_2, a_p_2)) % 360,
341+
)
332342

333-
h_1_prime = np.degrees(np.arctan2(b_1, a_1_prime)) % 360
334-
h_2_prime = np.degrees(np.arctan2(b_2, a_2_prime)) % 360
343+
delta_L_p = L_2 - L_1
344+
345+
delta_C_p = C_p_2 - C_p_1
346+
347+
h_p_2_s_1 = h_p_2 - h_p_1
348+
C_p_1_m_2 = C_p_1 * C_p_2
349+
delta_h_p = np.select(
350+
[
351+
C_p_1_m_2 == 0,
352+
np.fabs(h_p_2_s_1) <= 180,
353+
h_p_2_s_1 > 180,
354+
h_p_2_s_1 < -180,
355+
],
356+
[
357+
0,
358+
h_p_2_s_1,
359+
h_p_2_s_1 - 360,
360+
h_p_2_s_1 + 360,
361+
],
362+
)
335363

336-
h_bar_prime = np.where(
337-
np.fabs(h_1_prime - h_2_prime) <= 180,
338-
0.5 * (h_1_prime + h_2_prime),
339-
(0.5 * (h_1_prime + h_2_prime + 360)),
364+
delta_H_p = 2 * np.sqrt(C_p_1_m_2) * np.sin(np.deg2rad(delta_h_p / 2))
365+
366+
L_bar_p = (L_1 + L_2) / 2
367+
368+
C_bar_p = (C_p_1 + C_p_2) / 2
369+
370+
a_h_p_1_s_2 = np.fabs(h_p_1 - h_p_2)
371+
h_p_1_a_2 = h_p_1 + h_p_2
372+
h_bar_p = np.select(
373+
[
374+
C_p_1_m_2 == 0,
375+
a_h_p_1_s_2 <= 180,
376+
np.logical_and(a_h_p_1_s_2 > 180, h_p_1_a_2 < 360),
377+
np.logical_and(a_h_p_1_s_2 > 180, h_p_1_a_2 >= 360),
378+
],
379+
[
380+
h_p_1_a_2,
381+
h_p_1_a_2 / 2,
382+
(h_p_1_a_2 + 360) / 2,
383+
(h_p_1_a_2 - 360) / 2,
384+
],
340385
)
341386

342-
t = (
387+
T = (
343388
1
344-
- 0.17 * np.cos(np.deg2rad(h_bar_prime - 30))
345-
+ 0.24 * np.cos(np.deg2rad(2 * h_bar_prime))
346-
+ 0.32 * np.cos(np.deg2rad(3 * h_bar_prime + 6))
347-
- 0.20 * np.cos(np.deg2rad(4 * h_bar_prime - 63))
389+
- 0.17 * np.cos(np.deg2rad(h_bar_p - 30))
390+
+ 0.24 * np.cos(np.deg2rad(2 * h_bar_p))
391+
+ 0.32 * np.cos(np.deg2rad(3 * h_bar_p + 6))
392+
- 0.20 * np.cos(np.deg2rad(4 * h_bar_p - 63))
348393
)
349394

350-
h = h_2_prime - h_1_prime
351-
delta_h_prime = np.where(h_2_prime <= h_1_prime, h - 360, h + 360)
352-
delta_h_prime = np.where(np.fabs(h) <= 180, h, delta_h_prime)
395+
delta_theta = 30 * np.exp(-(((h_bar_p - 275) / 25) ** 2))
353396

354-
delta_L_prime = L_2 - L_1
355-
delta_C_prime = c_2_prime - c_1_prime
356-
delta_H_prime = (
357-
2
358-
* np.sqrt(c_1_prime * c_2_prime)
359-
* np.sin(np.deg2rad(0.5 * delta_h_prime))
360-
)
397+
C_bar_p_7 = C_bar_p**7
398+
R_C = 2 * np.sqrt(C_bar_p_7 / (C_bar_p_7 + 25**7))
361399

362-
s_L = 1 + (
363-
(0.015 * (l_bar_prime - 50) * (l_bar_prime - 50))
364-
/ np.sqrt(20 + (l_bar_prime - 50) * (l_bar_prime - 50))
365-
)
366-
s_C = 1 + 0.045 * c_bar_prime
367-
s_H = 1 + 0.015 * c_bar_prime * t
400+
L_bar_p_2 = (L_bar_p - 50) ** 2
401+
S_L = 1 + ((0.015 * L_bar_p_2) / np.sqrt(20 + L_bar_p_2))
368402

369-
delta_theta = 30 * np.exp(
370-
-((h_bar_prime - 275) / 25) * ((h_bar_prime - 275) / 25)
371-
)
403+
S_C = 1 + 0.045 * C_bar_p
372404

373-
c_bar_prime7 = c_bar_prime**7
405+
S_H = 1 + 0.015 * C_bar_p * T
374406

375-
r_C = np.sqrt(c_bar_prime7 / (c_bar_prime7 + 25**7))
376-
r_T = -2 * r_C * np.sin(np.deg2rad(2 * delta_theta))
407+
R_T = -np.sin(np.deg2rad(2 * delta_theta)) * R_C
377408

378409
d_E = np.sqrt(
379-
(delta_L_prime / (k_L * s_L)) ** 2
380-
+ (delta_C_prime / (k_C * s_C)) ** 2
381-
+ (delta_H_prime / (k_H * s_H)) ** 2
382-
+ (delta_C_prime / (k_C * s_C)) * (delta_H_prime / (k_H * s_H)) * r_T
410+
(delta_L_p / (k_L * S_L)) ** 2
411+
+ (delta_C_p / (k_C * S_C)) ** 2
412+
+ (delta_H_p / (k_H * S_H)) ** 2
413+
+ R_T * (delta_C_p / (k_C * S_C)) * (delta_H_p / (k_H * S_H))
383414
)
384415

385416
return as_float(d_E)

colour/difference/tests/test_delta_e.py

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ def test_delta_E_CIE2000(self):
255255
np.array([100.00000000, 21.57210357, 272.22819350]),
256256
np.array([100.00000000, 8.32281957, -73.58297716]),
257257
),
258-
68.23094879,
258+
68.23111251,
259259
places=7,
260260
)
261261

@@ -285,7 +285,7 @@ def test_delta_E_CIE2000(self):
285285
np.array([50.00000000, 8.32281957, -73.58297716]),
286286
textiles=True,
287287
),
288-
70.63198003,
288+
70.63213819,
289289
places=7,
290290
)
291291

@@ -353,6 +353,44 @@ def test_delta_E_CIE2000_Sharma2004(self):
353353
:cite:`Sharma2005b`
354354
"""
355355

356+
# NOTE: The 14th test case is excluded as "Numpy" 1.24.0 introduced
357+
# numerical differences between "Linux" and "macOS / Windows" with the
358+
# "np.arctan2" definition :
359+
#
360+
# | Ubuntu | macOS / Windows |
361+
# C_1_ab | 2.490000200803205 | 2.490000200803205 |
362+
# C_2_ab | 2.490000200803205 | 2.490000200803205 |
363+
# C_bar_ab | 2.490000200803205 | 2.490000200803205 |
364+
# C_bar_ab_7 | 593.465770158617033 | 593.465770158617033 |
365+
# G | 0.499844088629080 | 0.499844088629080 |
366+
# a_p_1 | -0.001499844088629 | -0.001499844088629 |
367+
# a_p_2 | 0.001499844088629 | 0.001499844088629 |
368+
# C_p_1 | 2.490000451713271 | 2.490000451713271 |
369+
# C_p_2 | 2.490000451713271 | 2.490000451713271 |
370+
# h_p_1 | 90.034511938077543 | 90.034511938077557 | <--
371+
# h_p_2 | 270.034511938077571 | 270.034511938077571 |
372+
# delta_L_p | 0.000000000000000 | 0.000000000000000 |
373+
# delta_C_p | 0.000000000000000 | 0.000000000000000 |
374+
# h_p_2_s_1 | 180.000000000000028 | 180.000000000000000 | <--
375+
# C_p_1_m_2 | 6.200102249532291 | 6.200102249532291 |
376+
# delta_h_p | -179.999999999999972 | 180.000000000000000 | <--
377+
# delta_H_p | -4.980000903426540 | 4.980000903426541 | <--
378+
# L_bar_p | 50.000000000000000 | 50.000000000000000 |
379+
# C_bar_p | 2.490000451713271 | 2.490000451713271 |
380+
# a_h_p_1_s_2 | 180.000000000000028 | 180.000000000000000 | <--
381+
# h_p_1_a_2 | 360.069023876155143 | 360.069023876155143 |
382+
# h_bar_p | 0.034511938077571 | 180.034511938077571 |
383+
# T | 1.319683185432364 | 0.977862082189372 | <--
384+
# delta_theta | 0.000000000000000 | 0.000016235458767 | <--
385+
# C_bar_p_7 | 593.466188771459770 | 593.466188771459770 |
386+
# R_C | 0.000623645703630 | 0.000623645703630 |
387+
# L_bar_p_2 | 0.000000000000000 | 0.000000000000000 |
388+
# S_L | 1.000000000000000 | 1.000000000000000 |
389+
# S_C | 1.112050020327097 | 1.112050020327097 |
390+
# S_H | 1.049290175917675 | 1.036523155395472 | <--
391+
# R_T | -0.000000000000000 | -0.000000000353435 | <--
392+
# d_E | 4.746066453039259 | 4.804524508211768 | <--
393+
356394
Lab_1 = np.array(
357395
[
358396
[50.0000, 2.6772, -79.7751],
@@ -368,7 +406,7 @@ def test_delta_E_CIE2000_Sharma2004(self):
368406
[50.0000, 2.4900, -0.0010],
369407
[50.0000, 2.4900, -0.0010],
370408
[50.0000, -0.0010, 2.4900],
371-
[50.0000, -0.0010, 2.4900],
409+
# [50.0000, -0.0010, 2.4900],
372410
[50.0000, -0.0010, 2.4900],
373411
[50.0000, 2.5000, 0.0000],
374412
[50.0000, 2.5000, 0.0000],
@@ -407,7 +445,7 @@ def test_delta_E_CIE2000_Sharma2004(self):
407445
[50.0000, -2.4900, 0.0011],
408446
[50.0000, -2.4900, 0.0012],
409447
[50.0000, 0.0009, -2.4900],
410-
[50.0000, 0.0010, -2.4900],
448+
# [50.0000, 0.0010, -2.4900],
411449
[50.0000, 0.0011, -2.4900],
412450
[50.0000, 0.0000, -2.5000],
413451
[73.0000, 25.0000, -18.0000],
@@ -446,7 +484,7 @@ def test_delta_E_CIE2000_Sharma2004(self):
446484
7.2195,
447485
7.2195,
448486
4.8045,
449-
4.8045,
487+
# 4.8045,
450488
4.7461,
451489
4.3065,
452490
27.1492,

0 commit comments

Comments
 (0)