Tạo màu giữa đỏ và xanh cho đồng hồ đo điện?


137

Tôi đang viết một trò chơi Java và tôi muốn triển khai một máy đo sức mạnh cho việc bạn sẽ bắn một thứ gì đó khó đến mức nào.

Tôi cần phải viết một hàm lấy int từ 0 - 100, và dựa trên số đó là bao nhiêu, nó sẽ trả về màu giữa Xanh lục (0 trên thang đo công suất) và Đỏ (100 trên thang đo công suất).

Tương tự như cách điều khiển âm lượng hoạt động:
kiểm soát âm lượng

Tôi cần thực hiện thao tác nào trên các thành phần Đỏ, Xanh lục và Xanh lam của một màu để tạo ra các màu giữa Xanh lục và Đỏ?

Vì vậy, tôi có thể chạy nói getColor(80)và nó sẽ trả về màu cam (giá trị của nó trong R, G, B) hoặc getColor(10)sẽ trả về giá trị RGB xanh / vàng nhiều hơn.

Tôi biết tôi cần tăng các thành phần của các giá trị R, G, B cho một màu mới, nhưng tôi không biết cụ thể những gì tăng hoặc giảm khi màu chuyển từ Xanh-Đỏ.


Phát triển:

Tôi đã kết thúc bằng cách sử dụng không gian màu HSV / HSB vì tôi thích màu tăng dần tốt hơn (không có màu nâu sẫm ở giữa).

Hàm tôi đã sử dụng là:

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

Trong đó "sức mạnh" là một số trong khoảng từ 0,0 đến 1,0. 0,0 sẽ trả về màu đỏ tươi, 1,0 sẽ trả lại màu xanh sáng.

Biểu đồ Java Huế:
Biểu đồ Java Huế


Trước đây tôi đã hỏi câu hỏi tương tự (cực kỳ giống nhau) ở đây: http://stackoverflow.com/questions/168838/color-scaling-feft
Tomas Pajonk

2
Bạn có nên đảo ngược sức mạnh? Giả sử màu đỏ là điểm nhấn cao nhất và bạn đang làm việc trong khoảng từ 0,1 đến 0,4, sức mạnh càng cao thì H
Adriaan Davel

Bạn đang sử dụng OpenGL? Vì có nhiều cách để thiết lập các điểm của một hình tam giác thành các màu khác nhau và sau đó trộn / gradient giữa chúng. Bạn có thể có hiệu suất tốt hơn yêu cầu card đồ họa thực hiện công việc cho bạn. Ngoài ra mã có thể đơn giản hơn / dễ thích nghi hơn (giả sử nếu bạn muốn đồng hồ đo năng lượng của người ngoài hành tinh chuyển từ màu xanh sang màu xanh)
DarcyThomas

Câu trả lời:


203

Điều này sẽ hoạt động - chỉ quy mô tuyến tính các giá trị màu đỏ và màu xanh lá cây. Giả sử giá trị đỏ / xanh / xanh tối đa của bạn là 255nnằm trong phạm vi0 .. 100

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

(Sửa đổi cho toán học số nguyên, chóp mũ cho Ferrucio)

Một cách khác để làm là sử dụng mô hình màu HSV và chuyển màu từ 0 degrees(đỏ) sang 120 degrees(xanh) với bất kỳ độ bão hòa và giá trị nào phù hợp với bạn. Điều này sẽ cung cấp một gradient dễ chịu hơn.

Đây là một minh chứng cho từng kỹ thuật - độ dốc trên cùng sử dụng RGB, phía dưới sử dụng HSV:

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


20
Làm điều này tốt hơn nhiều, tốt hơn nhiều trong không gian HSV.
DJClayworth

@DJClayworth, phải, tôi đã đi với HSV.
mmcdole

+1; Tôi sẽ hỏi một câu hỏi mới về cách cải thiện thuật toán màu tôi có để tô màu biểu đồ thanh trong HTML / PHP ... SO đã gợi ý câu hỏi này tương tự và câu trả lời của bạn đã giúp tôi khắc phục vấn đề mà không phải đặt câu hỏi! Cảm ơn!
beggs

Làm thế nào bạn sẽ viết một chức năng làm việc với bất kỳ giá trị màu sắc? Nói, tính màu giữa RGB 20,30,190 và RBG 69,190,10?
Kokodoko

