Generare colori tra rosso e verde per un misuratore di potenza?


137

Sto scrivendo un gioco Java e voglio implementare un misuratore di potenza per quanto duramente sparerai qualcosa.

Devo scrivere una funzione che abbia un int compreso tra 0 e 100 e in base a quanto è alto quel numero, restituirà un colore tra Verde (0 sulla scala di potenza) e Rosso (100 sulla scala di potenza).

Simile a come funzionano i controlli del volume:
controllo del volume

Quale operazione devo eseguire sui componenti rosso, verde e blu di un colore per generare i colori tra verde e rosso?

Quindi, potrei dirlo, getColor(80)e restituirà un colore arancione (i suoi valori in R, G, B) o getColor(10)che restituirà un valore RGB più verde / giallo.

So che ho bisogno di aumentare i componenti dei valori R, G, B per un nuovo colore, ma non so specificamente cosa salga o scenda mentre i colori cambiano da Verde-Rosso.


Progresso:

Ho finito per usare lo spazio colore HSV / HSB perché mi piaceva di più il gradiente (nessun marrone scuro nel mezzo).

La funzione che ho usato era:

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);
}

Dove "potere" è un numero compreso tra 0,0 e 1,0. 0.0 restituirà un rosso brillante, 1.0 restituirà un verde brillante.

Tabella tonalità Java:
Grafico tonalità Java


In precedenza ho posto la stessa (estremamente simile) domanda qui: http://stackoverflow.com/questions/168838/color-scaling-function
Tomas Pajonk

2
Non dovresti invertire il potere? Supponendo che il rosso sia il colpo più alto e si sta lavorando tra 0,1 e 0,4, maggiore è la potenza più bassa è la H
Adriaan Davel

Stai usando OpenGL? Dato che ci sono modi per impostare i punti di un triangolo su colori diversi e quindi fondere / sfumare tra loro. Probabilmente otterrai prestazioni migliori chiedendo alla scheda grafica di fare il lavoro per te. Anche il codice potrebbe essere più semplice / più adattabile (diciamo se vuoi che un misuratore di potenza alieni passi dal verde al blu)
DarcyThomas

Risposte:


203

Questo dovrebbe funzionare - basta ridimensionare linearmente i valori di rosso e verde. Supponendo che il valore massimo rosso / verde / blu sia 255ed nè nell'intervallo0 .. 100

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

(Modificato per la matematica intera, punta del cappello a Ferrucio)

Un altro modo di fare sarebbe usare un modello di colore HSV e scorrere la tonalità da 0 degrees(rosso) a 120 degrees(verde) con la saturazione e il valore adatti a te. Questo dovrebbe dare un gradiente più gradevole.

Ecco una dimostrazione di ogni tecnica: il gradiente superiore usa RGB, il fondo usa HSV:

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


20
È molto, molto meglio farlo nello spazio HSV.
DJClayworth,

@DJClayworth, sì, sono andato con HSV.
mmcdole,

+1; Stavo per fare una nuova domanda su come migliorare un algoritmo di colore che ho per colorare un grafico a barre in HTML / PHP ... SO ha suggerito questa domanda come simile e la tua risposta mi ha aiutato a risolvere il problema senza dover porre la domanda! Grazie!
supplica il

Come scriveresti una funzione che funziona con qualsiasi valore di colore? Dire, calcolare il colore tra RGB 20,30,190 e RBG 69,190,10?
Kokodoko,

1
stessa tecnica - per passare dal valore X al valore Y in N passi, ogni passo incrementa X di (YX) / N - anche se sembrerà più bello se ti sposti nello spazio HSV anziché RGB
Paul Dixon

32

Dalla parte superiore della mia testa, ecco la transizione di tonalità verde-rossa nello spazio HSV, tradotta in 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)

I valori di rosso, verde e blu nell'esempio sopra sono percentuali, probabilmente vorrai moltiplicarli per 255 per ottenere l'intervallo 0-255 più utilizzato.


12

Risposta breve Copia'n'Pasta ...

Su Java Std:

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

Su Android:

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

nota: valore è un numero compreso tra 0 e 1 che indica la condizione da rosso a verde.


