gpt4 book ai didi

c# - 如何比较 Color 对象并获得 Color[] 中最接近的 Color?

转载 作者:太空狗 更新时间:2023-10-29 19:51:53 28 4
gpt4 key购买 nike

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

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 空间中的直接距离
  • 还有一个以某种方式权衡色调、饱和度和亮度的。

显然,您可能想更改第三次测量中的魔数(Magic Number):色相在 0-360 之间,亮度和饱和度在 0-1 之间,因此对于这些数字,色相比饱和度和亮度强约 3.6 倍..

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

  • 我用的Linq没有找到最近的而是找到了closestFromBelow;这意味着有 50% 的机会被淘汰。
  • 在某些地方我使用了 color.GetBrightness() 方法。委婉地说,这是完全没用的。即:BlueYellow 的值相同,都是 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);
}

一些辅助函数:

 // color brightness as perceived:
float getBrightness(Color c)
{ return (c.R * 0.299f + c.G * 0.587f + c.B *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)); }

这是我用于屏幕截图文本的方便小 helper :

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

我更新了屏幕截图,不仅显示了 13 种颜色,还显示了一些主要是红色的颜色以供测试;所有颜色都显示了它们的色调、饱和度和亮度值。最后三个数字是三种方法的结果。

如您所见,简单距离法对于明亮和不饱和的颜色在色调方面具有误导性:最后一种颜色(象牙色)实际上是明亮的淡黄色!

衡量所有颜色属性的第三种方法在我看来是最好的。不过,您应该使用测量数字!

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

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

有关 color distances see Wikipedia 的更多信息!

color distances

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

关于c# - 如何比较 Color 对象并获得 Color[] 中最接近的 Color?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27374550/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com