C# 如何比较颜色对象并获得颜色[]中最接近的颜色?

C# 如何比较颜色对象并获得颜色[]中最接近的颜色?,c#,windows-runtime,win-universal-app,C#,Windows Runtime,Win Universal App,假设我有一个颜色数组(从红色到红色的整个光谱)。较短的版本如下所示: public Color[] ColorArray = new Color[360] { Color.FromArgb(255, 245, 244, 242), Color.FromArgb(255, 245, 244, 240), Color.FromArgb(255, 245, 244, 238) } int indexInArray = closestColor1(clist.ToList(), someColor);

假设我有一个颜色数组(从红色到红色的整个光谱)。较短的版本如下所示:

public Color[] ColorArray = new Color[360] { Color.FromArgb(255, 245, 244, 242), Color.FromArgb(255, 245, 244, 240), Color.FromArgb(255, 245, 244, 238) }
int indexInArray = closestColor1(clist.ToList(), someColor);
现在如果我有一个单独的

Color object (Color c = Color.FromArgb(255, 14, 4, 5))
如何获取数组中最接近选定颜色的值?这可能吗?

试试这个:

    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空间中的欧几里德距离

颜色距离不是一个精确定义的东西。以下是三种测量方法:

  • 一种只检查颜色的色调的方法,忽略饱和度和亮度
  • 仅在RGB空间中测量直接距离的仪器
  • 而一个在某种程度上衡量了色调、饱和度和亮度
显然,您可能需要在第三次测量中更改幻数:色调为0-360,亮度和饱和度为0-1,因此使用这些数字,色调的权重约为饱和度和亮度的3.6倍

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

  • 我使用的Linq没有找到最接近的,而是从下面找到最接近的;这就意味着有50%的机会被淘汰
  • 在某些地方,我使用了
    color.GetBrightness()
    方法。委婉地说,这是完全无用的。也就是说:
    蓝色
    黄色
    具有相同的值
    0.5
  • 色调的值在0-360之间,但它们当然是环绕的!我完全错过了
我已将大部分原始答案替换为更正代码:

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

// 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);
}
以下是我用于屏幕截图文本的便捷小助手:

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

//我使用的颜色:
//你的阵列
颜色[]clist=新颜色[13];
clist[0]=颜色。蓝色;
clist[1]=颜色为蓝紫色;
clist[2]=颜色。品红色;
clist[3]=颜色。紫色;
clist[4]=颜色。红色;
clist[5]=颜色。番茄;
clist[6]=颜色为橙色;
clist[7]=颜色。黄色;
clist[8]=颜色。黄绿色;
clist[9]=颜色。绿色;
clist[10]=Color.SpringGreen;
clist[11]=颜色为青色;
clist[12]=颜色。象牙色;
//以及要测试的颜色列表:
列表目标=新列表();
目标。添加(颜色。粉红色);
目标。添加(颜色。橙色);
目标。添加(颜色。浅粉色);
添加(Color.DarkSalmon);
targets.Add(Color.LightCoral);
targets.Add(Color.DarkRed);
目标。添加(颜色。印度红);
目标。添加(颜色。薰衣草色);
目标。添加(颜色。薰衣草色);

这是可能的,您只需要编写一个自定义比较器。。。您如何确定哪一个更接近白色,尽管超出了
(255,0255)
(0,255,255)
?您需要定义“更接近”的含义。通常这是显而易见的,但对于颜色来说,做一些额外的思考和测试可能是个好主意。直接方法简单地通过添加3个RGB通道的差异来测量距离;但也许你更愿意通过赋予色调更多的权重来衡量测量结果,而不是亮度和饱和度。。?所有这些值都可以在颜色类中直接访问..请参见我完全重写的答案!所以我有一个所有颜色的色轮,我得到一个RGB值。现在我想把选择器放在最匹配的颜色上。因此,如果RGB值为淡红色,则应位于色轮的淡红色部分。如果您只关心颜色的色调,尤其是如果您的颜色列表已完全饱和,请选择第一种方法!当亮度接近0或1时,色调的权重需要减小。瞧,我可以有两种非常接近、非常明亮(或非常暗)的颜色,但它们的色调可能会相差180度。这个有趣的概念可能非常有意义。第二种方法(RGB空间中的直接距离)基本上做了类似的事情。。
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);