Per convertire direttamente in un codice colore esadecimale, potresti voler sfruttareString.format("#%06X", 0xFFFFFF & getTrafficlightColor(value));
ngeek

10

Se vuoi una rappresentazione verde-gialla-rossa come suggerisce la risposta accettata, dai un'occhiata a questo.

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>


Ricevo valori uguali per percentuali diverse usando questo codice ... qualche idea? Ad esempio, le seguenti percentuali restituiscono tutte RGB 1.255,0: 0,277, 0,222, 0,111 ... i valori più alti (ad esempio 1.0) restituiscono gli RGB corretti con un verde più luminoso, ma smettono di scorrere dopo una soglia e ottengo solo sfumature di verde sulla mia scala.
Patrick,

8

L'interpolazione lineare tra verde e rosso dovrebbe quasi funzionare, tranne per il fatto che al centro ci sarà un colore marrone fangoso.

La soluzione più flessibile e più bella è quella di avere un file immagine da qualche parte che abbia l'esatta scala cromatica che desideri. E poi cerca il valore in pixel lì dentro. Questo ha la flessibilità che puoi modificare il gradiente per essere giusto .

Se vuoi ancora farlo dal codice, probabilmente è meglio interpolare tra i colori verde e giallo nella parte sinistra e tra giallo e rosso nella parte destra. Nello spazio RGB, il verde è (R = 0, G = 255, B = 0), il giallo è (R = 255, G = 255, B = 0), il rosso è (R = 255, G = 0, B = 0 ) - si presume che ciascun componente di colore vada da 0 a 255.


1
Il suggerimento qui di dividere lo spettro in rosso / giallo e giallo / verde dà i risultati di giallo più piacevoli.
fico

4

Ho fatto una piccola funzione che ti dà il valore intero rgb per un valore percentuale:

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);
}

Pertanto, se il valore corrente è 50 e il valore massimo è 100, questa funzione restituirà il colore necessario, quindi se si esegue il ciclo di questa funzione con un valore percentuale, il valore del colore passerà dal verde al rosso. Ci scusiamo per la cattiva spiegazione


3

La risposta accettata non ha nemmeno veramente risposto alla domanda ...

C ++

Ecco un semplice segmento di codice C ++ dal mio motore che si interpola in modo lineare ed efficiente tra tre colori arbitrari:

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);
}

Si interpolation_factorpresume che sia compreso nell'intervallo di 0.0 ... 1.0.
Si presume che i colori siano compresi nell'intervallo di 0.0 ... 1.0(ad esempio per OpenGL).

C #

Ecco la stessa funzione scritta in 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)));
}

Si interpolationFactorpresume che sia compreso nell'intervallo di 0.0 ... 1.0.
Si presume che i colori siano nella gamma di 0 ... 255.


1
Il codice C # ha funzionato alla grande per me (aggiunta del voto) ma c'è un errore di ortografia nella sua interpolazioneFactorColor2 dovrebbe essere interpolazioneFactor2
DJIDave

Anche per completezza, questo è il modo in cui ho utilizzato la funzione per restituire RGB alla vista razr MVC double n = actualValue / maxValue; // Questo dà il rapporto 0-1 var color = GetInterpolatedColor (n); return string.Concat ("#", colour.R.ToString ("X"), colour.G.ToString ("X"), colour.B.ToString ("X"));
DJIDave,

@DJIDave: Wow, che errore ovvio e stupido. L'ho risolto. Grazie!
Tara,

2

È necessario interpolare linearmente (LERP) i componenti del colore. Ecco come si fa in generale, dato un valore iniziale v0 , un valore finale v1 e il rapporto richiesto (un galleggiante normalizzato tra 0,0 e 1,0):

v = v0 + ratio * (v1 - v0)

Questo dà v0 quando il rapporto è 0,0, v1 quando il rapporto è 1,0 e tutto il resto negli altri casi.

Puoi farlo sui componenti RGB o usando qualche altra combinazione di colori, come HSV o HLS. Gli ultimi due saranno visivamente più gradevoli, dal momento che lavorano su componenti di tonalità e luminosità che mappano meglio la nostra percezione del colore.


2

