如何比较出彩的对象,并以颜色[]得到最接近的颜色? [英] How to compare Color object and get closest Color in an Color[]?
问题描述
比方说,我有一个颜色数组(带全彩色光谱,从红色到红色)。一个较短的版本是这样的:
Let's say I have an array with colors (with the whole color spectrum, from red to red.). A shorter version would look like this:
public Color[] ColorArray = new Color[360] { Color.FromArgb(255, 245, 244, 242), Color.FromArgb(255, 245, 244, 240), Color.FromArgb(255, 245, 244, 238) }
现在,如果我有一个单独的
Now if I have a seperate
Color object (Color c = Color.FromArgb(255, 14, 4, 5))
我怎样才能在数组中的值是最接近所选颜色?而这甚至可能?
How can I get the value in the Array that is the closest to the selected color? And is this even possible?
推荐答案
颜色距离不是一个精确定义的东西。因此,这里有三的方法来衡量的:
Color distance is not a precisely defined thing. So here are three methods to measure it:
- ,检查只是色调<一种方法/ STRONG>的颜色,忽略两种饱和度和亮度
- 一个只测量了直接距离 RGB 空格
- 而一个重量色调,在某种程度上饱和度和亮度。
- One method that checks only the hues of the colors, ignoring both saturation and brightness
- One that only measures the direct distance in RGB space
- And one that weighs hue, saturation and brightness in some way.
显然,你可能要改变幻数在第3次测量:色相为0-360,亮度和饱和度都在0-1,因此与这些数字色调重量超过饱和度和亮度。
Obviously you may want to change the magic numbers in the 3rd measurement: hue is in 0-360, brightness and saturation are in 0-1, so with these numbers hue weighs about 3.6 times stronger than saturation and brightness..
更新:原来的解决方案,我贴有几处错误:
Update: The original solution I posted contained several errors:
- LINQ的我用没'找不到最接近的,但closestFromBelow;这意味着由一个被关闭50%的机会。
- 在某些地方我用了
color.GetBrightness()
方法。这是,说得客气一点,完全无用。即:蓝色
和黄
有相同的值0.5
! - 色相值从0-360去,但他们当然环绕!我错过了完全..
- The Linq I used didn't find the closest but the closestFromBelow; this meant a 50% chance of being off by one.
- In some places I used the
color.GetBrightness()
method. This is, to put it mildly, totally useless. To wit:Blue
andYellow
have the same value of0.5
! - The values for hue go from 0-360, but of course they wrap around! I missed that completely..
我已经取代最有修正的原代码的回答:
I have replaced most of the original answer with corrected code:
现在,这些都是方法的新版本,每区选出最接近的匹配的索引中找到:
These now are the new version of the methods, each returning the index of the closest match found:
// 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);
}
一些辅助函数:
A few helper functions:
// 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)); }
下面是我用的截图文本的方便小助手:
Here is the handy little helper I used for the screenshot texts:
Brush tBrush(Color c) { return getBrightness(c) < 0.5 ? Brushes.White : Brushes.Black; }
我已经更新了截图显示,不仅13种颜色,但也有一些主要的红颜色测试;所有颜色显示与他们的色调,饱和度和亮度值。 。最后三个数字是三种方法的结果。
I have updated the screenshot to display not only 13 colors but also a number of mostly reddish colors for testing; all colors are shown with their values for hue, saturation and brightness. The last three numbers are the results of the three methods.
正如你所看到的,简单的距离的方法是非常容易引起误解的色调明智的明亮和非饱和的色彩:最后一种颜色(象牙)实际上是一个充满生机和浅黄色的!
As you can see, the simple distance method is quite misleading hue-wise for bright and non-saturated colors: The last color (Ivory) is in fact a bright and pale yellow!
衡量了所有的颜色特性的第三种方法是最好的海事组织。你应该玩的计量数字,但!
The third method which gauges all color properties is best imo. You should play around with the gauging numbers, though!
在这真的取决于你想要达到什么样的底;如果,因为它似乎,你只在乎颜色的色调,简单地去为第一种方法!你可以调用它,使用阵列是这样的:
In the end it really depends on what you want to achieve; if, as it seems, you only care about the hues of the colors, simply go for the first method! You can call it, using your array like this:
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);
这篇关于如何比较出彩的对象,并以颜色[]得到最接近的颜色?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!