为功率计生成红色和绿色之间的颜色?


136

我正在编写Java游戏,并且想实现一个功率计,以了解您要射击某些东西的难度。

我需要编写一个整数,该整数的取值范围为0-100,并且根据该数字的高低,它将返回绿色(功率标度为0)和红色(功率标度为100)之间的颜色。

与音量控制的工作方式类似:
音量控制

我需要对颜色的红色,绿色和蓝色分量执行什么操作才能生成绿色和红色之间的颜色?

因此,我可以说,getColor(80)它将返回橙色(R,G,B中的值),或者getColor(10)将返回更绿色/黄色RGB的值。

我知道我需要增加一种新颜色的R,G,B值的分量,但是我不知道随着颜色从绿色到红色的变化,具体是上升还是下降。


进展:

我最终使用了HSV / HSB颜色空间,因为我更喜欢渐变色(中间没有深褐色)。

我使用的功能是:

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

其中“幂”是介于0.0和1.0之间的数字。0.0将返回亮红色,1.0将返回亮绿色。

Java色调图表:
Java色相图


我以前曾在这里问过相同(极其相似)的问题:http
//stackoverflow.com/questions/168838/color-scaling-function

2
您不应该反转电源吗?假设红色是最高命中率,并且您在0.1到0.4之间工作,则功率越高,H值就越低
Adriaan Davel 2012年

您在使用OpenGL吗?有多种方法可以将三角形的点设置为不同的颜色,然后在它们之间进行混合/渐变。要求图形卡为您完成工作,可能会获得更好的性能。代码也可以更简单/更具适应性(例如,如果您要让外星人功率计从绿色变为蓝色)
DarcyThomas 2013年

Answers:


202

这应该起作用-只需线性缩放红色和绿色值即可。假设您的最大红色/绿色/蓝色值为255,并且n在范围内0 .. 100

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

(针对整数数学进行了修改,Ferrucio对此给予了建议)

另一种方法是使用HSV颜色模型,并0 degrees120 degrees适合您的饱和度和值将色相从(红色)循环为(绿色)。这应该给出一个更令人满意的渐变。

这是每种技术的演示-顶部渐变使用RGB,底部使用HSV:

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


20
在HSV空间中执行此操作要好得多。
DJClayworth

@DJClayworth,是的,我参加了HSV。
mmcdole

+1; 我正要问一个新的问题,关于如何改善在HTML / PHP中为条形图着色的颜色算法...因此建议该问题与之类似,您的答案可以帮助我解决问题,而不必提出问题!谢谢!
乞求

您将如何编写适用于任何颜色值的函数?说,计算RGB 20,30,190和RBG 69,190,10之间的颜色?
Kokodoko

1
相同的技术-从值X移动到Y值的N个步骤,每一步你增量X由(YX)/ N -尽管它看起来更好,如果你在HSV空间而非RGB移动
保罗·迪克森

32

在我头顶上方,这是HSV空间中的绿红色调过渡,转换为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)

上面示例中的红色,绿色,蓝色值是百分比,您可能希望将它们乘以255,以获得最常用的0-255范围。


12

简短的“复制粘贴”答案...

在Java Std上:

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

在Android上:

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

注意:值是介于0到1之间的数字,表示红色到绿色。


要直接转换为十六进制颜色代码,您可能需要利用String.format("#%06X", 0xFFFFFF & getTrafficlightColor(value));
ngeek,2016年

10

如果您想要像接受的答案所示的绿色-黄色-红色表示形式,那么请看一下。

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>


我正在使用此代码获得不同百分比的相等值...有什么想法吗?例如,以下百分比全部返回RGB 1,255,0:0.277、0.222、0.111 ...较高的值(例如1.0)的确会返回具有更亮绿色的正确RGB,但是它们在阈值之后停止下降,我只得到在我的体重秤上的绿色阴影。
帕特里克

8

在绿色和红色之间进行线性插值几乎可以工作,除了中间会出现浑浊的棕色。

最灵活,最美观的解决方案是将图像文件放置在具有所需颜色渐变的位置。然后在其中查找像素值。这样具有灵活性,您可以调整渐变以使其恰到好处

