如何根据 C# 中的值范围计算颜色?

发布于 2024-08-22 05:09:48 字数 385 浏览 5 评论 0原文

var colors = new Color[] { 
    Color.Blue, 
    Color.Green, 
    Color.Yellow, 
    Color.Orange, 
    Color.Red 
};

var min = 0;
var max = 400;

我试图根据另一个数字获取这些值之间的颜色。例如,如果我想要值为 350 的颜色,则它将是 50% 橙色和 50% 红色。

编辑 - 为了清晰起见,重新措辞

我能想到的唯一方法是在 Photoshop 中创建渐变图像,然后计算偏移量并获取像素 RGB 值。然而,这看起来非常老套,我想通过某种计算来做到这一点。

有什么想法吗?

var colors = new Color[] { 
    Color.Blue, 
    Color.Green, 
    Color.Yellow, 
    Color.Orange, 
    Color.Red 
};

var min = 0;
var max = 400;

I'm trying to get the color in between these values based on another number. So for example if I wanted to the color for the value 350, it would be 50% orange and 50% red.

EDIT - Reworded for clarity

The only way I can think of doing it is creating a gradient image in photoshop, then calculating the offset and grabbing the pixel RGB value. However this seems extremely hacky and I would like to do it by some kind of calculation.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

孤城病女 2024-08-29 05:09:48

您可以使用线性插值来混合 R、G 和 B 值(如果需要,还可以使用 A)。下面是 Windows 窗体项目的一些示例代码。只需添加一个范围为 0 到 400 的轨迹栏,并将轨迹栏的滚动事件连接到下面的处理程序:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    byte interpolate(byte a, byte b, double p)
    {
        return (byte)(a * (1 - p) + b * p);
    }

    private void trackBar1_Scroll(object sender, EventArgs e)
    {
        int v = trackBar1.Value;
        BackColor = getColor(v);
    }

    private Color getColor(int v)
    {
        SortedDictionary<int, Color> d = new SortedDictionary<int, Color>();
        d.Add(0, Color.Blue);
        d.Add(100, Color.Green);
        d.Add(200, Color.Yellow);
        d.Add(300, Color.Orange);
        d.Add(400, Color.Red);

        KeyValuePair<int, Color> kvp_previous = new KeyValuePair<int,Color>(-1, Color.Black);
        foreach (KeyValuePair<int, Color> kvp in d)
        {
            if (kvp.Key > v)
            {
                double p = (v - kvp_previous.Key) / (double)(kvp.Key - kvp_previous.Key);
                Color a = kvp_previous.Value;
                Color b = kvp.Value;
                Color c = Color.FromArgb(
                    interpolate(a.R, b.R, p),
                    interpolate(a.G, b.G, p),
                    interpolate(a.B, b.B, p));
                return c;
            }
            kvp_previous = kvp;
        }

        return Color.Black;
    }
}

您也可以按照 nobugz 的建议将这个想法与 HSL 颜色结合使用。

注意:此代码只是概念验证。在真实的应用程序中,您可能需要创建一个类来封装颜色选择逻辑,使其更加可定制,以及错误处理等。它也没有针对速度进行优化。如果速度是一个重要的考虑因素,那么您可能应该使用查找表。

You could use linear interpolation to mix the R, G and B values (and A if you want). Here's some example code for a Windows Form project. Just add a trackbar with range 0 to 400 and wire up the trackbar's scroll event to the handler below:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    byte interpolate(byte a, byte b, double p)
    {
        return (byte)(a * (1 - p) + b * p);
    }

    private void trackBar1_Scroll(object sender, EventArgs e)
    {
        int v = trackBar1.Value;
        BackColor = getColor(v);
    }

    private Color getColor(int v)
    {
        SortedDictionary<int, Color> d = new SortedDictionary<int, Color>();
        d.Add(0, Color.Blue);
        d.Add(100, Color.Green);
        d.Add(200, Color.Yellow);
        d.Add(300, Color.Orange);
        d.Add(400, Color.Red);

        KeyValuePair<int, Color> kvp_previous = new KeyValuePair<int,Color>(-1, Color.Black);
        foreach (KeyValuePair<int, Color> kvp in d)
        {
            if (kvp.Key > v)
            {
                double p = (v - kvp_previous.Key) / (double)(kvp.Key - kvp_previous.Key);
                Color a = kvp_previous.Value;
                Color b = kvp.Value;
                Color c = Color.FromArgb(
                    interpolate(a.R, b.R, p),
                    interpolate(a.G, b.G, p),
                    interpolate(a.B, b.B, p));
                return c;
            }
            kvp_previous = kvp;
        }

        return Color.Black;
    }
}

You could also use this idea with HSL colors as suggested by nobugz.

Note: This code is just proof-of-concept. In a real application you would want to create a class to encapsulate the color choosing logic, make it more customizable, and error handling, etc. It's also not optimized for speed. If speed is an important consideration then you should probably use a look-up table instead.

倚栏听风 2024-08-29 05:09:48

Mark Byers 的答案中有一个小错误,需要修改为:

if (kvp.Key > v)
{
    double p = (v - kvp_previous.Key) / (double)(kvp.Key - kvp_previous.Key);
    Color a = kvp_previous.Value;
    Color b = kvp.Value;
    Color c = Color.FromArgb(
        interpolate(a.R, b.R, p),
        interpolate(a.G, b.G, p),
        interpolate(a.B, b.B, p));
    return c;
}
else if (kvp.Key == v)
{
    return kvp.Value;
}

