7

我想根据某个变量的值将颜色从颜色 A(我们称之为红色)平滑地插值到颜色 C(我们称之为绿色)通过颜色 B(我们称之为黄色)。

如果变量 = 100,我想要纯绿色。如果变量 = 50,我想要纯黄色。如果变量 = 0,我想要纯红色。

我知道您可以将每个 RGB 三元组视为 3 维空间中的坐标。我正在寻找的是一种快速而肮脏的线性插值技巧,它可以与 .NET 颜色类型的特定布局(ARGB 等的单独值)完美配合。

4

2 回答 2

16

首先,您要求进行线性插值,但没有指定颜色 B 位于颜色 A 和颜色 C 之间的线上;这是必要的。其次,您没有指定,但我将做一个简化的假设,即颜色 B 是颜色 A 和颜色 C 之间的线的中点;如果不是这样,以下代码很容易修改。最后,我改变了你的假设,即参数是介于零和一百之间的整数,是介于零和一之间的双精度数。在后一种情况下,代码更容易编写和理解,并且仍然可以与前者一起使用(将您的输入除以 100)。

class ColorInterpolator {
    delegate byte ComponentSelector(Color color);
    static ComponentSelector _redSelector = color => color.R;
    static ComponentSelector _greenSelector = color => color.G;
    static ComponentSelector _blueSelector = color => color.B;

    public static Color InterpolateBetween(
        Color endPoint1,
        Color endPoint2,
        double lambda) {
        if (lambda < 0 || lambda > 1) {
            throw new ArgumentOutOfRangeException("lambda");
        }
        Color color = Color.FromRgb(
            InterpolateComponent(endPoint1, endPoint2, lambda, _redSelector),
            InterpolateComponent(endPoint1, endPoint2, lambda, _greenSelector),
            InterpolateComponent(endPoint1, endPoint2, lambda, _blueSelector)
        );

        return color;
    }

    static byte InterpolateComponent(
        Color endPoint1,
        Color endPoint2,
        double lambda,
        ComponentSelector selector) {
        return (byte)(selector(endPoint1)
            + (selector(endPoint2) - selector(endPoint1)) * lambda);
    }
}

如果颜色 B 不是颜色 A 和颜色 C 之间的中点,你如何修改它?最简单的方法如下。如果参数(我称之为“ lambda”)小于0.5,乘以lambda2 并返回颜色 A 和颜色 B 之间的插值。如果参数大于0.5,乘以lambda2 并减 1(这映射[0.5, 1][0, 1])并返回颜色 B 和颜色 C 之间的插值颜色。

如果您不喜欢颜色 B 位于颜色 A 和颜色 C 之间的线上的要求,那么您可以完全使用我刚刚描述的修改在颜色之间进行分段线性插值。

最后,您没有指定是否要插入所谓的 alpha 值(“ARGB”中的“A”)。上面的代码也很容易修改以处理这种情况。再添加一个ComponentSelector定义为color => color.A,用于InterpolateComponent插入该值并使用 的Color.FromArgb(int, int, int, int)重载Color.FromArgb

于 2009-08-06T03:27:40.287 回答
4

使用像这样的高斯分布混合颜色的另一种方法(0.0 - 1.0 范围内的任意数量的颜色,以增加混合增加 sigma_2 值)

public static Color InterpolateColor(Color[] colors, double x)
{
    double r = 0.0, g = 0.0, b = 0.0;
    double total = 0.0;
    double step = 1.0 / (double)(colors.Length - 1);
    double mu = 0.0;
    double sigma_2 = 0.035;

    foreach (Color color in colors)
    {                
        total += Math.Exp(-(x - mu) * (x - mu) / (2.0 * sigma_2)) / Math.Sqrt(2.0 * Math.PI * sigma_2);
        mu += step;
    }

    mu = 0.0;
    foreach(Color color in colors)
    {                
        double percent = Math.Exp(-(x - mu) * (x - mu) / (2.0 * sigma_2)) / Math.Sqrt(2.0 * Math.PI * sigma_2);
        mu += step;

        r += color.R * percent / total;
        g += color.G * percent / total;
        b += color.B * percent / total;
    }

    return Color.FromArgb(255, (int)r, (int)g, (int)b);
}

更多信息http://en.wikipedia.org/wiki/Normal_distribution

混合 3 种颜色的示例:

在此处输入图像描述

于 2014-09-29T15:10:40.567 回答