.NET中3种颜色之间的颜色插值

时间:2009-08-06 02:26:04

标签: .net colors interpolation system.drawing.color

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

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

据我所知,您可以将每个RGB三元组视为三维空间中的坐标。我正在寻找的是一种快速而肮脏的线性插值技巧,可以与.NET Color类型的特定布局(ARGB的单独值等)一起干净地工作。

2 个答案:

答案 0 :(得分:15)

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

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,则将lambda乘以2并返回颜色A和颜色B之间的插值颜色。如果参数大于0.5,将lambda乘以2并减去一(将[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重载。

答案 1 :(得分:1)

另一种使用高斯分布混合颜色的方法(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种颜色的样本:

enter image description here