Алгоритм Вопрос: Нужно динамически увеличивать от 00FF00 до FF0000 за время, C # / Java - PullRequest
5 голосов
/ 21 марта 2009

Я хочу изменить цвет с ярко-зеленого на темно-красный со временем (240 часов). Лучший способ, который я вижу, - это изменить шестнадцатеричный комбо с 00FF00 на FF0000.

Я не знаю, как динамически считать до FF0000 с 00FF00 для моей жизни. Я просматриваю 10-дневный период, поэтому, скорее всего, более чем на 240 часов.

Кто-нибудь может мне помочь?

Я никогда не посещал класс алгоритмов, поэтому думаю, что это как-то связано с этой проблемой.

Если у вас есть лучший способ сделать это, дайте мне знать.

Я ищу какой-то код здесь. Спасибо, парни. Он может быть на любом языке, но неизбежно будет преобразован в C #.

Ответы [ 5 ]

29 голосов
/ 21 марта 2009

Если вы переходите от яркого цвета к яркому цвету, как подсказывают шестнадцатеричные значения, то вы можете интерполировать в HSV-пространство , а не в RGB-пространство. Пространство HSV приблизительно соответствует нашему пониманию цвета - оттенка, насыщенности и ценности. Пространство RGB приблизительно соответствует тому, как работают светочувствительные клетки в наших глазах.

Верхний градиент - линейная RGB-интерполяция от FF0000 до 00FF00. Его среднее значение 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, которое ближе к воспринимаемой яркости, как показано спиралью куба Дэйва Грина цветными интерполяциями.

8 голосов
/ 21 марта 2009

Просто подумайте об этом с точки зрения компонентов. Несмотря на то, что оно выглядит как одно большое шестнадцатеричное число, на самом деле это три рядом.

В начале красный - 0, зеленый - 255 (FF), синий - 0.
В конце красный - 255, зеленый - 0, синий - 0.

Итак, каждые (количество времени, которое у вас есть / 255), увеличивайте красный на 1 и уменьшайте зеленый на 1.

3 голосов
/ 21 марта 2009

time_remaining (значение варьируется от 0 до 239)

зеленый = 255 * (time_remaining / 239)
красный = 255 - зеленый
синий = 0

цвет = (красный, зеленый, синий)

0 голосов
/ 25 марта 2017

Вот Java-код Пита, переведенный на C # на тот случай, если кто-то ищет это. Он отлично подходит для моих целей (от черного до темно-красного и обратно).

    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;
    }
0 голосов
/ 08 ноября 2013

вот быстрый ответ 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)));

}
...