// Conversion from RGB to CIELAB, using illuminant D65. public static LabColor ToLab(this Color color) { // RGB are assumed to be in [0...255] range double R = color.R / 255d; double G = color.G / 255d; double B = color.B / 255d; // CIEXYZ coordinates are normalized to [0...1] double x = 0.4124564 * R + 0.3575761 * G + 0.1804375 * B; double y = 0.2126729 * R + 0.7151522 * G + 0.0721750 * B; double z = 0.0193339 * R + 0.1191920 * G + 0.9503041 * B; double xRatio = x / XN; double yRatio = y / YN; double zRatio = z / ZN; LabColor result = new LabColor { // L is normalized to [0...100] L = 116 * XyzToLab(yRatio) - 16, a = 500 * (XyzToLab(xRatio) - XyzToLab(yRatio)), b = 200 * (XyzToLab(yRatio) - XyzToLab(zRatio)) }; return(result); }
static double GetSingleValue(SortingTask task, int x, int y) { Color c = task.OriginalImage.GetPixel(x, y); switch (task.Metric) { case SortMetric.Intensity: return(c.GetIntensity()); case SortMetric.Lightness: return(c.GetLightness()); case SortMetric.Value: return(Math.Max(c.R, Math.Max(c.G, c.B))); case SortMetric.Luma: return(c.R * 0.2126 + c.G * 0.7152 + c.B * 0.0722); case SortMetric.HslHue: return(c.GetHue() / 360d); case SortMetric.LabHue: { LabColor labC = c.ToLab(); if (labC.a == 0) { return(Math.PI / 2); } else { double lh = Math.Atan2(labC.b, labC.a); if (lh <= 0) { lh = Math.PI * 2 - Math.Abs(lh); } return(lh); } } case SortMetric.Chroma: return(c.GetChroma()); case SortMetric.LabChroma: { LabColor labColor = c.ToLab(); return(Math.Sqrt(labColor.a * labColor.a + labColor.b * labColor.b)); } case SortMetric.HsbSaturation: { double chroma = c.GetChroma(); if (chroma == 0) { return(0); } else { return(chroma / c.GetMax()); } } case SortMetric.HsiSaturation: { double chroma = c.GetChroma(); double intensity = c.GetIntensity(); if (chroma == 0 || intensity == 0) { return(0); } else { double m = c.GetMin(); return(1 - m / intensity); } } case SortMetric.HslSaturation: { double max = c.GetMax(); double min = c.GetMin(); double chroma = c.GetChroma(); double L = c.GetLightness(); if (chroma == 0 || L == 0 || L == 1) { return(0); } if (L < 0.5) { return(chroma / (max + min)); } else { return(chroma / (2 - max - min)); } } case SortMetric.LabSaturation: { LabColor labColor = c.ToLab(); if (labColor.L < ColorUtil.LinearThreshold) { return(0); } else { return(Math.Sqrt(labColor.a * labColor.a + labColor.b * labColor.b) / labColor.L); } } case SortMetric.RedChannel: return(c.R); case SortMetric.GreenChannel: return(c.G); case SortMetric.BlueChannel: return(c.B); case SortMetric.Red: return(c.R - Math.Max(c.G, c.B)); case SortMetric.Green: return(c.G - Math.Max(c.R, c.B)); case SortMetric.Blue: return(c.B - Math.Max(c.R, c.G)); case SortMetric.Cyan: return((c.G + c.B) - Math.Max(c.R * 1.5, Math.Abs(c.G - c.B))); case SortMetric.Magenta: return((c.R + c.B) - Math.Max(c.G * 1.5, Math.Abs(c.R - c.B))); case SortMetric.Yellow: return((c.R + c.G) - Math.Max(c.B * 1.5, Math.Abs(c.R - c.G))); case SortMetric.LabA: return(c.ToLab().a); case SortMetric.LabB: return(c.ToLab().b); default: throw new ArgumentOutOfRangeException(); } }