Hasilkan warna antara merah dan hijau untuk meteran listrik?


138

Saya sedang menulis permainan Java dan saya ingin menerapkan pengukur daya seberapa keras Anda akan menembak sesuatu.

Saya perlu menulis fungsi yang mengambil int antara 0 - 100, dan berdasarkan seberapa tinggi angkanya, itu akan mengembalikan warna antara Hijau (0 pada skala daya) dan Merah (100 pada skala daya).

Mirip dengan cara kerja kontrol volume:
pengatur suara

Operasi apa yang harus saya lakukan pada komponen warna Merah, Hijau, dan Biru untuk menghasilkan warna antara Hijau dan Merah?

Jadi, saya bisa menjalankan say, getColor(80)dan itu akan mengembalikan warna jingga (nilainya di R, G, B) atau getColor(10)yang akan mengembalikan nilai RGB yang lebih Hijau / Kuning.

Saya tahu saya perlu meningkatkan komponen nilai R, G, B untuk warna baru, tetapi saya tidak tahu secara spesifik apa yang naik atau turun saat warna bergeser dari Hijau-Merah.


Kemajuan:

Saya akhirnya menggunakan ruang warna HSV / HSB karena saya lebih menyukai gradien (tidak ada cokelat gelap di tengah).

Fungsi yang saya gunakan adalah:

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

Di mana "daya" adalah angka antara 0,0 dan 1,0. 0,0 akan mengembalikan warna merah cerah, 1,0 akan mengembalikan hijau cerah.

Bagan Warna Jawa:
Bagan Warna Jawa


Saya sebelumnya telah menanyakan pertanyaan yang sama (sangat mirip) di sini: http://stackoverflow.com/questions/168838/color-scaling-function
Tomas Pajonk

2
Haruskah Anda tidak membalikkan daya? Dengan asumsi merah adalah hit tertinggi, dan Anda bekerja antara 0,1 dan 0,4, semakin tinggi kekuatan semakin rendah H
Adriaan Davel

Apakah Anda menggunakan OpenGL? Karena ada cara untuk mengatur titik-titik segitiga ke warna yang berbeda dan kemudian memadukan / gradien di antara keduanya. Anda mungkin mendapatkan kinerja yang lebih baik dengan meminta kartu grafis melakukan pekerjaan untuk Anda. Juga kodenya bisa lebih sederhana / lebih mudah beradaptasi (katakanlah jika Anda ingin meteran daya alien berubah dari hijau menjadi biru)
DarcyThomas

Jawaban:


205

Ini seharusnya berfungsi - cukup skala nilai merah dan hijau secara linier. Dengan asumsi nilai merah / hijau / biru maks Anda adalah 255, dan nberada dalam kisaran0 .. 100

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

(Diubah untuk matematika integer, ujung topi menjadi Ferrucio)

Cara lain untuk melakukannya adalah dengan menggunakan model warna HSV , dan siklus rona dari 0 degrees(merah) ke120 degrees (hijau) dengan saturasi dan nilai apa pun yang sesuai untuk Anda. Ini akan memberikan gradien yang lebih menyenangkan.

Berikut demonstrasi setiap teknik - gradien atas menggunakan RGB, bawah menggunakan HSV:

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


20
Jauh lebih baik melakukan ini di ruang HSV.
DJClayworth

@DJClayworth, ya saya pergi dengan HSV.
mmcdole

+1; Saya akan mengajukan pertanyaan baru tentang cara meningkatkan algoritme warna yang saya miliki untuk mewarnai diagram batang dalam HTML / PHP ... JADI menyarankan pertanyaan ini serupa dan jawaban Anda membantu saya memperbaiki masalah tanpa harus mengajukan pertanyaan! Terima kasih!
Beggs

Bagaimana Anda menulis fungsi yang berfungsi dengan nilai warna apa pun? Katakanlah, hitung warna antara RGB 20,30,190 dan RBG 69,190,10?
Kokodoko

