public static double CIELab94(CIELab lab1, CIELab lab2) { var sl = 1.0; var kl = 1.0; var kc = 1.0; var kh = 1.0; var c1 = Math.Sqrt(lab1.A * lab1.A + lab1.B * lab1.B); var c2 = Math.Sqrt(lab2.A * lab2.A + lab2.B * lab2.B); var dl = lab2.L - lab1.L; var dc = c2 - c1; var de = CIELabOriginal(lab1, lab2); var dh = 0.0; if ((de * de) > (dl * dl + dc * dc)) { dh = Math.Sqrt(de * de - dl * dl - dc * dc); } var sc = 1.0 + 0.045 * c1; var sh = 1.0 + 0.015 * c1; return(Math.Sqrt((dl / (kl * sl)) * (dl / (kl * sl)) + (dc / (kc * sc)) * (dc / (kc * sc)) + (dh / (kh * sh)) * (dh / (kh * sh)))); }
public static double CIELabOriginal(CIELab lab1, CIELab lab2) { var dl = lab2.L - lab1.L; var da = lab2.A - lab1.A; var db = lab2.B - lab1.B; return(Math.Sqrt(dl * dl + da * da + db * db)); }
//by http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf public static double CIELab2000(CIELab lab1, CIELab lab2) { //step 1 var c1 = Math.Sqrt(lab1.A * lab1.A + lab1.B * lab1.B); var c2 = Math.Sqrt(lab2.A * lab2.A + lab2.B * lab2.B); var averageC = (c1 + c2) / 2.0; var g = 0.5 * (1.0 - Math.Sqrt(Math.Pow(averageC, 7.0) / (Math.Pow(averageC, 7.0) + 6103515625.0))); var a1 = (1.0 + g) * lab1.A; var a2 = (1.0 + g) * lab2.A; var c11 = Math.Sqrt(a1 * a1 + lab1.B * lab1.B); var c12 = Math.Sqrt(a2 * a2 + lab2.B * lab2.B); var h1 = 0.0; if (lab1.B != 0.0 || a1 != 0.0) { if (lab1.B >= 0) { h1 = Math.Atan2(lab1.B, a1) * 180.0 / Math.PI; } else { h1 = Math.Atan2(lab1.B, a1) * 180.0 / Math.PI + 360.0; } } var h2 = 0.0; if (lab2.B != 0.0 || a2 != 0.0) { if (lab2.B >= 0) { h2 = Math.Atan2(lab2.B, a2) * 180.0 / Math.PI; } else { h2 = Math.Atan2(lab2.B, a2) * 180.0 / Math.PI + 360.0; } } //step2 var dh = 0.0; if (c11 * c12 != 0.0) { if ((h2 - h1 <= 180.0) && (h2 - h1) >= -180.0) { dh = h2 - h1; } else if ((h2 - h1) > 180.0) { dh = h2 - h1 - 360.0; } else if ((h2 - h1) < -180.0) { dh = h2 - h1 + 360.0; } } var dH = 2.0 * Math.Sqrt(c11 * c12) * Math.Sin((dh / 2.0) * Math.PI / 180.0); //step 3 var averageL = (lab2.L + lab1.L) / 2.0; var averageC1 = (c11 + c12) / 2.0; var averageh = h1 + h2; if (c11 * c12 != 0.0) { if ((h2 - h1) >= -180.0 && (h2 - h1) <= 180.0) { averageh = (h1 + h2) / 2.0; } else if (Math.Abs(h2 - h1) > 180.0 && (h2 + h1) < 360.0) { averageh = (h1 + h2) / 2.0 + 180.0; } else if (Math.Abs(h2 - h1) > 180.0 && (h2 + h1) >= 360.0) { averageh = (h1 + h2) / 2.0 - 180.0; } } var lave50 = (averageL - 50.0) * (averageL - 50.0); var sl = 1.0 + (0.015 * lave50) / (Math.Sqrt(20.0 + lave50)); var sc = 1.0 + 0.045 * averageC1; var t = 1.0 - 0.17 * Math.Cos((averageh - 30.0) * Math.PI / 180.0) + 0.24 * Math.Cos((2.0 * averageh) * Math.PI / 180.0) + 0.32 * Math.Cos((3.0 * averageh + 6.0) * Math.PI / 180.0) - 0.2 * Math.Cos((4.0 * averageh - 63) * Math.PI / 180.0); var sh = 1.0 + 0.015 * averageC1 * t; var dteta = 30.0 * Math.Exp(-1 * (Math.Pow((averageh - 275.0) / 25.0, 2.0))); var rc = 2.0 * Math.Sqrt(Math.Pow(averageC1, 7.0) / (Math.Pow(averageC1, 7.0) + 6103515625.0)); var rt = -Math.Sin((2.0 * dteta) * Math.PI / 180.0) * rc; var deltal = lab2.L - lab1.L; var deltac = c12 - c11; const double kl = 1.0; const double kc = 1.0; const double kh = 1.0; var first = deltal / kl / sl; var second = deltac / kc / sc; var third = dH / kh / sh; return(Math.Sqrt(first * first + second * second + third * third + rt * second * third)); }