Comparing Colors using Delta-E 1994 in C#
Continuing on with a previous post where I did a C# version of the Delta-E algorithm, which is really mostly just converting RGB to CIE-L*ab. Getting the delta score at that point is really pretty simple. I’ve had a chance now to convert one of the better algorithms now as well. To use the 1994 version below, just replace the CompareTo function in my original post with the one below. You could also overload it and pass in the K_1 and K_2 values as parameters, or create an enum to pass in as a parameter. I would recommend using a couple of existing values and eyeballing them if you’re not sure if you should use the graphics or textiles ones. Dark blues, teal, and tan were the ones that I used.
There is obviously a performance hit as it’s significantly more complex than the older version. I haven’t done any performance testing to compare the two yet, but I may post those in the future if I get a chance. I may do the CMC and 2000 formulas as well when I get some more time.
public int CompareTo(ColorFormulas oComparisionColor)
{
// Based upon the Delta-E (1994) formula at easyrgb.com (http://www.easyrgb.com/index.php?X=DELT&H=04#text4)
// Also referenced the python ColorMath project for factoring in textile vs screen: https://github.com/gtaylor/python-colormath/blob/master/colormath/color_diff.py
double CIE_L1 = CieL; //Color #1 CIE-L*ab values
double CIE_a1 = CieA;
double CIE_b1 = CieB;
double CIE_L2 = oComparisionColor.CieL; //Color #2 CIE-L*ab values
double CIE_a2 = oComparisionColor.CieA;
double CIE_b2 = oComparisionColor.CieB;
double K_1 = 0.048; // 0.045 graphic arts, 0.048 textiles
double K_2 = 0.014; // 0.015 graphic arts, 0.014 textiles
double K_L = 2; // 1 default, 2 textiles
double K_C = 1;
double K_H = 1;
double xC1 = Math.Sqrt(Math.Pow(CIE_a1, 2) + Math.Pow(CIE_b1, 2));
double xC2 = Math.Sqrt(Math.Pow(CIE_a2, 2) + Math.Pow(CIE_b2, 2));
double S_L = 1;
double S_C = 1 + K_1 * xC1;
double S_H = 1 + K_2 * xC1;
double delta_L = CIE_L1 - CIE_L2;
double delta_C = xC1 - xC2;
double delta_a = CIE_a1 - CIE_a2;
double delta_b = CIE_b1 - CIE_b2;
double delta_H = 0;
double deltaHCalc = Math.Pow(delta_a, 2) + Math.Pow(delta_b, 2) - Math.Pow(delta_C, 2);
// Can't do a sqrt of a negative num
if (deltaHCalc < 0)
{
delta_H = 0;
}
else
{
delta_H = Math.Sqrt(deltaHCalc);
}
// Make double sure that delta_H is non-negative
if (Double.IsNaN(delta_H) || delta_H < 0) delta_H = 0;
double L_group = Math.Pow(delta_L / (K_L * S_L), 2);
double C_group = Math.Pow(delta_C / (K_C * S_C), 2);
double H_group = Math.Pow(delta_H / (K_H * S_H), 2);
double Delta94 = Math.Sqrt(L_group + C_group + H_group);
return Convert.ToInt16(Math.Round(Delta94));
}