如何比较颜色对象,并得到最接近的颜色在颜色?

比方说,我有一个颜色的arrays(整个色谱,从红色到红色)。 较短的版本将如下所示:

public Color[] ColorArray = new Color[360] { Color.FromArgb(255, 245, 244, 242), Color.FromArgb(255, 245, 244, 240), Color.FromArgb(255, 245, 244, 238) } 

现在如果我有一个单独的

 Color object (Color c = Color.FromArgb(255, 14, 4, 5)) 

我怎样才能得到最接近所选颜色的数组中的值? 这甚至有可能吗?

色距不是一个精确定义的东西。 所以这里有三种方法来衡量它:

  • 一种检查颜色色调的方法,忽略饱和度和亮度
  • 一个只能测量RGB空间中的直接距离
  • 还有一种以某种方式来衡量色调,饱和度和亮度。

很明显,你可能想改变第三次测量中的魔术数字:色调在0-360,亮度和饱和度在0-1,所以这些数字的色调比饱和度和亮度强大约3.6倍。

更新 :我发布的原始解决scheme包含几个错误:

  • 我使用的Linq没有find最接近但最接近的FromBelow; 这意味着有50%的机会被一个人拒之门外。
  • 在一些地方,我使用了color.GetBrightness()方法。 这是说,温和地,完全没用。 换句话说, BlueYellow的值是0.5
  • 色调的值从0-360,但当然他们环绕! 我完全错过了

我用正确的代码replace了大部分的原始答案:

这些现在是方法的新版本,每个版本都返回最接近匹配的索引:

 // closed match for hues only: int closestColor1(List<Color> colors, Color target) { var hue1 = target.GetHue(); var diffs = colors.Select(n => getHueDistance(n.GetHue(), hue1)); var diffMin = diffs.Min(n => n); return diffs.ToList().FindIndex(n => n == diffMin); } // closed match in RGB space int closestColor2(List<Color> colors, Color target) { var colorDiffs = colors.Select(n => ColorDiff(n, target)).Min(n =>n); return colors.FindIndex(n => ColorDiff(n, target) == colorDiffs); } // weighed distance using hue, saturation and brightness int closestColor3(List<Color> colors, Color target) { float hue1 = target.GetHue(); var num1 = ColorNum(target); var diffs = colors.Select(n => Math.Abs(ColorNum(n) - num1) + getHueDistance(n.GetHue(), hue1) ); var diffMin = diffs.Min(x => x); return diffs.ToList().FindIndex(n => n == diffMin); } 

一些帮手function:

  // color brightness as perceived: float getBrightness(Color c) { return (cR * 0.299f + cG * 0.587f + cB *0.114f) / 256f;} // distance between two hues: float getHueDistance(float hue1, float hue2) { float d = Math.Abs(hue1 - hue2); return d > 180 ? 360 - d : d; } // weighed only by saturation and brightness (from my trackbars) float ColorNum(Color c) { return c.GetSaturation() * factorSat + getBrightness(c) * factorBri; } // distance in RGB space int ColorDiff(Color c1, Color c2) { return (int ) Math.Sqrt((c1.R - c2.R) * (c1.R - c2.R) + (c1.G - c2.G) * (c1.G - c2.G) + (c1.B - c2.B)*(c1.B - c2.B)); } 

这里是我用于截图文本的方便的小帮手:

 Brush tBrush(Color c) { return getBrightness(c) < 0.5 ? Brushes.White : Brushes.Black; } 

我已经更新了屏幕截图,不仅显示13种颜色,而且还显示一些大部分偏红的颜色供testing; 所有的颜色都显示出他们的色调,饱和度和亮度值。 最后三个数字是三种方法的结果。

正如你所看到的那样,简单的距离方法对于明亮和不饱和的颜色来说是相当具有误导性的色调:最后一种颜色(象牙色)实际上是一种明亮的淡黄色!

测量所有颜色属性的第三种方法是最好的。 虽然你应该玩弄测量数字!

最后,这取决于你想达到什么目的。 如果看起来你只关心颜色的色调,那么只需要第一种方法! 你可以使用你的数组来调用它:

 int indexInArray = closestColor1(clist.ToList(), someColor); 

有关色距的更多信息, 请参阅维基百科 !

色距

 // the colors I used: // your array Color[] clist = new Color[13]; clist[0] = Color.Blue; clist[1] = Color.BlueViolet; clist[2] = Color.Magenta; clist[3] = Color.Purple; clist[4] = Color.Red; clist[5] = Color.Tomato; clist[6] = Color.Orange; clist[7] = Color.Yellow; clist[8] = Color.YellowGreen; clist[9] = Color.Green; clist[10] = Color.SpringGreen; clist[11] = Color.Cyan; clist[12] = Color.Ivory; // and a list of color to test: List<Color> targets = new List<Color>(); targets.Add(Color.Pink); targets.Add(Color.OrangeRed); targets.Add(Color.LightPink); targets.Add(Color.DarkSalmon); targets.Add(Color.LightCoral); targets.Add(Color.DarkRed); targets.Add(Color.IndianRed); targets.Add(Color.LavenderBlush); targets.Add(Color.Lavender); 

尝试这个:

  static void Main() { Color[] ColorArray = { Color.FromArgb(255, 245, 244, 242), Color.FromArgb(255, 245, 244, 240), Color.FromArgb(255, 245, 244, 238) }; var closest = GetClosestColor(ColorArray, Color.FromArgb(255, 245, 244, 241)); Console.WriteLine(closest); } private static Color GetClosestColor(Color[] colorArray, Color baseColor) { var colors = colorArray.Select(x => new {Value = x, Diff = GetDiff(x, baseColor)}).ToList(); var min = colors.Min(x => x.Diff); return colors.Find(x => x.Diff == min).Value; } private static int GetDiff(Color color, Color baseColor) { int a = color.A - baseColor.A, r = color.R - baseColor.R, g = color.G - baseColor.G, b = color.B - baseColor.B; return a*a + r*r + g*g + b*b; } 

在这里,我将ARGB空间中closest欧几里得的距离解释