1
teknik yang sama - untuk berpindah dari nilai X ke nilai Y dalam langkah N, setiap langkah Anda menambah X sebesar (YX) / N - meskipun akan terlihat lebih bagus jika Anda bergerak di ruang HSV daripada RGB
Paul Dixon

32

Di luar kepalaku, inilah transisi rona hijau-merah di ruang HSV, diterjemahkan ke 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)

Nilai merah, hijau, biru pada contoh di atas adalah persentase, Anda mungkin ingin mengalikannya dengan 255 untuk mendapatkan rentang 0-255 yang paling sering digunakan.


12

Jawaban Copy'n'Paste singkat ...

Di Java Std:

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

Di Android:

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

catatan: nilai adalah angka antara 0 dan 1 yang menunjukkan kondisi merah ke hijau.


Untuk langsung mengonversi ke kode warna hex, Anda mungkin ingin memanfaatkanString.format("#%06X", 0xFFFFFF & getTrafficlightColor(value));
ngeek

10

Jika Anda menginginkan representasi hijau-kuning-merah seperti yang disarankan jawaban yang diterima, lihat ini.

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>


Saya mendapatkan nilai yang sama untuk persentase yang berbeda menggunakan kode ini ... ada ide? Misalnya, persentase berikut semua mengembalikan RGB 1,255,0: 0,277, 0,222, 0,111 ... nilai yang lebih tinggi (misalnya 1.0) mengembalikan RGB yang benar dengan warna hijau yang lebih cerah, tetapi mereka berhenti tertinggal setelah ambang batas dan saya hanya mendapatkan nuansa hijau pada skala saya.
Patrick

8

Interpolasi linier antara hijau dan merah hampir bisa digunakan, kecuali di bagian tengah akan ada warna coklat keruh.

Solusi paling fleksibel dan terbaik adalah memiliki file gambar di suatu tempat yang memiliki warna ramp yang Anda inginkan. Dan kemudian cari nilai piksel di sana. Ini memiliki fleksibilitas sehingga Anda dapat mengubah gradien menjadi tepat .

Jika Anda masih ingin melakukannya dari kode, mungkin yang terbaik adalah menginterpolasi antara warna hijau dan kuning di sisi kiri, dan antara kuning dan merah di sisi kanan. Dalam ruang RGB, hijau adalah (R = 0, G = 255, B = 0), kuning adalah (R = 255, G = 255, B = 0), merah adalah (R = 255, G = 0, B = 0 ) - ini mengasumsikan setiap komponen warna berubah dari 0 hingga 255.


1
Saran di sini untuk membagi spektrum menjadi Merah / Kuning dan Kuning / Hijau memberikan hasil kuning yang paling menyenangkan.
ara

4

Saya membuat fungsi kecil yang memberi Anda nilai integer rgb untuk nilai persentase:

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

Jadi jika currentValue Anda 50 dan maxValue Anda 100, fungsi ini akan mengembalikan warna yang Anda butuhkan, jadi jika Anda mengulang fungsi ini dengan nilai persentase, nilai warna Anda akan berubah dari hijau menjadi merah. Maaf atas penjelasan yang buruk


3

Jawaban yang diterima bahkan tidak benar-benar menjawab pertanyaan itu ...

C ++

Berikut adalah segmen kode C ++ sederhana dari mesin saya yang secara linier dan efisien menginterpolasi antara tiga warna acak:

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

The interpolation_factordiasumsikan di kisaran 0.0 ... 1.0.
Warna diasumsikan berada dalam kisaran 0.0 ... 1.0(misalnya untuk OpenGL).

C #

Berikut fungsi yang sama yang ditulis di 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)));
}

The interpolationFactordiasumsikan di kisaran 0.0 ... 1.0.
Warna diasumsikan berada dalam kisaran 0 ... 255.


1
Kode C # bekerja sangat baik bagi saya (upvote ditambahkan) tetapi ada kesalahan ejaan di dalamnya interpolationFactorColor2 harus interpolationFactor2
DJIDave