Direi che vuoi qualcosa tra un segmento di linea nello spazio HSV (che ha un giallo leggermente troppo luminoso al centro) e un segmento di linea nello spazio RGB (che ha un brutto marrone al centro). Userei questo, dove power = 0darà il verde, power = 50daremo un giallo leggermente opaco, e power = 100daremo il rosso.

blue = 0;
green = 255 * sqrt( cos ( power * PI / 200 ));
red = 255 * sqrt( sin ( power * PI / 200 )); 

2

Ecco la soluzione copia e incolla per la scala Swift e HSV:

L'inizializzatore UIColor accetta tonalità, saturazione e luminosità in [0, 1], quindi per un dato valore da [0, 1] abbiamo:

let hue:        CGFloat = value / 3
let saturation: CGFloat = 1 // Or choose any
let brightness: CGFloat = 1 // Or choose any
let alpha:      CGFloat = 1 // Or choose any

let color = UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha)

1
import java.awt.Color;

public class ColorUtils {

    public static Color interpolate(Color start, Color end, float p) {
        float[] startHSB = Color.RGBtoHSB(start.getRed(), start.getGreen(), start.getBlue(), null);
        float[] endHSB = Color.RGBtoHSB(end.getRed(), end.getGreen(), end.getBlue(), null);

        float brightness = (startHSB[2] + endHSB[2]) / 2;
        float saturation = (startHSB[1] + endHSB[1]) / 2;

        float hueMax = 0;
        float hueMin = 0;
        if (startHSB[0] > endHSB[0]) {
            hueMax = startHSB[0];
            hueMin = endHSB[0];
        } else {
            hueMin = startHSB[0];
            hueMax = endHSB[0];
        }

        float hue = ((hueMax - hueMin) * p) + hueMin;

        return Color.getHSBColor(hue, saturation, brightness);
    }
}

1

Se hai bisogno di questo tipo di gradiente (in realtà invertito) nei CSS (versione minima 2.1) puoi usare anche HSL.

Supponendo di essere in un modello AngularJs e che il valore sia un numero compreso tra 0 e 1 e che si desidera modellare un elemento (sfondo o colore del testo) ...

hsl({{ value * 120}}, 50%, 35%)

Primo valore: gradi (0 rosso, 120 verde) Secondo valore: saturazione (50% è neutro) Terzo valore: leggerezza (50% neutro)

Un bell'articolo qui

Teoria su Wikipedia qui


1

Ecco la Objective-Cversione della soluzione di Simucal:

- (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];
}

Dove livello sarebbe un valore tra 0.0e 1.0.
Spero che questo aiuti qualcuno!


1

In Python 2.7:

import colorsys

def get_rgb_from_hue_spectrum(percent, start_hue, end_hue):
    # spectrum is red (0.0), orange, yellow, green, blue, indigo, violet (0.9)
    hue = percent * (end_hue - start_hue) + start_hue
    lightness = 0.5
    saturation = 1
    r, g, b = colorsys.hls_to_rgb(hue, lightness, saturation)
    return r * 255, g * 255, b * 255

# from green to red:
get_rgb_from_hue_spectrum(percent, 0.3, 0.0)

# or red to green:
get_rgb_from_hue_spectrum(percent, 0.0, 0.3)

La percentuale è ovviamente value / max_value. O se la tua bilancia non inizia da 0 allora (value - min_value) / (max_value - min_value).


1

JavaScript

Sto usando la visualizzazione di Google con un grafico a barre e volevo che le barre fossero da verde a rosso in base a una percentuale. Questa si è rivelata la soluzione più pulita che ho trovato e funziona perfettamente.

function getGreenToRed(percent){
    r = percent<50 ? 255 : Math.floor(255-(percent*2-100)*255/100);
    g = percent>50 ? 255 : Math.floor((percent*2)*255/100);
    return 'rgb('+r+','+g+',0)';
}

Assicurati solo che la tua percentuale sia 50 per il 50% e non 0,50.


1

Ho aggiornato la risposta accettata suddividendola nella prima e nella seconda metà dell'intervallo (0,100) e sostituendo 100 per un livello massimo, in modo che l'intervallo possa diventare dinamico. Il risultato è esattamente come nel modello HSV, ma continua a usare RGB. La chiave è avere il (255.255,0) al centro per rappresentare il colore giallo. Ho combinato questa idea nella risposta accettata e in un altro codice VBA, quindi realizzala in VBA e usala in Excel. Spero che la logica aiuti e possa essere utilizzata in altre lingue / applicazioni.