1
cùng một kỹ thuật - để chuyển từ giá trị X sang giá trị Y theo N bước, mỗi bước bạn tăng X theo (YX) / N - mặc dù nó sẽ đẹp hơn nếu bạn di chuyển trong không gian HSV thay vì RGB
Paul Dixon

32

Ngoài đỉnh đầu của tôi, đây là sự chuyển đổi màu xanh lục đỏ trong không gian HSV, được dịch sang 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)

Các giá trị đỏ, lục, lam trong ví dụ trên là tỷ lệ phần trăm, có lẽ bạn muốn nhân chúng với 255 để có phạm vi 0-255 được sử dụng nhiều nhất.


12

Bản sao ngắn''Paste trả lời ...

Trên Java Std:

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

Trên Android:

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

lưu ý: giá trị là một số từ 0 đến 1 biểu thị điều kiện đỏ-lục.


Để trực tiếp chuyển đổi thành mã màu hex, bạn có thể muốn tận dụngString.format("#%06X", 0xFFFFFF & getTrafficlightColor(value));
ngeek

10

Nếu bạn muốn một đại diện xanh-vàng-đỏ như câu trả lời được chấp nhận cho thấy thì hãy xem cái này.

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>


Tôi đang nhận được các giá trị bằng nhau cho các tỷ lệ phần trăm khác nhau bằng cách sử dụng mã này ... có ý tưởng nào không? Ví dụ: tất cả các tỷ lệ phần trăm sau trả về RGB 1,255,0: 0,277, 0,2222, 0,11 ... các giá trị cao hơn (ví dụ 1.0) sẽ trả về các RGB chính xác với màu xanh lá cây sáng hơn, nhưng chúng dừng lại sau một ngưỡng và tôi chỉ nhận được sắc thái của màu xanh lá cây trên quy mô của tôi.
Patrick

8

Nội suy tuyến tính giữa màu xanh lá cây và màu đỏ hầu như sẽ hoạt động, ngoại trừ ở giữa sẽ có màu nâu bùn.

Giải pháp linh hoạt nhất và tìm kiếm tốt nhất là có một tệp hình ảnh ở đâu đó có đoạn màu chính xác mà bạn muốn. Và sau đó tra cứu giá trị pixel trong đó. Điều này có tính linh hoạt mà bạn có thể điều chỉnh độ dốc cho vừa phải .

Nếu bạn vẫn muốn thực hiện nó từ mã, thì có lẽ tốt nhất là nội suy giữa các màu xanh lá cây và màu vàng ở phía bên trái và giữa màu vàng và màu đỏ ở phía bên phải. Trong không gian RGB, màu xanh lá cây là (R = 0, G = 255, B = 0), màu vàng là (R = 255, G = 255, B = 0), màu đỏ là (R = 255, G = 0, B = 0 ) - đây là giả sử mỗi thành phần màu đi từ 0 đến 255.


1
Gợi ý ở đây về việc tách phổ thành Đỏ / Vàng và Vàng / Xanh cho kết quả màu vàng đẹp nhất.
hình

4

Tôi đã thực hiện một hàm nhỏ cung cấp cho bạn giá trị số nguyên rgb cho giá trị phần tră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);
}

Vì vậy, nếu currentValue của bạn là 50 và maxValue của bạn là 100, hàm này sẽ trả về màu mà bạn cần, vì vậy nếu bạn lặp chức năng này với giá trị phần trăm, giá trị màu của bạn sẽ chuyển từ xanh sang đỏ. Xin lỗi vì lời giải thích tồi


3

Câu trả lời được chấp nhận thậm chí không thực sự trả lời câu hỏi ...

C ++

Đây là một đoạn mã C ++ đơn giản từ công cụ của tôi, nội suy tuyến tính và hiệu quả giữa ba màu tùy ý:

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

Các interpolation_factorđược giả định là trong khoảng 0.0 ... 1.0.
Các màu được giả sử là trong phạm vi 0.0 ... 1.0(ví dụ: đối với OpenGL).

C #

Đây là chức năng tương tự được viết bằng 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)));
}

Các interpolationFactorđược giả định là trong khoảng 0.0 ... 1.0.
Các màu được giả định là trong phạm vi 0 ... 255.


1
Mã C # hoạt động rất tốt đối với tôi (đã thêm upvote) nhưng có một lỗi chính tả trong nội
suyFactorColor2

Ngoài ra, để hoàn thiện, đây là cách tôi sử dụng hàm để trả lại RGB cho MVC razr xem double n = factValue / maxValue; // Điều này cho tỷ lệ 0-1 var color = GetInterpiatedColor (n); return chuỗi.Concat ("#", colour.R.ToString ("X"), colour.G.ToString ("X"), colour.B.ToString ("X"));
DJIDave

