CIEDE2000 implementation in Prolog
| Number of visits | 580 |
|---|---|
| Number of files viewed | 277 + 607 |
This page presents a reference implementation of the CIEDE2000 color difference formula written in the Prolog programming language. If you want to ensure perfect compatibility (to the tenth decimal place) with certain third-party implementations, it may be necessary to modify the comments in the source code; the following link automates this operation for you.
The ΔE2000 function in Prolog
Letβs consider the more common and academic (Sharma, 2005) of the two formulations.
% This function written in Prolog is not affiliated with the CIE (International Commission on Illumination),
% and is released into the public domain. It is provided "as is" without any warranty, express or implied.
% The classic CIE ΞE2000 implementation, which operates on two L*a*b* colors, and returns their difference.
% "l" ranges from 0 to 100, while "a" and "b" are unbounded and commonly clamped to the range of -128 to 127.
ciede_2000(L1, A1, B1, L2, A2, B2, DeltaE2000) :-
% Working in Prolog with the CIEDE2000 color-difference formula.
% K_L, K_C, K_H are parametric factors to be adjusted according to
% different viewing parameters such as textures, backgrounds...
K_L is 1.0,
K_C is 1.0,
K_H is 1.0,
Pi_1 is 3.14159265358979323846,
Pi_3 is 1.04719755119659774615,
% 1. Compute chroma magnitudes ... a and b usually range from -128 to +127
A1_sq is A1 * A1,
B1_sq is B1 * B1,
C_orig_1 is sqrt(A1_sq + B1_sq),
A2_sq is A2 * A2,
B2_sq is B2 * B2,
C_orig_2 is sqrt(A2_sq + B2_sq),
% 2. Compute chroma mean and apply G compensation
C_avg is 0.5 * (C_orig_1 + C_orig_2),
C_avg_3 is C_avg * C_avg * C_avg,
C_avg_7 is C_avg_3 * C_avg_3 * C_avg,
G_denom is C_avg_7 + 6103515625.0,
G_ratio is C_avg_7 / G_denom,
G_sqrt is sqrt(G_ratio),
G_factor is 1.0 + 0.5 * (1.0 - G_sqrt),
% 3. Apply G correction to a components, compute corrected chroma
A1_prime is A1 * G_factor,
C1_prime_sq is A1_prime * A1_prime + B1 * B1,
C1_prime is sqrt(C1_prime_sq),
A2_prime is A2 * G_factor,
C2_prime_sq is A2_prime * A2_prime + B2 * B2,
C2_prime is sqrt(C2_prime_sq),
% 4. Compute hue angles in radians, adjust for negatives and wrap
H1_raw is atan2(B1, A1_prime),
H2_raw is atan2(B2, A2_prime),
(H1_raw < 0.0 -> H1_adj is H1_raw + 2.0 * Pi_1 ; H1_adj = H1_raw),
(H2_raw < 0.0 -> H2_adj is H2_raw + 2.0 * Pi_1 ; H2_adj = H2_raw),
Delta_h is abs(H1_adj - H2_adj),
H_mean_raw is 0.5 * (H1_adj + H2_adj),
H_diff_raw is 0.5 * (H2_adj - H1_adj),
% Check if hue mean wraps around pi (180 deg)
Wrap_dist is abs(Pi_1 - Delta_h),
(1.0e-14 < Wrap_dist, Pi_1 < Delta_h -> Hue_wrap = 1.0 ; Hue_wrap = 0),
H_diff is H_diff_raw + Hue_wrap * Pi_1,
% π Sharmaβs formulation doesnβt use the next line, but the three after it,
% and these two variants differ by Β±0.0003 on the final color differences.
H_mean is H_mean_raw + Hue_wrap * Pi_1,
% (Hue_wrap =:= 1, H_mean_raw < Pi_1 -> H_mean_hi = Pi_1 ; H_mean_hi = 0.0),
% (Hue_wrap =:= 1, H_mean_hi =:= 0.0 -> H_mean_lo = Pi_1 ; H_mean_lo = 0.0),
% H_mean is H_mean_raw + H_mean_hi - H_mean_lo,
% 5. Compute hue rotation correction factor R_T
C_bar is 0.5 * (C1_prime + C2_prime),
C_bar_3 is C_bar * C_bar * C_bar,
C_bar_7 is C_bar_3 * C_bar_3 * C_bar,
Rc_denom is C_bar_7 + 6103515625.0,
R_C is sqrt(C_bar_7 / Rc_denom),
Theta is 36.0 * H_mean - 55.0 * Pi_1,
Theta_denom is -25.0 * Pi_1 * Pi_1,
Exp_argument is Theta * Theta / Theta_denom,
Exp_term is exp(Exp_argument),
Delta_theta is Pi_3 * Exp_term,
Sin_term is sin(Delta_theta),
% Rotation factor ... cross-effect between chroma and hue
R_T is -2.0 * R_C * Sin_term,
% 6. Compute lightness term ... L nominally ranges from 0 to 100
L_avg is 0.5 * (L1 + L2),
L_delta_sq is (L_avg - 50.0) * (L_avg - 50.0),
L_delta is L2 - L1,
% Adaptation to the non-linearity of light perception ... S_L
S_l_num is 0.015 * L_delta_sq,
S_l_denom is sqrt(20.0 + L_delta_sq),
S_L is 1.0 + S_l_num / S_l_denom,
L_term is L_delta / (K_L * S_L),
% 7. Compute chroma-related trig terms and factor T
Trig_1 is 0.17 * sin(H_mean + Pi_3),
Trig_2 is 0.24 * sin(2.0 * H_mean + 0.5 * Pi_1),
Trig_3 is 0.32 * sin(3.0 * H_mean + 1.6 * Pi_3),
Trig_4 is 0.2 * sin(4.0 * H_mean + 0.15 * Pi_1),
T is 1.0 - Trig_1 + Trig_2 + Trig_3 - Trig_4,
C_sum is C1_prime + C2_prime,
C_product is C1_prime * C2_prime,
C_geo_mean is sqrt(C_product),
% 8. Compute hue difference and scaling factor S_H
Sin_h_diff is sin(H_diff),
S_H is 1.0 + 0.0075 * C_sum * T,
H_term is 2.0 * C_geo_mean * Sin_h_diff / (K_H * S_H),
% 9. Compute chroma difference and scaling factor S_C
C_delta is C2_prime - C1_prime,
S_C is 1.0 + 0.0225 * C_sum,
C_term is C_delta / (K_C * S_C),
% 10. Combine lightness, chroma, hue, and interaction terms
L_part is L_term * L_term,
C_part is C_term * C_term,
H_part is H_term * H_term,
Interaction is C_term * H_term * R_T,
Delta_e_squared is L_part + C_part + H_part + Interaction,
DeltaE2000 is sqrt(Delta_e_squared).
% GitHub Project : https://github.com/michel-leonard/ciede2000-color-matching
% Online Tests : https://michel-leonard.github.io/ciede2000-color-matching
% L1 = 14.8 a1 = 33.5 b1 = 2.4
% L2 = 16.6 a2 = 38.1 b2 = -2.7
% CIE ΞE00 = 3.6462011992 (Bruce Lindbloom, Netflixβs VMAF, ...)
% CIE ΞE00 = 3.6461873926 (Gaurav Sharma, OpenJDK, ...)
% Deviation between implementations β 1.4e-5
% See the source code comments for easy switching between these two widely used ΞE*00 implementation variants.K_L, K_C and K_H parameters
The parameters K_L, K_C and K_H in the CIEDE2000 formula are weighting factors applied to the brightness (ΞL*), chroma (ΞC*) and hue (ΞH*) components respectively. In the source code, they are defined as constants with a default value of 1, corresponding to the standard observation conditions laid down by the International Commission on Illumination (CIE). In practice, you might need to adjust these coefficients to reflect specific conditions: for example, K_L = 2 is sometimes used to give more weight to differences in brightness (a common occurrence in the textile industry), while K_C or K_H can be reduced to increase tolerance for variations in saturation or hue. In summary, these coefficients typically range from 0.5 to 2, with 1 being the most common value.
Source code accuracy and reliability
The difference between Sharmaβs academic formulation and Lindbloomβs simplified formulation does not exceed Β±0.0003 on the final ΞE2000. The implementation presented here is 64-bit and guarantees more than 10 decimal places of precision; the choice of one formulation over another is, therefore, a technical detail. At the top of this page, you can choose between the two formulations; the one currently displayed is the simplified formulation.
How to determine if a given implementation of CIEDE2000 is academic or simplified?
- Evaluate
ciede_2000(56.6, 43.6, 41.1, 68.4, 9.4, -8.6) - If the result is
30.0001, then it is the academic type (such as Sharma, OpenJDK, etc.) - If the result is
29.9999, then it is the simplified type (such as Lindbloom, Netflix VMAF, etc.)
How do you convert RGB colors to L*a*b*?
Go to the AWK, C, Dart, Java, JavaScript, Kotlin, Lua, PHP, Python, Ruby or Rust page where such a converter (using D65 illuminant) is already implemented in addition to the color comparison function.
CIELAB value ranges and interpretation of the ΞE2000
In the CIELAB color space, the L* component represents lightness and typically ranges from 0 (black) to 100 (white). The a* and b* components represent color axes: a* goes from green to red, while b* goes from blue to yellow. In practice, the values of a* and b* are almost always limited to a range between -128 and +127, although the standard does not specify an official limit for these two components.
| Color 1 | Color 2 | Value of ΞE2000 |
|---|---|---|
| 1 | ||
| 2 | ||
| 3 |
| Color 1 | Color 2 | Value of ΞE2000 |
|---|---|---|
| 5 | ||
| 10 | ||
| 15 |
ΞE2000 (CIEDE2000) measures the perceived difference between two colors: 0 means the colors are identical, and higher values (up to 185 and more) indicate a larger difference. For example, a ΔE2000 value around 5 means the colors are close, while a value around 15 means they are clearly different. When the ΔE2000 value exceeds 40, the colors being compared have virtually nothing in common, and we can no longer derive any precise information from them.
Example of use in Prolog
% Compute the Delta E (CIEDE2000) color difference between two L*a*b* colors in Prolog
color_1([69.5, 43.6, -1.8]).
color_2([70.2, 37.9, 1.6]).
extract_lab([L, A, B], L, A, B).
compute_delta_e :-
color_1(C1),
color_2(C2),
extract_lab(C1, L1, A1, B1),
extract_lab(C2, L2, A2, B2),
ciede_2000(L1, A1, B1, L2, A2, B2, DeltaE),
format('Delta E 2000 = ~10f~n', [DeltaE]).
% .................................................. This shows a ΔE2000 of 2.8044781137
% As explained in the comments, compliance with Gaurav Sharma would display 2.8044649638Test results
Our test program, written in C99, includes 250 precise static tests. These tests ensure that your calculations will be performed without errors, even in critical edge cases, for example, when the arctangent function returns a mathematically undefined value. The results show that this CIEDE2000 function in Prolog is interoperable with the 41 other programming languages that we offer.
CIEDE2000 Verification Summary :
First Verified Line : 27,-123,101,44,-30,122,29.98937281745311
Duration : 254.09 s
Successes : 10000000
Errors : 0
Average Delta E : 63.2072
Average Deviation : 5.0e-15
Maximum Deviation : 1.1e-13Files to download
Feel free to use these files provided by Michel, even for commercial purposes.
| File | Size | Number of clicks |
|---|---|---|
| ciede-2000.pro | 5 KB | 112 |
| ciede-2000-driver.pro | 6 KB | 110 |
| test-pro.yml | 4 KB | 55 |
| reference-dataset.txt | 4 KB | 607 |
| Click on pro.zip to receive all these files in an archive. | ||
Community
What do you think of this source code or CIEDE2000? Your opinion is important to us! The guestbook already contains 9 messages - including 1 in English. Take a look and share your opinion.