web-dev-qa-db-fra.com

Générer des couleurs entre le rouge et le vert pour un compteur de puissance?

Je suis en train d'écrire un jeu Java) et je souhaite implémenter un compteur de puissance pour mesurer la difficulté avec laquelle vous allez filmer.

J'ai besoin d'écrire une fonction qui prend un int entre 0 et 100. En fonction de la valeur de ce nombre, elle retournera une couleur entre le vert (0 sur l'échelle de puissance) et le rouge (100 sur l'échelle de puissance).

Similaire au fonctionnement des contrôles de volume:
volume control

Quelle opération dois-je effectuer sur les composants rouge, vert et bleu d’une couleur pour générer les couleurs entre le vert et le rouge?

Donc, je pourrais courir par exemple, getColor(80) et il retournera une couleur orangée (ses valeurs dans R, V, B) ou getColor(10) qui retournera une valeur RVB plus verte/jaune.

Je sais que je dois augmenter les composants des valeurs R, V, B pour une nouvelle couleur, mais je ne sais pas précisément ce qui monte ou qui baisse lorsque les couleurs passent du vert au rouge.


Le progrès:

J'ai fini par utiliser l'espace colorimétrique HSV/HSB parce que j'aimais mieux le dégradé (pas de brun foncé au milieu).

La fonction que j'ai utilisée était:

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

Où "puissance" est un nombre compris entre 0.0 et 1.0. 0.0 retournera un rouge vif, 1.0 retournera un vert vif.

Tableau de teinte Java:
Java Hue Chart

133
mmcdole

Cela devrait fonctionner - il suffit de mettre à l'échelle de manière linéaire les valeurs rouge et verte. En supposant que votre valeur maximale rouge/vert/bleu est 255 et n est dans la plage 0 .. 100

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

(modifié pour les mathématiques sur les nombres entiers, pointe du chapeau à Ferrucio)

Une autre façon de faire serait d'utiliser un modèle de couleurs HSV , et de changer la teinte de 0 degrees (rouge) à 120 degrees (vert) avec la saturation et la valeur qui vous conviennent. Cela devrait donner un gradient plus agréable.

Voici une démonstration de chaque technique - le dégradé supérieur utilise le RVB, le fond utilise le VHS:

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

199
Paul Dixon

Voici la transition de teinte vert-rouge dans l'espace HSV, traduite en RVB:

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)

Les valeurs rouge, verte et bleue dans l'exemple ci-dessus sont des pourcentages. Vous voudrez probablement les multiplier par 255 pour obtenir la plage 0-255 la plus utilisée.

32
Rafał Dowgird

Réponse Copier-Copier Court ...

On Java Std:

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

Sur Android:

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

remarque: la valeur est un nombre compris entre 0 et 1 indiquant l'état rouge à vert.

12
mschmoock

Une interpolation linéaire entre le vert et le rouge presque devrait fonctionner, sauf qu'au milieu il y aura une couleur marron boueuse.

La solution la plus flexible et la plus esthétique consiste à créer un fichier image contenant la rampe de couleur exacte souhaitée. Et puis recherchez la valeur de pixel à l'intérieur. Cela a la flexibilité que vous pouvez modifier le dégradé pour être juste bien.

Si vous voulez toujours le faire à partir de code, il est probablement préférable d'interpoler entre les couleurs verte et jaune du côté gauche et entre le jaune et le rouge du côté droit. Dans l'espace RVB, le vert est (R = 0, G = 255, B = 0), le jaune est (R = 255, G = 255, B = 0), le rouge est (R = 255, G = 0, B = 0 ) - en supposant que chaque composante de couleur passe de 0 à 255.

8
NeARAZ

Si vous voulez une représentation vert-jaune-rouge comme le suggère la réponse acceptée, jetez un coup d'œil à ceci.

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
Blowsie

J'ai créé une petite fonction qui vous donne la valeur entière de rgb pour une valeur de pourcentage:

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

Donc, si votre currentValue est 50 et votre maxValue, 100, cette fonction retournera la couleur dont vous avez besoin. Ainsi, si vous bouclez cette fonction avec une valeur en pourcentage, votre valeur de couleur passera du vert au rouge. Désolé pour la mauvaise explication

