Güç ölçer için kırmızı ve yeşil arasında renk üretilsin mi?


137

Bir Java oyunu yazıyorum ve bir şey çekmenin ne kadar zor olacağına dair bir güç ölçer uygulamak istiyorum.

0 - 100 arasında bir int alan bir işlev yazmam gerekir ve bu sayının ne kadar yüksek olduğuna bağlı olarak, Yeşil (güç ölçeğinde 0) ve Kırmızı (güç ölçeğinde 100) arasında bir renk döndürür.

Ses düzeyi denetimlerinin çalışma şekline benzer:
ses kontrol

Yeşil ve Kırmızı arasındaki renkleri oluşturmak için bir rengin Kırmızı, Yeşil ve Mavi bileşenleri üzerinde ne yapmam gerekir?

Yani, söyleyebilirim getColor(80)ve orangri bir renk (R, G, B'deki değerleri) veya getColor(10)daha fazla Yeşil / Sarı RGB değeri döndürür.

Yeni bir renk için R, G, B değerlerinin bileşenlerini artırmam gerektiğini biliyorum, ancak renkler Yeşil-Kırmızı'dan değiştikçe neyin yukarı veya aşağı gittiğini bilmiyorum.


İlerleme:

HSV / HSB renk alanını kullandım, çünkü gradyanı daha iyi sevdim (ortada koyu kahverengim yok).

Kullandığım işlev:

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

Burada "güç", 0.0 ile 1.0 arasında bir sayıdır. 0.0 parlak kırmızı, 1.0 parlak yeşil döndürür.

Java Ton Tablosu:
Java Ton Tablosu


Daha önce burada aynı (son derece benzer) bir soru sordum: http://stackoverflow.com/questions/168838/color-scaling-function
Tomas Pajonk

2
Gücü ters çevirmemelisiniz? Kırmızı en yüksek vuruş olduğunu varsayarsak ve 0,1 ile 0,4 arasında çalışıyorsanız, güç ne kadar yüksek olursa H
Adriaan Davel

OpenGL kullanıyor musunuz? Üçgenin noktalarını farklı renklere ayarlamanın ve aralarında harmanlamayı / eğimi ayarlamanın yolları olduğu için. Muhtemelen grafik kartından işi sizin için yapmasını isteyen daha iyi bir performans elde edersiniz. Ayrıca kod daha basit / daha uyarlanabilir olabilir (uzaylı bir güç ölçerin yeşilden maviye gitmesini istiyorsanız)
DarcyThomas

Yanıtlar:


203

Bu işe yarar - sadece kırmızı ve yeşil değerleri doğrusal olarak ölçeklendirin. Varsayarsak, maks kırmızı / yeşil / mavi değeridir 255ve naralığındadır0 .. 100

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

(Tamsayı matematik için değiştirildi, şapkanın ucu Ferrucio'ya)

Yapmanın başka bir yolu, bir HSV renk modeli kullanmak ve tonu 0 degrees(kırmızı) ila 120 degrees(yeşil) arasında doygunluk ve değer ne olursa olsun çevirmek olacaktır. Bu daha hoş bir gradyan vermelidir.

İşte her tekniğin bir gösterimi - üst gradyan RGB kullanır, alt HSV kullanır:

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


20
HSV alanında bunu yapmak çok, çok daha iyi.
DJClayworth

@ DJClayworth, evet HSV ile gittim.
mmcdole

+ 1; Ben HTML / PHP bir çubuk grafik boyama için sahip bir renk algoritması geliştirmek hakkında yeni bir soru soracaktı ... SO bu soruyu benzer olarak önerdi ve cevabınız soruyu sormak zorunda kalmadan sorunu düzeltmek yardımcı oldu! Teşekkürler!
Temmuz'ta beggs

Herhangi bir renk değeriyle çalışan bir işlevi nasıl yazarsınız? Söyle, RGB 20,30,190 ve RBG 69,190,10 arasındaki rengi hesapla?
Kokodoko

1
aynı teknik - N adımında X değerini Y değerine taşımak için, X'i (YX) / N'ye kadar artırdığınız her adım - RGB yerine HSV alanında hareket ederseniz daha güzel görünecektir
Paul Dixon

32

Başımın üstünde, HSV uzayında RGB'ye çevrilmiş yeşil-kırmızı renk tonu geçişi:

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)

Yukarıdaki örnekteki kırmızı, yeşil, mavi değerler yüzdelerdir, en çok kullanılan 0-255 aralığını elde etmek için büyük olasılıkla bunları 255 ile çarpmak istersiniz.


12

Kısa Copy'n'Paste yanıtı ...

Java Std'de:

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

Android'de:

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

not: değer, 0'dan 1'e kadar, kırmızıdan yeşile durumunu gösteren bir sayıdır.


Doğrudan onaltılık renk koduna dönüştürmek için kaldıraç kullanabilirsinizString.format("#%06X", 0xFFFFFF & getTrafficlightColor(value));
ngeek

10

Kabul edilen cevap önerileri gibi yeşil-sarı-kırmızı bir temsil istiyorsanız o zaman buna bir göz atın.

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>


Bu kodu kullanarak farklı yüzdeler için eşit değerler alıyorum ... herhangi bir fikir? Örneğin, aşağıdaki yüzdelerin tümü RGB 1,255,0 döndürür: 0,277, 0,222, 0,11 ... ... daha yüksek değerler (örneğin 1,0) daha parlak yeşil olan doğru RGB'leri döndürür, ancak bir eşikten sonra izlemeyi bırakırlar ve sadece benim ölçeğimde yeşil tonları.
Patrick

8

Yeşil ve kırmızı arasında doğrusal olarak enterpolasyon neredeyse işe yaramalıdır , ancak ortada çamurlu kahverengi renk olacaktır.

En esnek ve en iyi görünümlü çözüm, tam olarak istediğiniz renk rampasına sahip bir görüntü dosyasına sahip olmaktır. Ve sonra piksel değerini orada arayın. Bu olmak gradyan çimdik o esnekliğe sahiptir sadece sağ .

Hala koddan yapmak istiyorsanız, muhtemelen sol taraftaki yeşil ve sarı renkler arasında ve sağ taraftaki sarı ve kırmızı arasında enterpolasyon yapmak en iyisidir. RGB alanında yeşil (R = 0, G = 255, B = 0), sarı (R = 255, G = 255, B = 0), kırmızı (R = 255, G = 0, B = 0 ) - Bu, her renk bileşeninin 0 ila 255 arasında olduğunu varsayar.


1
Burada spektrumu Kırmızı / Sarı ve Sarı / Yeşil'e bölme önerisi en hoş sarı sonuçları verir.
incir

4

Yüzde değeri için rgb tamsayı değeri veren küçük bir işlev yaptım:

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 değeriniz 50 ve maxValue değeriniz 100 ise, bu işlev ihtiyacınız olan rengi döndürür, bu nedenle bu işlevi bir yüzde değeriyle döngü yaparsanız, renk değeriniz yeşilden kırmızıya döner. Kötü açıklama için özür dilerim


3

Kabul edilen cevap soruya gerçekten cevap vermedi ...

C ++

İşte üç keyfi renk arasında doğrusal ve verimli bir şekilde enterpolasyon yapan basit bir C ++ kod segmenti:

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_factorAralığında olduğu varsayılır 0.0 ... 1.0.
Renklerin 0.0 ... 1.0(ör. OpenGL için) aralığında olduğu varsayılır .

C #

Aynı işlevi C # ile yazılmış:

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

interpolationFactorAralığında olduğu varsayılır 0.0 ... 1.0.
Renklerin aralığı olarak kabul edilir 0 ... 255.


1
C # kodu benim için parlak çalıştı (upvote eklendi) ama içinde bir yazım hatası var interpolationFactorColor2 interpolation olmalıdır
Factor2

Ayrıca tamlık için RGB MVC razr görünüm çift n = actualValue / maxValue; // Bu işlevi 0-1 var color = GetInterpolatedColor (n); dönüş dizesi. Concat ("#", renk.R.ToString ("X"), renk.G.ToString ("X"), renk.B.ToString ("X"));
DJIDave

@DJIDave: Vay be, ne kadar açık ve aptalca bir hata. Ben düzelttim. Teşekkürler!
Tara

2

Renk bileşenlerini doğrusal olarak enterpolasyon (LERP) yapmanız gerekir . Başlangıç ​​değeri v0 , bitiş değeri v1 ve gerekli oran (0.0 ve 1.0 arasında normalleştirilmiş bir kayan nokta) göz önüne alındığında genel olarak nasıl yapılır :

v = v0 + ratio * (v1 - v0)

Bu oran 0.0 olduğunda v0, oran 1.0 olduğunda v1 ve diğer durumlarda arasındaki her şeyi verir.

Bunu RGB bileşenlerinde veya HSV veya HLS gibi başka bir renk şeması kullanarak yapabilirsiniz. Son ikisi renk algımızla daha iyi eşleşen ton ve parlaklık kompozisyonları üzerinde çalıştıkları için görsel olarak daha hoş olacaktır.


2

HSV alanındaki bir çizgi segmenti (ortada biraz çok parlak sarı olan) ve RGB alanındaki bir çizgi segmenti (ortada çirkin bir kahverengi olan) arasında bir şey istediğinizi söyleyebilirim. Bunu power = 0yeşil power = 50verecek, biraz donuk sarı power = 100verecek ve kırmızı verecek.

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

2

Swift ve HSV ölçeği için kopyala ve yapıştır çözümü:

UIColor başlatıcısı [0, 1] 'de ton, doygunluk ve parlaklık kabul eder, bu nedenle [0, 1]' den verilen değer için:

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

CSS'de (min 2.1 sürümü) bu tür bir eğime (aslında tersine) ihtiyacınız varsa HSL'yi de kullanabilirsiniz.

Bir AngularJs şablonunda olduğunuzu ve değerin 0 ile 1 arasında bir sayı olduğunu ve bir öğeye (arka plan veya metin rengi) stil vermek istediğinizi varsayalım ...

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

Birinci değer: derece (0 kırmızı, 120 yeşil) İkinci değer: doygunluk (% 50 nötr) Üçüncü değer: hafiflik (% 50 nötr)

Güzel bir makale burada

Wikipedia'da teori burada


1

İşte Objective-CSimucal çözümünü uygun versiyonu:

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

Seviye 0.0ve ile arasında bir değer olur 1.0.
Umarım bu birine yardımcı olur!


1

Python 2.7'de:

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)