Sub UpdateConditionalFormatting(rng As Range)
    Dim cell As Range
    Dim max As Integer

    max = WorksheetFunction.max(rng)

    For Each cell In rng.Cells

    If cell.Value >= 0 And cell.Value < max / 2 Then
        cell.Interior.Color = RGB(255 * cell.Value / (max / 2), 255, 0)
    ElseIf cell.Value >= max / 2 And cell.Value <= max Then
        cell.Interior.Color = RGB(255, 255 * ((max) - cell.Value) / (max / 2), 0)
    End If

    Next cell
End Sub

Saluti, Pavlin


1

VB

Public Function GetPercentageColor( _
  ByVal iPercent As Long, Optional _
  ByVal bOpposit As Boolean) As Long
' 0->100% - Green->Yellow->Red
' bOpposit - Red->Yellow->Green

If bOpposit Then iPercent = (100 - iPercent)

Select Case iPercent
Case Is < 1: GetPercentageColor = 65280 ' RGB(0, 255, 0)
Case Is > 99: GetPercentageColor = 255  ' RGB(255, 0, 0)
Case Is < 50: GetPercentageColor = RGB(255 * iPercent / 50, 255, 0)
Case Else: GetPercentageColor = RGB(255, (255 * (100 - iPercent)) / 50, 0)
End Select

End Function

Anche se questo potrebbe funzionare, sarebbe utile fornire qualche spiegazione
David Glickman,

0

Esempio autonomo

<html>
<head>
<script>
//--------------------------------------------------------------------------
function gradient(left, mid, right)
{
    var obj = {}

    var lt50 = {"r":(mid.r-left.r)/50.0,
                "g":(mid.g-left.g)/50.0,
                "b":(mid.b-left.b)/50.0}
    var gt50 = {"r":(right.r-mid.r)/50.0,
                "g":(right.g-mid.g)/50.0,
                "b":(right.b-mid.b)/50.0}

    obj.getColor = function(percent) {
        if (percent == 50.0) {
            return mid;
        }
        if (percent < 50.0) {
            return "rgb("+Math.floor(left.r+lt50.r*percent+0.5)+","+
                          Math.floor(left.g+lt50.g*percent+0.5)+","+
                          Math.floor(left.b+lt50.b*percent+0.5)+")";
        }
        var p2 = percent-50.0;
        return "rgb("+Math.floor(mid.r+gt50.r*p2+0.5)+","+
                      Math.floor(mid.g+gt50.g*p2+0.5)+","+
                      Math.floor(mid.b+gt50.b*p2+0.5)+")";
    }

    return obj;
}

//--------------------------------------------------------------------------
var g_gradient = gradient( {"r":255, "g":20, "b":20},  // Left is red
                           {"r":255, "g":255, "b":20}, // Middle is yellow
                           {"r":20, "g":255, "b":20} ); // right is green

//--------------------------------------------------------------------------
function updateColor()
{
    var percent = document.getElementById('idtext').value.length;
    var oscore = document.getElementById('idscore');

    if (percent > 100.0) {
        percent = 100.0;
    }
    if (percent < 0.0) {
        percent = 0.0;
    }
    var col = g_gradient.getColor(percent)
    oscore.style['background-color'] = col;
    oscore.innerHTML = percent + '%';
}

</script>
</head>
<body onLoad="updateColor()">
<input size='100' placeholder='type text here' id='idtext' type="text" oninput="updateColor()" />
<br />
<br />
<div id='idscore' style='text-align:center; width:200px; border-style:solid;
     border-color:black; border-width:1px; height:20px;'> </div>
</body>
</html>

0

Questo varia da rosso a giallo e quindi a verde
varia da 0 a 100

-(UIColor*) redToGreenColorWithPosition:(int) value {

    double R, G;
    if (value > 50) {
        R = (255 * (100 - value)/ 50) ;
        G = 255;
    }else {
        R = 255;
        G = (255 * (value*2)) / 100;
    }

    return [UIColor colorWithRed:R/255.0f green:G/255.0f blue:0.0f alpha:1.0f];
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.