deltaE2000 function
ΔE CIE2000 between two Lab colors. Returns 0 for identical inputs and values up to ~100 for extreme contrasts.
Implementation follows Sharma et al. (2005), equations 1–10.
Implementation
double deltaE2000(Lab c1, Lab c2) {
const kL = 1.0;
const kC = 1.0;
const kH = 1.0;
final l1 = c1.l;
final a1 = c1.a;
final b1 = c1.b;
final l2 = c2.l;
final a2 = c2.a;
final b2 = c2.b;
final c1Star = math.sqrt(a1 * a1 + b1 * b1);
final c2Star = math.sqrt(a2 * a2 + b2 * b2);
final cMean = (c1Star + c2Star) / 2.0;
final cMean7 = math.pow(cMean, 7).toDouble();
final g = 0.5 * (1.0 - math.sqrt(cMean7 / (cMean7 + math.pow(25, 7))));
final a1Prime = a1 * (1.0 + g);
final a2Prime = a2 * (1.0 + g);
final c1Prime = math.sqrt(a1Prime * a1Prime + b1 * b1);
final c2Prime = math.sqrt(a2Prime * a2Prime + b2 * b2);
final h1Prime = _atan2Deg(b1, a1Prime);
final h2Prime = _atan2Deg(b2, a2Prime);
final dlPrime = l2 - l1;
final dcPrime = c2Prime - c1Prime;
double dhPrime;
if (c1Prime * c2Prime == 0) {
dhPrime = 0;
} else {
var diff = h2Prime - h1Prime;
if (diff > 180) {
diff -= 360;
} else if (diff < -180) {
diff += 360;
}
dhPrime = diff;
}
final dHPrime =
2.0 * math.sqrt(c1Prime * c2Prime) * math.sin(_deg2rad(dhPrime / 2.0));
final lMeanPrime = (l1 + l2) / 2.0;
final cMeanPrime = (c1Prime + c2Prime) / 2.0;
double hMeanPrime;
if (c1Prime * c2Prime == 0) {
hMeanPrime = h1Prime + h2Prime;
} else if ((h1Prime - h2Prime).abs() <= 180) {
hMeanPrime = (h1Prime + h2Prime) / 2.0;
} else if ((h1Prime + h2Prime) < 360) {
hMeanPrime = (h1Prime + h2Prime + 360) / 2.0;
} else {
hMeanPrime = (h1Prime + h2Prime - 360) / 2.0;
}
final t =
1.0 -
0.17 * math.cos(_deg2rad(hMeanPrime - 30)) +
0.24 * math.cos(_deg2rad(2 * hMeanPrime)) +
0.32 * math.cos(_deg2rad(3 * hMeanPrime + 6)) -
0.20 * math.cos(_deg2rad(4 * hMeanPrime - 63));
final dTheta =
30.0 * math.exp(-math.pow((hMeanPrime - 275) / 25, 2).toDouble());
final cMeanPrime7 = math.pow(cMeanPrime, 7).toDouble();
final rC = 2.0 * math.sqrt(cMeanPrime7 / (cMeanPrime7 + math.pow(25, 7)));
final lMinus50Sq = (lMeanPrime - 50) * (lMeanPrime - 50);
final sL = 1.0 + (0.015 * lMinus50Sq) / math.sqrt(20 + lMinus50Sq);
final sC = 1.0 + 0.045 * cMeanPrime;
final sH = 1.0 + 0.015 * cMeanPrime * t;
final rT = -math.sin(_deg2rad(2 * dTheta)) * rC;
final lTerm = dlPrime / (kL * sL);
final cTerm = dcPrime / (kC * sC);
final hTerm = dHPrime / (kH * sH);
return math.sqrt(
lTerm * lTerm + cTerm * cTerm + hTerm * hTerm + rT * cTerm * hTerm,
);
}