Yüzde elbette value / max_value. Veya ölçeğiniz 0'dan başlamazsa (value - min_value) / (max_value - min_value).


1

JavaScript

Google Visualization'ı çubuk grafikle kullanıyorum ve yüzde olarak çubukların yeşilden kırmızıya olmasını istedim. Bu bulduğum en temiz çözüm olduğu ortaya çıktı ve mükemmel çalışıyor.

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

Yüzde değerin % 50 için 50 olduğundan ve 0,50 değil .


1

Kabul edilen cevabı, (0,100) aralığının ilk ve ikinci yarısına bölerek ve 100'ü maksimum seviyeyle değiştirerek güncelledim, böylece aralık dinamik hale gelebilir. Sonuç, HSV modelinde olduğu gibi, ancak yine de RGB kullanıyor. Anahtar, sarı rengi temsil etmek için ortada (255,255,0) bulunmasıdır. Bu fikri kabul edilen cevapta ve başka bir VBA kodunda birleştirdim, bu yüzden VBA'da başarın ve Excel'de kullanın. Umarım mantık yardımcı olur ve diğer dillerde / uygulamalarda kullanılabilir.

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

Şerefe, 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

Bu işe yarayabilir olsa da, bazı açıklamalar sağlamanız yararlı olacaktır
David Glickman

0

Bağımsız örnek

<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

Bu Kırmızıdan Sarıya ve ardından Yeşil
değeri 0 - 100 arasında değişir

-(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];
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.