4
Nicholas

La réponse acceptée ne répondait même pas vraiment à la question ...

C++

Voici un simple segment de code C++ de mon moteur qui interpole linéairement et efficacement entre trois couleurs arbitraires:

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

Le interpolation_factor est supposé être dans la gamme de 0.0 ... 1.0.
Les couleurs sont supposées être dans la gamme de 0.0 ... 1.0 _ (par exemple pour OpenGL).

C #

Voici la même fonction écrite en 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)));
}

Le interpolationFactor est supposé être dans la plage de 0.0 ... 1.0.
Les couleurs sont supposées être dans la gamme de 0 ... 255.

3
Tara

Vous devez interpoler linéairement (LERP) les composantes de couleur. Voici comment on procède en général, avec une valeur de départ v0 , une valeur de fin v1 et le rapport requis (un flottant normalisé entre 0.0 et 1.0):

v = v0 + ratio * (v1 - v0)

Cela donne v0 lorsque le ratio est 0.0, v1 lorsque le ratio est 1.0, et tout ce qui est entre les autres cas.

Vous pouvez le faire soit sur les composants RVB, soit en utilisant un autre jeu de couleurs, tel que HSV ou HLS. Les deux derniers seront plus agréables visuellement, car ils travaillent sur des composants de teinte et de luminosité qui correspondent mieux à notre perception des couleurs.

2
efotinis

Je dirais que vous voulez quelque chose entre un segment de ligne dans l'espace HSV (qui a un jaune légèrement trop brillant au centre) et un segment de ligne dans l'espace RGB (qui a un brun laide au centre). Je voudrais utiliser ceci, où power = 0 donnera du vert, power = 50 donnera un jaune légèrement terne, et power = 100 va donner du rouge.

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

Si vous avez besoin de ce type de dégradé (en réalité inversé) en CSS (version min 2.1), vous pouvez également utiliser HSL.

Supposons que vous soyez dans un modèle AngularJs et que la valeur est un nombre compris entre 0 et 1 et que vous souhaitez styler un élément (couleur de fond ou de texte) ...

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

Première valeur: degrés (0 rouge, 120 vert) Deuxième valeur: saturation (50% est neutre) Troisième valeur: luminosité (50% neutre)

Un bel article ici

Théorie sur Wikipedia ici

1
lucabelluccini

Dans 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)

Le pourcentage est bien sûr value / max_value. Ou si votre échelle ne commence pas à 0, alors (value - min_value) / (max_value - min_value).

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
mawi

Voici la Objective-C version de la solution 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];
}

Où level serait une valeur comprise entre 0.0 et 1.0.
J'espère que ça aide quelqu'un!

1
S1LENT WARRIOR

Voici la solution de copier-coller pour Swift et l'échelle HSV:

L’initialiseur UIColor accepte la teinte, la saturation et la luminosité dans [0, 1]. Par conséquent, pour valeur de [0, 1], nous avons:

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

JavaScript

J'utilise la visualisation Google avec l'histogramme et je voulais que les barres passent du vert au rouge en fonction d'un pourcentage. Ceci s’est avéré être la solution la plus propre que j’ai trouvée et fonctionne parfaitement.

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

Assurez-vous simplement que votre pourcentage est 50 pour 50% et pas 0,50.

1
Patrick

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
0
MartiniB

J'ai mis à jour la réponse acceptée en la divisant en première et seconde moitié de la plage (0,100) et en remplaçant le nombre 100 par un niveau max, de sorte que la plage puisse devenir dynamique. Le résultat est exactement comme avec le modèle HSV, mais en utilisant toujours RVB. La clé est d'avoir le (255,255,0) au milieu pour représenter la couleur jaune. J'ai combiné cette idée dans la réponse acceptée et dans un autre code VBA; réalisez-la donc dans VBA et utilisez-la dans Excel. J'espère que la logique aide et peut être utilisée dans d'autres langages/applications.

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

Cordialement, Pavlin

0
Pavlin Todorov

Cela variera du rouge au jaune et ensuite au vert
La valeur varie de 0 à 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];
}
0
Simon Fernandes

Exemple autonome

<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
Amnon