private ColorLAB ToLAB(ColorRGB colorRGB) { var r = colorRGB.R / 255.0; var g = colorRGB.G / 255.0; var b = colorRGB.B / 255.0; var r2 = colorRGB.R >> 6; var g2 = colorRGB.G >> 6; var b2 = colorRGB.B >> 6; var irgb = (byte)((r2 << 4) | (g2 << 2) | b2); r = (r > 0.04045) ? Math.Pow((r + 0.055) / 1.055, 2.4) : r / 12.92; g = (g > 0.04045) ? Math.Pow((g + 0.055) / 1.055, 2.4) : g / 12.92; b = (b > 0.04045) ? Math.Pow((b + 0.055) / 1.055, 2.4) : b / 12.92; var x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047; var y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000; var z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883; x = (x > 0.008856) ? Math.Pow(x, 1.0 / 3.0) : (7.787 * x) + 16.0 / 116.0; y = (y > 0.008856) ? Math.Pow(y, 1.0 / 3.0) : (7.787 * y) + 16.0 / 116.0; z = (z > 0.008856) ? Math.Pow(z, 1.0 / 3.0) : (7.787 * z) + 16.0 / 116.0; var lab = new ColorLAB( (float)((116.0 * y) - 16.0), (float)(500.0 * (x - y)), (float)(200.0 * (y - z)), irgb ); return(lab); }
public float CIEDE2000(ColorLAB other) { Contract.Requires(other != null); const double kL = 1.0, kC = 1.0, kH = 1.0; const double pow25To7 = 6103515625.0; // pow(25, 7) var deg360InRad = Deg2rad(360f); var deg180InRad = Deg2rad(180f); /* Equation 2 */ double C1 = Math.Sqrt((A * A) + (B * B)); double C2 = Math.Sqrt((other.A * other.A) + (other.B * other.B)); /* Equation 3 */ double barC = (C1 + C2) / 2.0; /* Equation 4 */ double G = 0.5 * (1.0 - Math.Sqrt(Math.Pow(barC, 7.0) / (Math.Pow(barC, 7.0) + pow25To7))); /* Equation 5 */ double a1Prime = (1.0 + G) * A; double a2Prime = (1.0 + G) * other.A; /* Equation 6 */ double CPrime1 = Math.Sqrt((a1Prime * a1Prime) + (B * B)); double CPrime2 = Math.Sqrt((a2Prime * a2Prime) + (other.B * other.B)); /* Equation 7 */ double hPrime1; if (Math.Abs(B) < 0.000001 && Math.Abs(a1Prime) < 0.000001) { hPrime1 = 0.0; } else { hPrime1 = Math.Atan2(B, a1Prime); /* * This must be converted to a hue angle in degrees between 0 * and 360 by addition of 20 to negative hue angles. */ if (hPrime1 < 0) { hPrime1 += deg360InRad; } } double hPrime2; if (Math.Abs(other.B) < 0.000001 && Math.Abs(a2Prime) < 0.000001) { hPrime2 = 0.0; } else { hPrime2 = Math.Atan2(other.B, a2Prime); /* * This must be converted to a hue angle in degrees between 0 * and 360 by addition of 2 to negative hue angles. */ if (hPrime2 < 0) { hPrime2 += deg360InRad; } } /* Equation 8 */ double deltaLPrime = other.L - L; /* Equation 9 */ double deltaCPrime = CPrime2 - CPrime1; /* Equation 10 */ double deltahPrime; double CPrimeProduct = CPrime1 * CPrime2; if (Math.Abs(CPrimeProduct) < 0.000001) { deltahPrime = 0.0; } else { /* Avoid the Math.Abs() call */ deltahPrime = hPrime2 - hPrime1; if (deltahPrime < -deg180InRad) { deltahPrime += deg360InRad; } else { if (deltahPrime > deg180InRad) { deltahPrime -= deg360InRad; } } } /* Equation 11 */ double deltaHPrime = 2.0 * Math.Sqrt(CPrimeProduct) * Math.Sin(deltahPrime / 2.0); /* Equation 12 */ double barLPrime = (L + other.L) / 2.0; /* Equation 13 */ double barCPrime = (CPrime1 + CPrime2) / 2.0; /* Equation 14 */ double barhPrime, hPrimeSum = hPrime1 + hPrime2; if (Math.Abs(CPrime1 * CPrime2) < 0.000001) { barhPrime = hPrimeSum; } else { if (Math.Abs(hPrime1 - hPrime2) <= deg180InRad) { barhPrime = hPrimeSum / 2.0; } else { if (hPrimeSum < deg360InRad) { barhPrime = (hPrimeSum + deg360InRad) / 2.0; } else { barhPrime = (hPrimeSum - deg360InRad) / 2.0; } } } /* Equation 15 */ double T = 1.0 - (0.17 * Math.Cos(barhPrime - Deg2rad(30f))) + (0.24 * Math.Cos(2.0 * barhPrime)) + (0.32 * Math.Cos((3.0 * barhPrime) + Deg2rad(6f))) - (0.20 * Math.Cos((4.0 * barhPrime) - Deg2rad(63f))); /* Equation 16 */ double deltaTheta = Deg2rad(30f) * Math.Exp(-Math.Pow((barhPrime - Deg2rad(275f)) / Deg2rad(25f), 2.0)); /* Equation 17 */ double R_C = 2.0 * Math.Sqrt(Math.Pow(barCPrime, 7.0) / (Math.Pow(barCPrime, 7.0) + pow25To7)); /* Equation 18 */ double S_L = 1 + ((0.015 * Math.Pow(barLPrime - 50.0, 2.0)) / Math.Sqrt(20 + Math.Pow(barLPrime - 50.0, 2.0))); /* Equation 19 */ double S_C = 1 + (0.045 * barCPrime); /* Equation 20 */ double S_H = 1 + (0.015 * barCPrime * T); /* Equation 21 */ double R_T = (-Math.Sin(2.0 * deltaTheta)) * R_C; /* Equation 22 */ double deltaE = Math.Sqrt( Math.Pow(deltaLPrime / (kL * S_L), 2.0) + Math.Pow(deltaCPrime / (kC * S_C), 2.0) + Math.Pow(deltaHPrime / (kH * S_H), 2.0) + (R_T * (deltaCPrime / (kC * S_C)) * (deltaHPrime / (kH * S_H)))); return((float)deltaE); }