CIEDE2000-Implementierung in Ada
| Anzahl der Besuche | 452 |
|---|---|
| Anzahl der angesehenen Dateien | 211 + 378 |
Diese Seite enthält eine Referenzimplementierung der CIEDE2000 Formel für den Farbabstand in Ada. Wenn Sie eine perfekte Kompatibilität (bis zur zehnten Dezimalstelle) mit einigen Implementierungen von Drittanbietern sicherstellen wollen, müssen Sie möglicherweise die Kommentare im Quellcode ändern. Um dies zu erleichtern, automatisiert der folgende Link diesen Vorgang.
Die Funktion ΔE2000 in Ada
Betrachten wir die gängigere und akademische (Sharma, 2005) der beiden Formulierungen.
-- This function written in Ada 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.
with Ada.Numerics.Generic_Elementary_Functions;
-- 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.
function ciede_2000 (l_1, a_1, b_1, l_2, a_2, b_2 : Long_Float) return Long_Float is
package Math is new Ada.Numerics.Generic_Elementary_Functions (Long_Float);
-- Working in Ada 2005 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 : constant Long_Float := 1.0;
k_c : constant Long_Float := 1.0;
k_h : constant Long_Float := 1.0;
m_pi : constant Long_Float := Ada.Numerics.Pi;
n, c_1, c_2, h_1, h_2, h_m, h_d, p, r_t, l, t, h, c: Long_Float;
begin
n := (Math.Sqrt(a_1 * a_1 + b_1 * b_1) + Math.Sqrt(a_2 * a_2 + b_2 * b_2)) * 0.5;
n := n * n * n * n * n * n * n;
-- A factor involving chroma raised to the power of 7 designed to make
-- the influence of chroma on the total color difference more accurate.
n := 1.0 + 0.5 * (1.0 - Math.Sqrt(n / (n + 6103515625.0)));
-- Application of the chroma correction factor.
c_1 := Math.Sqrt(a_1 * a_1 * n * n + b_1 * b_1);
c_2 := Math.Sqrt(a_2 * a_2 * n * n + b_2 * b_2);
-- atan2 is preferred over atan because it accurately computes the angle of
-- a point (x, y) in all quadrants, handling the signs of both coordinates.
if (a_1 /= 0.0) or (b_1 /= 0.0) then
h_1 := Math.Arctan(b_1, a_1 * n);
if h_1 < 0.0 then h_1 := h_1 + 2.0 * m_pi; end if;
else h_1 := 0.0; end if;
if (a_2 /= 0.0) or (b_2 /= 0.0) then
h_2 := Math.Arctan(b_2, a_2 * n);
if h_2 < 0.0 then h_2 := h_2 + 2.0 * m_pi; end if;
else h_2 := 0.0; end if;
if h_1 < h_2 then n := h_2 - h_1; else n := h_1 - h_2; end if;
-- Cross-implementation consistent rounding.
if m_pi - 1.0E-14 < n and n < m_pi + 1.0E-14 then
n := m_pi;
end if;
-- When the hue angles lie in different quadrants, the straightforward
-- average can produce a mean that incorrectly suggests a hue angle in
-- the wrong quadrant, the next lines handle this issue.
h_m := (h_1 + h_2) * 0.5;
h_d := (h_2 - h_1) * 0.5;
if m_pi < n then
h_d := h_d + m_pi;
-- 📜 Sharma’s formulation doesn’t use the next line, but the one after it,
-- and these two variants differ by ±0.0003 on the final color differences.
h_m := h_m + m_pi;
-- if h_m < m_pi then h_m := h_m + m_pi; else h_m := h_m - m_pi; end if;
end if;
p := 36.0 * h_m - 55.0 * m_pi;
n := (c_1 + c_2) * 0.5;
n := n * n * n * n * n * n * n;
-- The hue rotation correction term is designed to account for the
-- non-linear behavior of hue differences in the blue region.
r_t := -2.0 * Math.Sqrt(n / (n + 6103515625.0)) *
Math.Sin(m_pi / 3.0 *
Math.Exp(p * p / (-25.0 * m_pi * m_pi)));
n := (l_1 + l_2) * 0.5;
n := (n - 50.0) * (n - 50.0);
-- Lightness.
l := (l_2 - l_1) / (k_l * (1.0 + 0.015 * n / Math.Sqrt(20.0 + n)));
-- These coefficients adjust the impact of different harmonic
-- components on the hue difference calculation.
t := 1.0 + 0.24 * Math.Sin(2.0 * h_m + m_pi / 2.0) +
0.32 * Math.Sin(3.0 * h_m + 8.0 * m_pi / 15.0) -
0.17 * Math.Sin(h_m + m_pi / 3.0) -
0.20 * Math.Sin(4.0 * h_m + 3.0 * m_pi / 20.0);
n := c_1 + c_2;
-- Hue.
h := 2.0 * Math.Sqrt(c_1 * c_2) *
Math.Sin(h_d) / (k_h * (1.0 + 0.0075 * n * t));
-- Chroma.
c := (c_2 - c_1) / (k_c * (1.0 + 0.0225 * n));
-- Returning the square root ensures that dE00 accurately reflects the
-- geometric distance in color space, which can range from 0 to around 185.
return Math.Sqrt(l * l + h * h + c * c + c * h * r_t);
end ciede_2000;
-- GitHub Project : https://github.com/michel-leonard/ciede2000-color-matching
-- Online Tests : https://michel-leonard.github.io/ciede2000-color-matching
-- L1 = 74.5 a1 = 47.9 b1 = 4.1
-- L2 = 74.8 a2 = 53.8 b2 = -4.2
-- CIE ΔE00 = 4.5097679907 (Bruce Lindbloom, Netflix’s VMAF, ...)
-- CIE ΔE00 = 4.5097525960 (Gaurav Sharma, OpenJDK, ...)
-- Deviation between implementations ≈ 1.5e-5
-- See the source code comments for easy switching between these two widely used ΔE*00 implementation variants.Parameter k_l, k_c und k_h
Die Parameter k_l, k_c und k_h in der CIEDE2000-Formel sind Gewichtungsfaktoren, die jeweils auf die Komponenten Helligkeit (ΔL*), Chroma (ΔC*) und Farbton (ΔH*) angewendet werden. Im Quellcode sind sie als Konstanten definiert, deren Standardwert 1 ist; dies entspricht den von der Internationalen Beleuchtungskommission (CIE) festgelegten Standardbeobachtungsbedingungen. In der Praxis kann es erforderlich sein, diese Koeffizienten an spezifische Bedingungen anzupassen: So wird k_l = 2 manchmal verwendet, um Helligkeitsunterschiede stärker zu gewichten (was in der Textilindustrie häufig vorkommt), während k_c oder k_h je nach den Anforderungen reduziert werden können, um die Toleranz für Sättigungs- oder Farbtonschwankungen zu erhöhen. Je nach Kontext liegen diese Koeffizienten normalerweise zwischen 0,5 und 2.
Genauigkeit und Zuverlässigkeit des Quellcodes
Der Unterschied zwischen der akademischen Formulierung von Sharma und der vereinfachten Formulierung von Lindbloom beträgt nicht mehr als ±0,0003 auf dem endgültigen ΔE2000. Dies entspricht dem Unterschied, der normalerweise zwischen zwei 32-Bit-Implementierungen gemessen wird und für das menschliche Auge nicht wahrnehmbar ist. Unsere 64-Bit-Implementierungen, die alle miteinander übereinstimmen, garantieren mindestens 10 korrekte Nachkommastellen, so dass die Wahl der einen Formulierung gegenüber der anderen ein technisches Detail ist. Die Standardformel auf dieser Seite ist diejenige, die in der Community am häufigsten verwendet wird, sie ist etwas einfacher zu vektorisieren.
✎ Wenn Sie feststellen, dass die Kommentare im Quellcode nicht mit den Kommentaren in Englisch übereinstimmen, informieren Sie bitte den Autor der Seite, damit dies korrigiert werden kann.
Wie kann man RGB-Farben in L*a*b* umwandeln?
Gehen Sie auf die AWK, C, Dart, Java, JavaScript, Kotlin, Lua, PHP, Python, Ruby oder Rust-Seite, wo ein solcher Konverter (unter Verwendung der Lichtart D65) bereits zusätzlich zur Farbabstandsfunktion implementiert ist.
Wertebereiche in CIELAB und Interpretation des ΔE2000
Im CIELAB-Farbraum steht die Komponente L* für die Helligkeit und reicht normalerweise von 0 (schwarz) bis 100 (weiß). Die Komponenten a* und b* beschreiben die Farbachsen: a* verläuft von Grün nach Rot, b* von Blau nach Gelb. In der Praxis sind die Werte von a* und b* fast immer auf einen Bereich zwischen -128 und +127 beschränkt, obwohl der Standard keine offizielle Grenze für diese beiden Komponenten festlegt.
| Farbe 1 | Farbe 2 | Wert des ΔE2000 |
|---|---|---|
| 1 | ||
| 2 | ||
| 3 |
| Farbe 1 | Farbe 2 | Wert des ΔE2000 |
|---|---|---|
| 5 | ||
| 10 | ||
| 15 |
ΔE2000 (CIEDE2000) gibt den wahrgenommenen Unterschied zwischen zwei Farben an: 0 bedeutet identische Farben, höhere Werte (bis zu 185 und mehr) zeigen eine stärkere Abweichung. Beispielsweise entsprechen Werte um 5 eher ähnlichen Farben, während Werte um 15 deutlich unterschiedliche Farben anzeigen. Wenn der Wert ΔE2000 40 übersteigt, haben die verglichenen Farben praktisch nichts mehr gemeinsam, und wir können daraus keine genauen Informationen mehr ableiten.
Anwendungsbeispiel in Ada
-- Compute the Delta E (CIEDE2000) color difference between two L*a*b* colors in Ada
-- Color 1: l1 = 28.9, a1 = 47.5, b1 = 2.0
-- Color 2: l2 = 28.8, a2 = 41.6, b2 = -1.7
deltaE := ciede_2000(l1, a1, b1, l2, a2, b2);
Put(deltaE, Fore => 1, Aft => 15, Exp => 0);
New_Line;
-- .................................................. This shows a ΔE2000 of 2.7749016764
-- As explained in the comments, compliance with Gaurav Sharma would display 2.7749152801Testergebnisse
Der in der Sprache C99 geschriebene und mit 250 präzisen statischen Tests versehene Treiber hat bewiesen, dass diese Ada-Funktion mit der in anderen Programmiersprachen zur Verfügung gestellten CIEDE2000-Funktion interoperabel ist.
CIEDE2000 Verification Summary :
First Verified Line : 27,-123,101,44,42.0000098,-99,70.204734814936884
Duration : 37.68 s
Successes : 10000000
Errors : 0
Average Delta E : 63.0868
Average Deviation : 7.2e-15
Maximum Deviation : 2.7e-13Dateien zum Herunterladen
Verwenden Sie diese von Michel zur Verfügung gestellten Dateien frei, auch für kommerzielle Zwecke.
| Datei | Größe | Anzahl der Klicks |
|---|---|---|
| ciede-2000.adb | 4 KB | 78 |
| ciede-2000-driver.adb | 6 KB | 93 |
| test-adb.yml | 3 KB | 40 |
| reference-dataset.txt | 4 KB | 378 |
| Klicken Sie auf adb.zip, um alle Dateien in einem Archiv herunterzuladen. | ||
Gemeinschaft
Was halten Sie von diesem Quellcode oder von CIEDE2000? Ihre Meinung ist uns wichtig! Das Gästebuch enthält bereits 9 Einträge - davon 1 auf Deutsch. Schauen Sie sich dort um und teilen Sie Ihre Meinung mit.