根据亮度和饱和度,在颜色名称前添加“浅/鲜艳/淡/暗”。

3

我想获取最接近以下列表的颜色:

static List<Color> clist = new List<Color>()
    {
        Color.Black, Color.Brown, Color.Blue, Color.Green, Color.Red, Color.Yellow,
        Color.Gray, Color.Indigo, Color.Orange, Color.Pink, Color.Turquoise, Color.White
    };

我可以这样获得最接近的颜色,但我想根据颜色的亮度和饱和度添加:浅/深/鲜艳/明亮:

        static string closestColor2(List<Color> colors, Color target)
        {
            var colorDiffs = colors.Select(n => ColorDiff(n, target)).Min(n => n);
            int x = colors.FindIndex(n => ColorDiff(n, target) == colorDiffs);
            return colors[x].ToString();
        }

        static 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));
        }

1
你一定要在HSL或HSV颜色空间中计算距离(或者,如果你想变得更加高级,使用CIE或YUV等)。如果你想获得有意义的结果,就不能使用RGB颜色空间。如果仅仅色调不够,也需要使用其他组件。每个组件分配的权重取决于你自己。最好是将明度/值的权重赋予较高的比重,其次是色调,最后是饱和度。 - Cody Gray
还有哪些组件?我在颜色处理编程方面还很新。 - C. Cristi
对于HSL,其组成部分将是色相、饱和度和亮度。就像对于RGB一样,其组成部分是红色、绿色和蓝色。搜索“color distance c#”,这个主题已经有很多先前的讨论了。 - Cody Gray
3个回答

2

Color.GetBrightness() - https://msdn.microsoft.com/zh-cn/library/system.drawing.color.getbrightness.aspx - MrApnea
1
嗯,我正在和@FSDaniel交谈。不确定,但我猜你也可以做到:点击关闭并选择复制..至于你的问题,你可能需要研究这篇文章:https://dev59.com/pF4c5IYBdhLWcg3w7t_E#27375621?s=1|1.0432#27375621 - TaW
1
请注意,我之前已经给过你这个链接了:https://dev59.com/aUbRa4cB1Zd3GeqPwQBl#39142758?s=1|1.1144#39142758。 - TaW
在某些情况下,使用“淡/暗/鲜艳/浅”等解决方案会显示出类似于“淡暗蓝”的颜色,这相当令人困惑...我该如何更改以使其只显示一个颜色并在需要时进行更改? - C. Cristi
所以你想让我创建两个列表,一个包含我想要展示的颜色的RGB值,另一个包含期望的名称? - C. Cristi
显示剩余12条评论

1
我的建议是首先列出一份颜色列表。在你的回答中,你列出了一个小的颜色列表,但如果你愿意,你也可以随后添加全部141个颜色。

因此,请创建一个颜色列表:

    //List of Colors
    static List<Color> clist = new List<Color>{
        Color.Black, Color.Brown, Color.Blue, Color.LightSteelBlue, Color.Green, Color.Red, Color.Yellow,
        Color.Gray, Color.Indigo, Color.Orange, Color.Pink, Color.Turquoise, Color.White
    };

然后是另一个列表,列出您想要的颜色名称,包括“鲜艳的”、“深色的”等。

    //List of Color Names
    static List<string> cnlist = new List<string>{
        "Black", "Brown", "Blue", "Pale Light Blue", "Green", "Red", "Yellow",
        "Gray", "Indigo", "Orange", "Pink", "Turquoise", "White"
    };

你可以使用以下方法来找到最接近的颜色:
    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);
    }


    // 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));
    }

上述方法将返回列表中最接近颜色的索引,然后您可以使用相同的索引从颜色名称列表中获取指定的名称。这样,您就可以在每个颜色上获得所需的名称,而不需要依赖不完全准确的算法。由于颜色数量很少,编写名称只需要很少的时间,如前所述,您可以按照自己的意愿获得它们。
如果您想添加Color.*中存在的所有颜色,可以使用以下方法来获取它们:
private List<Color> GetAllColors() {
        var list = new List<Color>();
        var colorType = typeof(Color);
        var propInfos = colorType.GetProperties(BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.Public);
        foreach (var propInfo in propInfos) {
            var color = Color.FromName(propInfo.Name);
            list.Add(color);
        }
        return list;
    }

如果我想添加自定义RGB,我该怎么做? - C. Cristi

0
我找到了这段代码:
    string ColorName(Color c)
{
    List<float> hues = new List<float>()
    { 0, 15, 35, 44, 54, 63, 80, 160, 180, 200, 244, 280, 350, 360};
    List<string> hueNames = new List<string>()
        { "red", "orange-red", "orange", "yellow-orange", "yellow",
          "yellow-green",   "green"  , "blue-green" , "cyan", "blue", 
          "violet", "purple", "red" };

    float h = c.GetHue();
    float s = c.GetSaturation();
    float b = (c.R * 0.299f + c.G * 0.587f + c.B *0.114f) / 256f;

    string name = s < 0.35f ? "pale " : s > 0.8f ? "vivid " : "";
    name += b < 0.35f ? "dark " : b > 0.8f ? "light " : "";
    for (int i = 0; i < hues.Count - 1; i++)
        if (h >= hues[i] && h <= hues[i+1] )
        {
            name += hueNames[i];
            break;
        }
    return name;
}

这里

我尝试将它实现到你的代码中,像这样:

static string 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);
        var x = diffs.ToList().FindIndex(n => n == diffMin);

        Color c = colors[x];

        float h = c.GetHue();
        float s = c.GetSaturation();
        float b = (c.R * 0.299f + c.G * 0.587f + c.B * 0.114f) / 256f;

        string name = s < 0.35f ? "pale " : s > 0.8f ? "vivid " : "";
        name += b < 0.35f ? "dark " : b > 0.8f ? "light " : "";

        name += colors[x].ToString();

        return name;
    }

但是有些解决方案有时会同时显示类似"苍白深红色"/"苍白深蓝色"等的东西,这真的很令人困惑。如果你只想显示其中一个,你应该尝试类似的方法或考虑如何只显示一个。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接