@DJIDave: Wow, thật là một sai lầm rõ ràng và ngu ngốc. Tôi đã sửa nó. Cảm ơn!
Tara

2

Bạn cần nội suy tuyến tính (LERP) các thành phần màu. Đây là cách nó được thực hiện nói chung, được đưa ra một giá trị bắt đầu v0 , giá trị cuối v1tỷ lệ bắt buộc (một số float được chuẩn hóa giữa 0,0 và 1,0):

v = v0 + ratio * (v1 - v0)

Điều này cho v0 khi tỷ lệ là 0,0, v1 khi tỷ lệ là 1,0 và mọi thứ khác trong các trường hợp khác.

Bạn có thể thực hiện việc này trên các thành phần RGB hoặc sử dụng một số bảng màu khác, như HSV hoặc HLS. Hai cái sau sẽ dễ nhìn hơn, vì chúng hoạt động trên các thành phần màu sắc và độ sáng phù hợp với nhận thức màu sắc của chúng ta hơn.


2

Tôi muốn nói rằng bạn muốn một cái gì đó ở giữa một đoạn đường trong không gian HSV (có màu vàng hơi quá sáng ở giữa) và một đoạn đường trong không gian RGB (có màu nâu xấu xí ở giữa). Tôi sẽ sử dụng cái này, nơi power = 0sẽ cho màu xanh lá cây, power = 50sẽ cho màu vàng hơi xỉn, và power = 100sẽ cho màu đỏ.

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

2

Đây là giải pháp sao chép và dán cho thang đo Swift và HSV:

Trình khởi tạo UIColor chấp nhận màu sắc, độ bão hòa và độ sáng trong [0, 1] vì vậy với giá trị đã cho từ [0, 1] chúng ta có:

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

Nếu bạn cần loại gradient này (thực sự bị đảo ngược) trong CSS (phiên bản tối thiểu 2.1), bạn cũng có thể sử dụng HSL.

Giả sử bạn đang ở trong mẫu AngularJs và giá trị là một số từ 0 đến 1 và bạn muốn tạo kiểu cho một phần tử (màu nền hoặc màu văn bản) ...

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

Giá trị thứ nhất: độ (0 đỏ, 120 xanh) Giá trị thứ hai: bão hòa (50% là trung tính) Giá trị thứ ba: độ sáng (50% trung tính)

Một bài viết hay ở đây

Lý thuyết trên Wikipedia ở đây


1

Đây là Objective-Cphiên bản của giải pháp 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];
}

Trường hợp mức sẽ là một giá trị giữa 0.01.0.
Hy vọng điều này sẽ giúp được ai đó!


1

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

Phần trăm là tất nhiên value / max_value. Hoặc nếu quy mô của bạn không bắt đầu từ 0 thì (value - min_value) / (max_value - min_value).


1

JavaScript

Tôi đang sử dụng Google Visualization với biểu đồ thanh và muốn các thanh có màu xanh sang đỏ dựa trên tỷ lệ phần trăm. Đây hóa ra là giải pháp sạch nhất tôi tìm thấy và hoạt động hoàn hảo.

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

Chỉ cần đảm bảo tỷ lệ phần trăm của bạn là 50 cho 50% chứ không phải 0,5.


1

Tôi đã cập nhật câu trả lời được chấp nhận bằng cách chia nó thành nửa đầu và nửa sau của phạm vi (0,100) và thay thế 100 bằng mức tối đa, để phạm vi có thể trở nên động. Kết quả chính xác như với mô hình HSV, nhưng vẫn sử dụng RGB. Điều quan trọng là phải có (255,255,0) ở giữa để thể hiện màu vàng. Tôi đã kết hợp ý tưởng này trong câu trả lời được chấp nhận và một mã VBA khác, để đạt được nó trong VBA và sử dụng trong Excel. Tôi hy vọng logic giúp và có thể được sử dụng trong các ngôn ngữ / ứng dụng khác.

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

Chúc mừng, 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

Trong khi điều này có thể hoạt động, sẽ rất hữu ích nếu bạn cung cấp một số lời giải thích
David Glickman

0

Ví dụ khép kín

<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

Điều này sẽ thay đổi từ Đỏ sang Vàng và sau đó đến
giá trị Xanh thay đổi từ 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];
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.