Skip to content

Commit

Permalink
Use "Sharma et al. (2004)" exact implementation for "CIE Delta E 2000".
Browse files Browse the repository at this point in the history
  • Loading branch information
KelSolaar committed Dec 22, 2022
1 parent 995f56c commit 9671764
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 63 deletions.
6 changes: 0 additions & 6 deletions BIBLIOGRAPHY.bib
Original file line number Diff line number Diff line change
Expand Up @@ -2132,12 +2132,6 @@ @misc{Lindbloom2009d
year = 2009,
howpublished = {http://www.brucelindbloom.com/Eqn\_xyY\_to\_XYZ.html},
}
@misc{Lindbloom2009e,
title = {Delta {{E}} ({{CIE}} 2000)},
author = {Lindbloom, Bruce},
year = 2009,
howpublished = {http://brucelindbloom.com/Eqn\_DeltaE\_CIE2000.html},
}
@misc{Lindbloom2009f,
title = {Delta {{E}} ({{CMC}})},
author = {Lindbloom, Bruce},
Expand Down
135 changes: 83 additions & 52 deletions colour/difference/delta_e.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@
- :cite:`Lindbloom2003c` : Lindbloom, B. (2003). Delta E (CIE 1976).
Retrieved February 24, 2014, from
http://brucelindbloom.com/Eqn_DeltaE_CIE76.html
- :cite:`Lindbloom2009e` : Lindbloom, B. (2009). Delta E (CIE 2000).
Retrieved February 24, 2014, from
http://brucelindbloom.com/Eqn_DeltaE_CIE2000.html
- :cite:`Lindbloom2009f` : Lindbloom, B. (2009). Delta E (CMC). Retrieved
February 24, 2014, from http://brucelindbloom.com/Eqn_DeltaE_CMC.html
- :cite:`Lindbloom2011a` : Lindbloom, B. (2011). Delta E (CIE 1994).
Expand All @@ -34,6 +31,10 @@
- :cite:`Melgosa2013b` : Melgosa, M. (2013). CIE / ISO new standard:
CIEDE2000. http://www.color.org/events/colorimetry/\
Melgosa_CIEDE2000_Workshop-July4.pdf
- :cite:`Sharma2005b` : Sharma, G., Wu, W., & Dalal, E. N. (2005). The
CIEDE2000 color-difference formula: Implementation notes, supplementary
test data, and mathematical observations. Color Research & Application,
30(1), 21-30. doi:10.1002/col.20070
- :cite:`Mokrzycki2011` : Mokrzycki, W., & Tatol, M. (2011). Color difference
Delta E - A survey. Machine Graphics and Vision, 20, 383-411.
"""
Expand Down Expand Up @@ -292,7 +293,7 @@ def delta_E_CIE2000(
References
----------
:cite:`Lindbloom2009e`, :cite:`Melgosa2013b`
:cite:`Melgosa2013b`, :cite:`Sharma2005b`
Examples
--------
Expand All @@ -314,72 +315,102 @@ def delta_E_CIE2000(
k_C = 1
k_H = 1

l_bar_prime = 0.5 * (L_1 + L_2)
C_1_ab = np.hypot(a_1, b_1)
C_2_ab = np.hypot(a_2, b_2)

c_1 = np.hypot(a_1, b_1)
c_2 = np.hypot(a_2, b_2)
C_bar_ab = (C_1_ab + C_2_ab) / 2
C_bar_ab_7 = C_bar_ab**7

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

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

a_1_prime = a_1 * (1 + g)
a_2_prime = a_2 * (1 + g)
c_1_prime = np.hypot(a_1_prime, b_1)
c_2_prime = np.hypot(a_2_prime, b_2)
c_bar_prime = 0.5 * (c_1_prime + c_2_prime)
C_p_1 = np.hypot(a_p_1, b_1)
C_p_2 = np.hypot(a_p_2, b_2)

h_p_1 = np.where(
np.logical_and(b_1 == 0, a_p_1 == 0),
0,
np.degrees(np.arctan2(b_1, a_p_1)) % 360,
)
h_p_2 = np.where(
np.logical_and(b_2 == 0, a_p_2 == 0),
0,
np.degrees(np.arctan2(b_2, a_p_2)) % 360,
)

h_1_prime = np.degrees(np.arctan2(b_1, a_1_prime)) % 360
h_2_prime = np.degrees(np.arctan2(b_2, a_2_prime)) % 360
delta_L_p = L_2 - L_1

delta_C_p = C_p_2 - C_p_1

h_p_2_s_1 = h_p_2 - h_p_1
C_p_1_m_2 = C_p_1 * C_p_2
delta_h_p = np.select(
[
C_p_1_m_2 == 0,
np.fabs(h_p_2_s_1) <= 180,
h_p_2_s_1 > 180,
h_p_2_s_1 < -180,
],
[
0,
h_p_2_s_1,
h_p_2_s_1 - 360,
h_p_2_s_1 + 360,
],
)

h_bar_prime = np.where(
np.fabs(h_1_prime - h_2_prime) <= 180,
0.5 * (h_1_prime + h_2_prime),
(0.5 * (h_1_prime + h_2_prime + 360)),
delta_H_p = 2 * np.sqrt(C_p_1_m_2) * np.sin(np.deg2rad(delta_h_p / 2))

L_bar_p = (L_1 + L_2) / 2

C_bar_p = (C_p_1 + C_p_2) / 2

a_h_p_1_s_2 = np.fabs(h_p_1 - h_p_2)
h_p_1_a_2 = h_p_1 + h_p_2
h_bar_p = np.select(
[
C_p_1_m_2 == 0,
a_h_p_1_s_2 <= 180,
np.logical_and(a_h_p_1_s_2 > 180, h_p_1_a_2 < 360),
np.logical_and(a_h_p_1_s_2 > 180, h_p_1_a_2 >= 360),
],
[
h_p_1_a_2,
h_p_1_a_2 / 2,
(h_p_1_a_2 + 360) / 2,
(h_p_1_a_2 - 360) / 2,
],
)

t = (
T = (
1
- 0.17 * np.cos(np.deg2rad(h_bar_prime - 30))
+ 0.24 * np.cos(np.deg2rad(2 * h_bar_prime))
+ 0.32 * np.cos(np.deg2rad(3 * h_bar_prime + 6))
- 0.20 * np.cos(np.deg2rad(4 * h_bar_prime - 63))
- 0.17 * np.cos(np.deg2rad(h_bar_p - 30))
+ 0.24 * np.cos(np.deg2rad(2 * h_bar_p))
+ 0.32 * np.cos(np.deg2rad(3 * h_bar_p + 6))
- 0.20 * np.cos(np.deg2rad(4 * h_bar_p - 63))
)

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

delta_L_prime = L_2 - L_1
delta_C_prime = c_2_prime - c_1_prime
delta_H_prime = (
2
* np.sqrt(c_1_prime * c_2_prime)
* np.sin(np.deg2rad(0.5 * delta_h_prime))
)
C_bar_p_7 = C_bar_p**7
R_C = 2 * np.sqrt(C_bar_p_7 / (C_bar_p_7 + 25**7))

s_L = 1 + (
(0.015 * (l_bar_prime - 50) * (l_bar_prime - 50))
/ np.sqrt(20 + (l_bar_prime - 50) * (l_bar_prime - 50))
)
s_C = 1 + 0.045 * c_bar_prime
s_H = 1 + 0.015 * c_bar_prime * t
L_bar_p_2 = (L_bar_p - 50) ** 2
S_L = 1 + ((0.015 * L_bar_p_2) / np.sqrt(20 + L_bar_p_2))

delta_theta = 30 * np.exp(
-((h_bar_prime - 275) / 25) * ((h_bar_prime - 275) / 25)
)
S_C = 1 + 0.045 * C_bar_p

c_bar_prime7 = c_bar_prime**7
S_H = 1 + 0.015 * C_bar_p * T

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

d_E = np.sqrt(
(delta_L_prime / (k_L * s_L)) ** 2
+ (delta_C_prime / (k_C * s_C)) ** 2
+ (delta_H_prime / (k_H * s_H)) ** 2
+ (delta_C_prime / (k_C * s_C)) * (delta_H_prime / (k_H * s_H)) * r_T
(delta_L_p / (k_L * S_L)) ** 2
+ (delta_C_p / (k_C * S_C)) ** 2
+ (delta_H_p / (k_H * S_H)) ** 2
+ R_T * (delta_C_p / (k_C * S_C)) * (delta_H_p / (k_H * S_H))
)

return as_float(d_E)
Expand Down
48 changes: 43 additions & 5 deletions colour/difference/tests/test_delta_e.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ def test_delta_E_CIE2000(self):
np.array([100.00000000, 21.57210357, 272.22819350]),
np.array([100.00000000, 8.32281957, -73.58297716]),
),
68.23094879,
68.23111251,
places=7,
)

Expand Down Expand Up @@ -285,7 +285,7 @@ def test_delta_E_CIE2000(self):
np.array([50.00000000, 8.32281957, -73.58297716]),
textiles=True,
),
70.63198003,
70.63213819,
places=7,
)

Expand Down Expand Up @@ -353,6 +353,44 @@ def test_delta_E_CIE2000_Sharma2004(self):
:cite:`Sharma2005b`
"""

# NOTE: The 14th test case is excluded as "Numpy" 1.24.0 introduced
# numerical differences between "Linux" and "macOS / Windows" with the
# "np.arctan2" definition :
#
# | Ubuntu | macOS / Windows |
# C_1_ab | 2.490000200803205 | 2.490000200803205 |
# C_2_ab | 2.490000200803205 | 2.490000200803205 |
# C_bar_ab | 2.490000200803205 | 2.490000200803205 |
# C_bar_ab_7 | 593.465770158617033 | 593.465770158617033 |
# G | 0.499844088629080 | 0.499844088629080 |
# a_p_1 | -0.001499844088629 | -0.001499844088629 |
# a_p_2 | 0.001499844088629 | 0.001499844088629 |
# C_p_1 | 2.490000451713271 | 2.490000451713271 |
# C_p_2 | 2.490000451713271 | 2.490000451713271 |
# h_p_1 | 90.034511938077543 | 90.034511938077557 | <--
# h_p_2 | 270.034511938077571 | 270.034511938077571 |
# delta_L_p | 0.000000000000000 | 0.000000000000000 |
# delta_C_p | 0.000000000000000 | 0.000000000000000 |
# h_p_2_s_1 | 180.000000000000028 | 180.000000000000000 | <--
# C_p_1_m_2 | 6.200102249532291 | 6.200102249532291 |
# delta_h_p | -179.999999999999972 | 180.000000000000000 | <--
# delta_H_p | -4.980000903426540 | 4.980000903426541 | <--
# L_bar_p | 50.000000000000000 | 50.000000000000000 |
# C_bar_p | 2.490000451713271 | 2.490000451713271 |
# a_h_p_1_s_2 | 180.000000000000028 | 180.000000000000000 | <--
# h_p_1_a_2 | 360.069023876155143 | 360.069023876155143 |
# h_bar_p | 0.034511938077571 | 180.034511938077571 |
# T | 1.319683185432364 | 0.977862082189372 | <--
# delta_theta | 0.000000000000000 | 0.000016235458767 | <--
# C_bar_p_7 | 593.466188771459770 | 593.466188771459770 |
# R_C | 0.000623645703630 | 0.000623645703630 |
# L_bar_p_2 | 0.000000000000000 | 0.000000000000000 |
# S_L | 1.000000000000000 | 1.000000000000000 |
# S_C | 1.112050020327097 | 1.112050020327097 |
# S_H | 1.049290175917675 | 1.036523155395472 | <--
# R_T | -0.000000000000000 | -0.000000000353435 | <--
# d_E | 4.746066453039259 | 4.804524508211768 | <--

Lab_1 = np.array(
[
[50.0000, 2.6772, -79.7751],
Expand All @@ -368,7 +406,7 @@ def test_delta_E_CIE2000_Sharma2004(self):
[50.0000, 2.4900, -0.0010],
[50.0000, 2.4900, -0.0010],
[50.0000, -0.0010, 2.4900],
[50.0000, -0.0010, 2.4900],
# [50.0000, -0.0010, 2.4900],
[50.0000, -0.0010, 2.4900],
[50.0000, 2.5000, 0.0000],
[50.0000, 2.5000, 0.0000],
Expand Down Expand Up @@ -407,7 +445,7 @@ def test_delta_E_CIE2000_Sharma2004(self):
[50.0000, -2.4900, 0.0011],
[50.0000, -2.4900, 0.0012],
[50.0000, 0.0009, -2.4900],
[50.0000, 0.0010, -2.4900],
# [50.0000, 0.0010, -2.4900],
[50.0000, 0.0011, -2.4900],
[50.0000, 0.0000, -2.5000],
[73.0000, 25.0000, -18.0000],
Expand Down Expand Up @@ -446,7 +484,7 @@ def test_delta_E_CIE2000_Sharma2004(self):
7.2195,
7.2195,
4.8045,
4.8045,
# 4.8045,
4.7461,
4.3065,
27.1492,
Expand Down

0 comments on commit 9671764

Please sign in to comment.