5

我想随着时间的推移(240 小时)将颜色从亮绿色更改为深红色。我能看到的最好方法是将十六进制组合从 00FF00 更改为 FF0000。

我不知道如何在我的一生中从 00FF00 动态地计数到 FF0000。我正在查看超过 10 天的时间段,因此很可能需要超过 240 小时才能增加。

谁能帮我吗?

我从来没有上过算法课,所以我认为这可能与这个问题有关。

如果您有更好的方法来做到这一点,请告诉我。

我在这里寻找某种代码。多谢你们。它可以是任何语言,但不可避免地会转换为 C#。

4

5 回答 5

29

如果您按照十六进制值的建议从亮色变为亮色,那么您可能希望在HSV 空间而不是 RGB 空间中进行插值。HSV 空间近似于我们对颜色的看法——色调、饱和度和值。RGB 空间近似于我们眼睛中光敏细胞的工作方式。

上梯度是从 FF0000 到 00FF00 的线性 RGB 插值。它的中间值为7f7f00,一种泥褐色。

中间梯度是 HSV 空间中的线性插值。由于 FF0000 和 00FF00 都完全饱和并且具有相同的值(亮度),因此插值始终保持相同的亮度和饱和度,因此中心值是亮黄色 ffff00。

第三种选择是 RGB 空间中的矢量旋转,这意味着中间值为 B4B400,(B4 hex = 180 dec = 255 / sqrt(2)),介于两种效果之间。这是通过计算每个端点的大小来完成的,然后缩放 RGB 线性插值的结果,使其具有相同的大小,有效地扫过两种颜色和原点平面中的弧线中的向量。由于我们实际上并没有对不同颜色的亮度进行同等加权,或者线性观察,这并不精确,但它的扫描强度确实相当均匀,而 HSV 在中间稍微轻一点,因为它有两个值100%。

删除了死的Imageshack链接


在 Java 中,如果您有 HSB 支持,算法很简单 - 获取最终值的 HSB,像在其他 RGB 答案中一样对它们进行线性插值,然后使用 h、s、v 值转换创建颜色:

static Color hsvInterpolate ( float mix, Color c0, Color c1 ) {
    float[] hsv0 = new float[3];
    float[] hsv1 = new float[3];

    float alt = 1.0f - mix;

    Color.RGBtoHSB( c0.getRed(), c0.getGreen(), c0.getBlue(), hsv0 );
    Color.RGBtoHSB( c1.getRed(), c1.getGreen(), c1.getBlue(), hsv1 );

    float h = mix * hsv0 [ 0 ] +  alt * hsv1 [ 0 ];
    float s = mix * hsv0 [ 1 ] +  alt * hsv1 [ 1 ];
    float v = mix * hsv0 [ 2 ] +  alt * hsv1 [ 2 ];

    return Color.getHSBColor ( h, s, v );
}

我不相信 C# 具有内置的转换功能,因此代码实际上并没有多大用处。

static Color vectorInterpolate ( float mix, Color c0, Color c1 ) {
    float alt = 1.0f - mix;

    double x0 = c0.getRed();
    double y0 = c0.getGreen();
    double z0 = c0.getBlue();

    double x1 = c1.getRed();
    double y1 = c1.getGreen();
    double z1 = c1.getBlue();

    double mag0 = sqrt( x0*x0 + y0*y0 + z0*z0 );
    double mag1 = sqrt( x1*x1 + y1*y1 + z1*z1 );

    double x = mix * x0 + alt * x1;
    double y = mix * y0 + alt * y1;
    double z = mix * z0 + alt * z1;

    double mag  = mix * mag0 + alt * mag1;
    double scale = mag / sqrt( x*x + y*y + z*z );

    return new Color ( 
        clamp ( x * scale ),
        clamp ( y * scale ),
        clamp ( z * scale ) );
}

static int clamp ( double value ) {
    int x = (int) round ( value );

    if ( x > 255 ) return 255;
    if ( x < 0 ) return 0;
    return x;
}

您可能希望找到向量与 RGB 立方体边缘的交点,而不是简单地夹紧它,但在这种情况下,这两种方式都无关紧要。


作为附录,还值得考虑 HSY 空间,它更接近于感知亮度,如Dave Green 的立方体螺旋颜色插值所示。

于 2009-03-21T19:01:29.197 回答
8

只需从组件的角度考虑它。尽管它看起来像一个大的十六进制数,但它实际上是三个并排的。

开始时红色为 0,绿色为 255(FF),蓝色为 0。
最后,红色为 255,绿色为 0,蓝色为 0。

因此,每(您拥有的时间量 / 255),红色加 1,绿色减 1。

于 2009-03-20T22:45:41.037 回答
4

time_remaining(值从 0 到 239 不等)

绿色 = 255 * (time_remaining / 239)
红色 = 255 - 绿色
蓝色 = 0

颜色 =(红、绿、蓝)

于 2009-03-20T22:51:10.493 回答
0

这是一个从红色到绿色的快速java答案(你可以更改它)值是当前value时间,all是时间的总和......

public static String progressiveColor(int value, int all){

    int red = 255 - (int)((float)(value*255)/(float)all);
    int green = (int)((float)(value*255)/(float)all);
    return String.format("#%06X", (0xFFFFFF & Color.argb(255, red, green, 0)));

}
于 2013-11-08T15:53:17.530 回答
0

这是 Pete 翻译成 C# 的 Java 代码,以防万一有人在寻找它。它非常适合我的目的(黑色到深红色和背面)。

    static Color VectorInterpolate(float mix, Color c0, Color c1)
    {
        float alt = 1.0f - mix;

        double x0 = c0.R;
        double y0 = c0.G;
        double z0 = c0.B;

        double x1 = c1.R;
        double y1 = c1.G;
        double z1 = c1.B;

        double mag0 = Math.Sqrt(x0 * x0 + y0 * y0 + z0 * z0);
        double mag1 = Math.Sqrt(x1 * x1 + y1 * y1 + z1 * z1);

        double x = mix * x0 + alt * x1;
        double y = mix * y0 + alt * y1;
        double z = mix * z0 + alt * z1;

        double mag = mix * mag0 + alt * mag1;
        double scale = mag / Math.Sqrt(x * x + y * y + z * z);

        return Color.FromRgb(Clamp(x * scale), Clamp(y * scale), Clamp(z * scale));
    }

    static byte Clamp(double value)
    {
        var x = (int)Math.Round(value);

        if (x > 255) return 255;
        if (x < 0) return 0;
        return (byte) x;
    }
于 2017-03-25T06:23:12.067 回答