如果您仍然想通过代码执行此操作,那么最好在左侧的绿色和黄色之间以及在右侧的黄色和红色之间进行插值。在RGB空间中,绿色为(R = 0,G = 255,B = 0),黄色为(R = 255,G = 255,B = 0),红色为(R = 255,G = 0,B = 0 )-假设每个颜色分量从0到255。


1
这里建议将光谱分为红色/黄色和黄色/绿色,以获得最令人愉悦的黄色结果。

4

我做了一个小函数,可以为您提供百分比值的rgb整数值:

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为50而maxValue为100,则此函数将返回所需的颜色,因此,如果使用百分比值循环此函数,则颜色值将从绿色变为红色。对不起,不好的解释


3

被接受的答案甚至没有真正回答问题。

C ++

这是我的引擎中的一个简单的C ++代码段,可以在三种任意颜色之间线性有效地进行插值:

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_factor被假定为在范围内0.0 ... 1.0
假定颜色在0.0 ... 1.0(例如对于OpenGL)的范围内。

C#

这是用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)));
}

interpolationFactor被假定为在范围内0.0 ... 1.0
颜色假定在的范围内0 ... 255


1
C#代码对我来说非常出色(已添加upvote),但其中存在一个拼写错误,
InterpolationFactorColor2

同样为了完整起见,这就是我利用函数将RGB返回到MVC razr视图的方式。double n = actualValue / maxValue; //这给出了0-1的比例var color = GetInterpolatedColor(n); 返回string.Concat(“#”,colour.R.ToString(“ X”),colour.G.ToString(“ X”),colour.B.ToString(“ X”));
DJIDave

@DJIDave:哇,多么明显和愚蠢的错误。我已经解决了。谢谢!
塔拉

2

您需要线性插值(LERP)颜色分量。在给定起始值v0,结束值v1和所需比率(0.0到1.0之间的标准化浮点数)的情况下,通常是按照以下方法完成的:

v = v0 + ratio * (v1 - v0)

比率为0.0时为v0,比率为1.0时为v1,其他情况下为v0。

您可以在RGB组件上执行此操作,也可以使用其他颜色方案(例如HSV或HLS)执行此操作。后两者将在视觉上更令人愉悦,因为它们使用的色相和亮度组合更适合我们的色彩感知。


2

我想说的是,您希望在HSV空间中的线段(中间有稍微太亮的黄色)和RGB空间中的线段(中间有丑陋的棕色)之间找到某种东西。我会用它,在该处power = 0将给出绿色,在该处将给出power = 50一个稍微暗淡的黄色,并且power = 100将给出红色。

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

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(最低版本2.1)中需要这种渐变(实际上是相反的),则也可以使用HSL。

假设您在AngularJs模板中,并且值是从0到1的数字,并且您要设置元素的样式(背景或文本颜色)...

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

第一个值:度(0红色,120个绿色)第二个值:饱和度(50%为中性)第三个值:亮度(50%中性)

一个很好的文章在这里

维基百科上的理论在这里


1

这是Swift和HSV规模的复制粘贴解决方案:

UIColor初始值设定项接受[0,1]中的色相,饱和度和亮度,因此对于[0,1]中的给定,我们有:

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

这是Objective-CSimucal解决方案的版本:

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

其中level是介于0.0和之间的值1.0
希望这对某人有帮助!


1

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

百分比当然是value / max_value。或者如果您的标度不是从0开始的话(value - min_value) / (max_value - min_value)


1

的JavaScript

我正在将Google可视化与条形图一起使用,并希望条形图根据百分比从绿色变为红色。原来这是我找到的最干净的解决方案,并且效果很好。

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

只要确保您的百分比是50表示50%,而不是 0.50。


1

我通过将可接受的答案分为(0,100)范围的上半部分和后半部分,然后用最大水平替换100来更新了可接受的答案,以便使范围变得动态。结果与HSV模型完全相同,但仍使用RGB。关键是中间应有(255,255,0)代表黄色。我将这个想法结合到了可接受的答案和另一个VBA代码中,因此可以在VBA中实现并在Excel中使用。我希望该逻辑有所帮助,并可以在其他语言/应用程序中使用。

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

欢呼声,帕夫林


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

尽管这可能有效,但如果您提供一些解释将很有帮助
David Glickman

0

自包含的例子

<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

从红色到黄色,然后从绿色
到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];
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.