否则任何等于输入点之一的内容都将返回为黑色。
(我没有足够的声誉来评论他的答案,所以据我所知这是我唯一的办法)

There is one small bug in Mark Byers answer, it needs to be modified to:

if (kvp.Key > v)
{
    double p = (v - kvp_previous.Key) / (double)(kvp.Key - kvp_previous.Key);
    Color a = kvp_previous.Value;
    Color b = kvp.Value;
    Color c = Color.FromArgb(
        interpolate(a.R, b.R, p),
        interpolate(a.G, b.G, p),
        interpolate(a.B, b.B, p));
    return c;
}
else if (kvp.Key == v)
{
    return kvp.Value;
}

Otherwise anything that is equal to one of the input points is returned as Black.
(I don't have enough reputation to comment on his answer so as far as I know this is my only recourse)

苏大泽ㄣ 2024-08-29 05:09:48

推广解决方案的另一种方法

/// <summary>
/// Interpolate colors 0.0 - 1.0        
/// </summary>        
public static Color Interpolate(double percent, params Color[] colors)
{
    int left = (int)Math.Floor(percent * (colors.Length - 1));
    int right = (int)Math.Ceiling(percent * (colors.Length - 1));
    Color colorLeft = colors[left];
    Color colorRight = colors[right];

    double step = 1.0 / (colors.Length - 1);
    double percentRight = (percent - (left * step)) / step;
    double percentLeft = 1.0 - percentRight;

    Color outputColor = new Color();

    outputColor.R = (byte)(colorLeft.R * percentLeft + colorRight.R * percentRight);
    outputColor.G = (byte)(colorLeft.G * percentLeft + colorRight.G * percentRight);
    outputColor.B = (byte)(colorLeft.B * percentLeft + colorRight.B * percentRight);
    outputColor.A = (byte)(colorLeft.A * percentLeft + colorRight.A * percentRight);

    return outputColor;
}

Another way to generalize solution

/// <summary>
/// Interpolate colors 0.0 - 1.0        
/// </summary>        
public static Color Interpolate(double percent, params Color[] colors)
{
    int left = (int)Math.Floor(percent * (colors.Length - 1));
    int right = (int)Math.Ceiling(percent * (colors.Length - 1));
    Color colorLeft = colors[left];
    Color colorRight = colors[right];

    double step = 1.0 / (colors.Length - 1);
    double percentRight = (percent - (left * step)) / step;
    double percentLeft = 1.0 - percentRight;

    Color outputColor = new Color();

    outputColor.R = (byte)(colorLeft.R * percentLeft + colorRight.R * percentRight);
    outputColor.G = (byte)(colorLeft.G * percentLeft + colorRight.G * percentRight);
    outputColor.B = (byte)(colorLeft.B * percentLeft + colorRight.B * percentRight);
    outputColor.A = (byte)(colorLeft.A * percentLeft + colorRight.A * percentRight);

    return outputColor;
}
雪化雨蝶 2024-08-29 05:09:48

像这样的东西可能对你有用......不过,这完全未经测试。这个想法是,您计算出您需要的两种颜色,然后根据您可以计算的百分比值混合这两种颜色。正如所说,完全未经测试。

using System.Convert;

public static Color oddColorFunction(int value)
{
    Color colors = new Color[] { Color.Blue, Color.Green, Color.Yellow, Color.Orange, Color.Red };
    int min = 0;
    int max = 400;

    decimal range = max / colors.Length;

    Color leftColor = ToInt32(Decimal.Floor(value / range));
    Color rightColor = ToInt32(Decimal.Ceiling(value / range));

    return mixColors(colors[leftColor], colors[rightColor], ToInt32(Decimal.Round(value % range * 100)));
}

public static mixColors(Color colorA, Color colorB, int percentage)
{
    //combine colors here based on percentage
    //I'm to lazy to code this :P
}

Something like this might work for you...though, this is completely untested. The idea is that you calculate what two colors you need, and after that you mix these two based on the percentage value which you can calculate. As said, completely untested.

using System.Convert;

public static Color oddColorFunction(int value)
{
    Color colors = new Color[] { Color.Blue, Color.Green, Color.Yellow, Color.Orange, Color.Red };
    int min = 0;
    int max = 400;

    decimal range = max / colors.Length;

    Color leftColor = ToInt32(Decimal.Floor(value / range));
    Color rightColor = ToInt32(Decimal.Ceiling(value / range));

    return mixColors(colors[leftColor], colors[rightColor], ToInt32(Decimal.Round(value % range * 100)));
}

public static mixColors(Color colorA, Color colorB, int percentage)
{
    //combine colors here based on percentage
    //I'm to lazy to code this :P
}
脱离于你 2024-08-29 05:09:48

颜色具有属性 R、G 和 B 。您可以将输入值除以 100 以获得底部颜色(将其剪裁为 3)。添加一个以获得顶部颜色。然后从底部和顶部颜色中获取 R、G 和 B,根据值 % 100 创建每个颜色的加权平均值,并使用这些值创建一个新颜色。

Color has the properties R, G, and B. You can take your input value, divide it by 100 to get the bottom color (clipping it at 3). Add one to that to get the top color. Then grab R, G, and B from the bottom and top colors, create a weighted average of each based on value % 100, and make a new Color with those values.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文