Генерировать цвета между красным и зеленым для измерителя мощности? - PullRequest
133 голосов
/ 04 декабря 2008

Я пишу Java-игру и хочу реализовать измеритель мощности, показывающий, как сильно вы собираетесь что-то снимать.

Мне нужно написать функцию, которая принимает целое число от 0 до 100 и, основываясь на том, как высоко это число, возвращает цвет между зеленым (0 на шкале мощности) и красным (100 на шкале мощности) .

Аналогично тому, как работают регуляторы громкости:
volume control

Какую операцию нужно выполнить для красного, зеленого и синего компонентов цвета, чтобы создать цвета между зеленым и красным?

Итак, я мог бы выполнить, скажем, getColor(80), и он вернет оранжевый цвет (его значения в R, G, B) или getColor(10), который вернет более зеленый / желтый RGB-значение.

Я знаю, что мне нужно увеличить компоненты значений R, G, B для нового цвета, но я не знаю точно, что повышается или понижается по мере того, как цвета переходят от зелено-красного.


Прогресс:

В итоге я использовал цветовое пространство HSV / HSB, потому что мне больше понравился градиент (в центре нет темных коричневых оттенков).

Я использовал следующую функцию:

public Color getColor(double power)
{
    double H = power * 0.4; // Hue (note 0.4 = Green, see huge chart below)
    double S = 0.9; // Saturation
    double B = 0.9; // Brightness

    return Color.getHSBColor((float)H, (float)S, (float)B);
}

Где «power» - это число от 0,0 до 1,0. 0.0 вернет ярко-красный, 1.0 вернет ярко-зеленый.

Диаграмма оттенка Java:
Java Hue Chart

Ответы [ 19 ]

199 голосов
/ 04 декабря 2008

Это должно работать - просто линейно масштабируйте красные и зеленые значения. Предполагая, что ваше максимальное красное / зеленое / синее значение равно 255, а n находится в диапазоне 0 .. 100

R = (255 * n) / 100
G = (255 * (100 - n)) / 100 
B = 0

(исправлено для целочисленной математики, наконечник шляпы для Ферруччо)

Еще один способ сделать это - использовать цветовую модель HSV и переключать оттенок от 0 degrees (красный) до 120 degrees (зеленый) с любым значением насыщенности и значения, которое вам подходит. Это должно дать более приятный градиент.

Вот демонстрация каждого метода - верхний градиент использует RGB, нижний использует HSV:

http://i38.tinypic.com/29o0q4k.jpg

32 голосов
/ 04 декабря 2008

Вверху моей головы, вот переход зелено-красного оттенка в пространстве HSV, переведенный в RGB:

blue = 0.0
if 0<=power<0.5:        #first, green stays at 100%, red raises to 100%
    green = 1.0
    red = 2 * power
if 0.5<=power<=1:       #then red stays at 100%, green decays
    red = 1.0
    green = 1.0 - 2 * (power-0.5)

Значения красного, зеленого и синего в приведенном выше примере представляют собой проценты, возможно, вы захотите умножить их на 255, чтобы получить наиболее часто используемый диапазон 0-255.

12 голосов
/ 06 ноября 2012

Short Copy'n'Paste ответ ...

На Java Std:

int getTrafficlightColor(double value){
    return java.awt.Color.HSBtoRGB((float)value/3f, 1f, 1f);
}

На Android:

int getTrafficlightColor(double value){
    return android.graphics.Color.HSVToColor(new float[]{(float)value*120f,1f,1f});
}

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

8 голосов
/ 29 января 2015

Если вам нужно зелено-желто-красное представление, как предлагает принятый ответ, взгляните на это.

http://jsfiddle.net/0awncw5u/2/

function percentToRGB(percent) {
    if (percent === 100) {
        percent = 99
    }
    var r, g, b;

    if (percent < 50) {
        // green to yellow
        r = Math.floor(255 * (percent / 50));
        g = 255;

    } else {
        // yellow to red
        r = 255;
        g = Math.floor(255 * ((50 - percent % 50) / 50));
    }
    b = 0;

    return "rgb(" + r + "," + g + "," + b + ")";
}


function render(i) {
    var item = "<li style='background-color:" + percentToRGB(i) + "'>" + i + "</li>";
    $("ul").append(item);
}

function repeat(fn, times) {
    for (var i = 0; i < times; i++) fn(i);
}