Juga untuk kelengkapan ini adalah bagaimana saya menggunakan fungsi untuk mengembalikan RGB ke MVC razr view double n = actualValue / maxValue; // Ini memberikan rasio 0-1 var color = GetInterpolatedColor (n); return string.Concat ("#", colour.R.ToString ("X"), colour.G.ToString ("X"), colour.B.ToString ("X"));
DJIDave

@DJIDave: Wow, sungguh kesalahan yang jelas dan bodoh. Saya sudah memperbaikinya. Terima kasih!
Tara

2

Anda perlu interpolasi linier (LERP) komponen warna. Begini cara melakukannya secara umum, diberi nilai awal v0 , nilai akhir v1 dan rasio yang diperlukan (float yang dinormalisasi antara 0.0 dan 1.0):

v = v0 + ratio * (v1 - v0)

Ini memberikan v0 ketika rasio adalah 0,0, v1 ketika rasio adalah 1,0, dan segala sesuatu di antara dalam kasus lain.

Anda dapat melakukannya baik pada komponen RGB, atau menggunakan skema warna lain, seperti HSV atau HLS. Dua yang terakhir ini akan lebih menyenangkan secara visual, karena keduanya bekerja pada komposisi corak dan kecerahan yang memetakan lebih baik ke persepsi warna kita.


2

Saya akan mengatakan Anda menginginkan sesuatu di antara segmen garis di ruang HSV (yang memiliki warna kuning agak terlalu terang di tengah) dan segmen garis di ruang RGB (yang memiliki warna coklat jelek di tengah). Saya akan menggunakan ini, di mana power = 0akan memberi warna hijau, power = 50akan memberikan warna kuning yang agak kusam, dan power = 100akan memberi warna merah.

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

2

Berikut adalah solusi salin dan tempel untuk skala Swift dan HSV:

Penginisialisasi UIColor menerima hue, saturation dan brightness dalam [0, 1] jadi untuk nilai yang diberikan dari [0, 1] kita memiliki:

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

Jika Anda membutuhkan jenis gradien ini (sebenarnya terbalik) di CSS (versi min 2.1) Anda dapat menggunakan HSL juga.

Misalkan Anda berada dalam template AngularJs dan nilainya adalah angka dari 0 hingga 1 dan Anda ingin memberi gaya pada elemen (latar belakang atau warna teks) ...

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

Nilai pertama: derajat (0 merah, 120 hijau) Nilai kedua: saturasi (50% netral) Nilai ketiga: ringan (50% netral)

Artikel yang bagus di sini

Teori di Wikipedia di sini


1

Berikut adalah Objective-Cversi solusi 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];
}

Dimana level akan menjadi nilai antara 0.0dan 1.0.
Semoga ini bisa membantu seseorang!


1

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

Persen tentu saja value / max_value. Atau jika skala Anda tidak dimulai dari 0 maka (value - min_value) / (max_value - min_value).


1

JavaScript

Saya menggunakan Visualisasi Google dengan diagram batang dan ingin batang berwarna hijau menjadi merah berdasarkan persentase. Ini ternyata solusi terbersih yang saya temukan dan berfungsi dengan sempurna.

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

Pastikan saja persentase Anda adalah 50 untuk 50% dan bukan 0,50.


1

Saya telah memperbarui jawaban yang diterima dengan membaginya menjadi paruh pertama dan kedua dari kisaran (0,100) dan mengganti 100 dengan level maksimal, sehingga kisaran dapat menjadi dinamis. Hasilnya sama persis dengan model HSV, namun tetap menggunakan RGB. Kuncinya adalah memiliki (255,255,0) di tengah untuk mewakili warna kuning. Saya telah menggabungkan ide ini dalam jawaban yang diterima dan kode VBA lain, jadi capai di VBA dan gunakan di Excel. Saya harap logikanya membantu dan dapat digunakan dalam bahasa / aplikasi lain.

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

Cheers, 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

Meskipun ini mungkin berhasil, akan sangat membantu jika Anda memberikan penjelasan
David Glickman

0

Contoh mandiri

<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

Ini akan bervariasi dari Merah ke Kuning dan kemudian ke Hijau
nilai bervariasi dari 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];
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.