repeat(render, 100);
li {
    font-size:8px;
    height:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<ul></ul>
8 голосов
/ 04 декабря 2008

Линейная интерполяция между зеленым и красным почти должна работать, за исключением того, что посередине будет мутный коричневый цвет.

Самое гибкое и наиболее привлекательное решение - иметь где-нибудь файл изображения с нужной вам цветовой шкалой. А затем посмотрите значение пикселя там. Это дает гибкость, позволяющую настроить градиент на * * * * * * Right .

Если вы все еще хотите сделать это из кода, то, вероятно, лучше всего интерполировать между зеленым и желтым цветами с левой стороны и между желтым и красным с правой стороны. В пространстве RGB зеленый - это (R = 0, G = 255, B = 0), желтый - (R = 255, G = 255, B = 0), красный - (R = 255, G = 0, B = 0 ) - это предполагает, что каждый компонент цвета идет от 0 до 255.

4 голосов
/ 05 ноября 2013

Я сделал небольшую функцию, которая дает вам целочисленное значение rgb для процентного значения:

private int getGreenToRedGradientByValue(int currentValue, int maxValue)
{
    int r = ( (255 * currentValue) / maxValue );
    int g = ( 255 * (maxValue-currentValue) ) / maxValue;
    int b = 0;
    return ((r&0x0ff)<<16)|((g&0x0ff)<<8)|(b&0x0ff);
}

Таким образом, если ваше currentValue равно 50, а maxValue равно 100, эта функция вернет нужный вам цвет, поэтому если вы зациклите эту функцию процентным значением, значение вашего цвета изменится с зеленого на красный. Извините за плохое объяснение

3 голосов
/ 14 мая 2015

Принятый ответ даже не ответил на вопрос ...

C ++

Вот простой фрагмент кода C ++ из моего движка, который линейно и эффективно интерполирует три произвольных цвета:

const MATH::FLOAT4 color1(0.0f, 1.0f, 0.0f, 1.0f);  // Green
const MATH::FLOAT4 color2(1.0f, 1.0f, 0.0f, 1.0f);  // Yellow
const MATH::FLOAT4 color3(1.0f, 0.0f, 0.0f, 1.0f);  // Red

MATH::FLOAT4 get_interpolated_color(float interpolation_factor)
{
    const float factor_color1 = std::max(interpolation_factor - 0.5f, 0.0f);
    const float factor_color2 = 0.5f - fabs(0.5f - interpolation_factor);
    const float factor_color3 = std::max(0.5f - interpolation_factor, 0.0f);

    MATH::FLOAT4 color;

    color.x = (color1.x * factor_color1 +
               color2.x * factor_color2 +
               color3.x * factor_color3) * 2.0f;

    color.y = (color1.y * factor_color1 +
               color2.y * factor_color2 +
               color3.y * factor_color3) * 2.0f;

    color.z = (color1.z * factor_color1 +
               color2.z * factor_color2 +
               color3.z * factor_color3) * 2.0f;

    color.w = 1.0f;

    return(color);
}

Предполагается, что interpolation_factor находится в диапазоне 0.0 ... 1.0.
Предполагается, что цвета находятся в диапазоне 0.0 ... 1.0 (например, для OpenGL).

C #

Вот та же функция, написанная на C #:

private readonly Color mColor1 = Color.FromArgb(255, 0, 255, 0);
private readonly Color mColor2 = Color.FromArgb(255, 255, 255, 0);
private readonly Color mColor3 = Color.FromArgb(255, 255, 0, 0);

private Color GetInterpolatedColor(double interpolationFactor)
{
    double interpolationFactor1 = Math.Max(interpolationFactor - 0.5, 0.0);
    double interpolationFactor2 = 0.5 - Math.Abs(0.5 - interpolationFactor);
    double interpolationFactor3 = Math.Max(0.5 - interpolationFactor, 0.0);

    return (Color.FromArgb(255,
                (byte)((mColor1.R * interpolationFactor1 +
                        mColor2.R * interpolationFactor2 +
                        mColor3.R * interpolationFactor3) * 2.0),

                (byte)((mColor1.G * interpolationFactor1 +
                        mColor2.G * interpolationFactor2 +
                        mColor3.G * interpolationFactor3) * 2.0),

                (byte)((mColor1.B * interpolationFactor1 +
                        mColor2.B * interpolationFactor2 +
                        mColor3.B * interpolationFactor3) * 2.0)));
}

Предполагается, что interpolationFactor находится в диапазоне 0.0 ... 1.0.
Предполагается, что цвета находятся в диапазоне 0 ... 255.

2 голосов
/ 26 мая 2014

Я бы сказал, что вы хотите что-то среднее между сегментом линии в пространстве HSV (у которого слегка слишком яркий желтый цвет в центре) и сегментом линии в пространстве RGB (с уродливым коричневым цветом в центре ). Я бы использовал это, где power = 0 даст зеленый, power = 50 даст слегка тусклый желтый, а power = 100 даст красный.

blue = 0;
green = 255 * sqrt( cos ( power * PI / 200 ));
red = 255 * sqrt( sin ( power * PI / 200 )); 
2 голосов
/ 04 декабря 2008

Вам необходимо линейно интерполировать (LERP) цветовые компоненты. Вот как это обычно делается, учитывая начальное значение v0 , конечное значение v1 и требуемое коэффициент (нормализованное значение с плавающей запятой между 0,0 и 1,0):

v = v0 + ratio * (v1 - v0)

Это дает v0, когда коэффициент равен 0.0, v1, когда коэффициент равен 1.0, и все остальное в других случаях.

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

1 голос
/ 31 августа 2015

Вот версия Objective-C решения Симукала:

- (UIColor*) colorForCurrentLevel:(float)level
{
    double hue = level * 0.4; // Hue (note 0.4 = Green)
    double saturation = 0.9; // Saturation
    double brightness = 0.9; // Brightness

    return [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1.0];
}

Где уровень будет значением от 0.0 до 1.0.
Надеюсь, это кому-нибудь поможет!

...