【问题标题】:Algorithm: How do I fade from Red to Green via Yellow using RGB values?算法:如何使用 RGB 值通过黄色从红色渐变到绿色?
【发布时间】:2011-09-17 16:02:38
【问题描述】:

我想根据 0 到 100 的值显示一种颜色。一端 (100) 是纯红色,另一端 (0) 是纯绿色。在中间(50),我希望它是黄色的。

我希望颜色逐渐从一种渐变到另一种,这样在 75 时,颜色是半红半黄,等等。

如何对 RGB 值进行编程以反映这种渐变?谢谢。

【问题讨论】:

  • WPF?表格?你打算将渐变应用到什么地方?

标签: c# algorithm rgb


【解决方案1】:

看看LinearGradientBrush。它应该是您正在寻找的完整实现。

【讨论】:

    【解决方案2】:

    我不懂 C#,所以这个答案只是一个建议的方法。让x 表示范围从0100int。这样的事情应该可以工作:

    red   = (x > 50 ? 1-2*(x-50)/100.0 : 1.0);
    green = (x > 50 ? 1.0 : 2*x/100.0);
    blue  = 0.0
    

    这个想法是从红色开始:(1.0,0.0,0.0)。然后增加绿色变成黄色:(1.0,1.0,0.0)。然后将红色减小为绿色:(0.0,1.0,0.0)

    编辑:这是 C# 中的代码

    static Color GetColorFromRedYellowGreenGradient(double percentage)
    {
        var red = (percentage > 50 ? 1 - 2 * (percentage - 50) / 100.0 : 1.0) * 255;
        var green = (percentage > 50 ? 1.0 : 2 * percentage / 100.0) * 255;
        var blue = 0.0;
        Color result = Color.FromArgb((int)red, (int)green, (int)blue);
        return result;
    }
    

    【讨论】:

    • 这样更直接。
    【解决方案3】:

    颜色的 RGB 值:

    • 红色 255, 0, 0
    • 黄色255、255、0
    • 绿色 0, 255, 0

    在红色和黄色之间,将您添加到绿色通道的距离相等,直到达到 255。在黄色和绿色之间,将您从红色通道中的减法间隔相等。

    【讨论】:

    • 颜色不是线性的,从 0 到 64 的变化比从 191 到 255 的变化更大,这在 LED 显示屏上尤其明显,因为它们的黑色更黑。
    • @Ferrybig,考虑到您的评论,正确的插值公式是什么?
    【解决方案4】:

    您需要改用HSB or HSV color representation,并使用 H(“色调”)值。请参阅其他 SO 问题以了解 RGB 和 HSB/HSV 之间的转换:How to change RGB color to HSV?

    【讨论】:

      【解决方案5】:

      这是一个非常简单的颜色分量线性插值。它可能会满足您的需求。

      public Color GetBlendedColor(int percentage)
      {
          if (percentage < 50)
              return Interpolate(Color.Red, Color.Yellow, percentage / 50.0);
          return Interpolate(Color.Yellow, Color.Lime, (percentage - 50) / 50.0);
      }
      
      private Color Interpolate(Color color1, Color color2, double fraction)
      {
          double r = Interpolate(color1.R, color2.R, fraction);
          double g = Interpolate(color1.G, color2.G, fraction);
          double b = Interpolate(color1.B, color2.B, fraction);
          return Color.FromArgb((int)Math.Round(r), (int)Math.Round(g), (int)Math.Round(b));
      }
      
      private double Interpolate(double d1, double d2, double fraction)
      {
          return d1 + (d2 - d1) * fraction;
      }
      

      【讨论】:

      • 在 Interpolate 函数中,假设 d2 是您的目标颜色,d1 是您的开始颜色,它应该是 (d2 - d1) 而不是 (d1 - d2)。
      • 这对我的自定义颜色和d1d2 的修复帮助很大。
      【解决方案6】:

      我也有同样的需求,我刚刚解决了这个问题:

      myColor = new Color(2.0f * x, 2.0f * (1 - x), 0);
      

      说明: 让我们关注颜色分量的 [0.0-1.0] 范围,而不是 [0-255] 范围:

      • 绿色 = 0.0, 1.0, 0.0
      • 黄色 = 1.0, 1.0, 0.0
      • 红色= 1.0, 0.0, 0.0

      如果你只是将绿色分量从 0.0(一端)缩放到 1.0(另一端)并对红色分量做同样的事情(但向后),你会得到丑陋和不均匀的颜色分布。

      为了让它看起来更好看,我们可以写很多代码,或者我们可以更聪明。

      如果您仔细查看单个分量,您会发现我们可以将范围分成两个相等的部分:在第一个部分中,我们将红色分量从 0.0 增加到 1.0,使绿色为 1.0,蓝色为 0.0 ;在第二个中,我们减少了绿色分量,将其他 2 个保持原样。我们可以利用任何高于 1.0 的值都将被读取为 1.0 的事实,通过最大化我们的值来简化代码。假设您的 x 值从 0.00 (0%) 变为 1.00 (100%),您可以将其乘以 2 以使其超过颜色分量的 1.0 限制。现在您的组件从 0.0 变为 2.0(红色)和从 2.0 变为 0.0(绿色)。让它们被剪裁到 [0.0-1.0] 范围,然后就可以了。

      如果您的 x 在另一个范围内移动(例如 [0-100]),您需要选择适当的因子而不是 2

      【讨论】:

      • 非常感谢。当我发现自己处于这种确切情况时,我想到了这种方法,因为其他解决方案对于这样的任务似乎太复杂了
      • 这绝对是最好的答案,因为它很简单而且效果很好。实际上,我必须计算出一些值才能完全理解它为何如此有效
      • 满足我们需求的优秀解决方案。我们用 Javascript 计算它,从红色到白色再到绿色。这增加了一个有趣的转折,因为黄色分量从 0.0 变为 1.0,然后通过比例返回 0.0。这计算为 yellowValue = 1 - Math.abs(value - 0.5) * 2;
      • @GiorgioAresu,我采用了您的原理并将其应用于此处找到的 codepen 上的实用程序:codepen.io/ahopkins/full/beNWWp
      • 完美运行!我正在使用 python (PyQt5) 并且不得不稍微修改:QColor(min(255,2*255*(temp)),min(255,2*255*(1-temp)),0)
      【解决方案7】:

      简化的扩展方法;

      public static Color Interpolate(this Color source, Color target, double percent)
      {
          var r = (byte)(source.R + (target.R - source.R) * percent);
          var g = (byte)(source.G + (target.G - source.G) * percent);
          var b = (byte)(source.B + (target.B - source.B) * percent);
      
          return Color.FromArgb(255, r, g, b);
      }
      

      用法;

      var low = 33.0;
      var high = 100.0;
      var color = Color.Red.Interpolate(Color.Green, low / high);
      

      【讨论】:

        【解决方案8】:

        你只需要创建一个带有整数参数的函数

        • 输入 100 将返回 RGB (100, 0, 0)
        • 输入 50 将返回 RGB (50, 50, 0)
        • 输入 0 将返回 RGB (0, 100, 0)
        • 输入 99 将返回 RGB (99, 1, 0)
        • 输入 98 将返回 RGB (98, 2, 0)
        • 输入 2 将返回 RGB (2, 98, 0)
        • 输入 1 将返回 RGB (1, 99, 0)

          私人颜色推子(int v){ 返回 Color.FromArgb(v, 100-v, 0); }

        【讨论】:

        • 您似乎忘记了 r.g.b 的值最多为 255 而不是 100。
        • 这实际上不会很好地褪色,黄色部分会很窄
        【解决方案9】:

        我今天需要类似的东西。输入是从 0.0 到 1.0 的百分比,输出红色到绿色。基于jterrace的回答实现:

        Color percentToColor(float percent)
        {
            if (percent<0 || percent>1) { return Color.Black; }
        
            int r, g;
            if (percent<0.5)
            {
                r=255;
                g = (int)(255*percent/0.5);  //closer to 0.5, closer to yellow (255,255,0)
            }
            else
            {
                g=255;
                r = 255 - (int)(255*(percent-0.5)/0.5); //closer to 1.0, closer to green (0,255,0)
            }
            return Color.FromArgb(r, g, 0);
        }
        

        【讨论】:

          【解决方案10】:

          在我用更逼真的颜色试验了一段时间后,这是我的公式:

          public Color GetColorOf(double value, double minValue, double maxValue)
          {
              if (value == 0 || minValue == maxValue) return Color.White;
          
              var g = (int)(240 * value / maxValue);
              var r = (int)(240 * value / minValue);
          
              return (value > 0
                  ? Color.FromArgb(240 - g, 255 - (int)(g * ((255 - 155) / 240.0)), 240 - g)
                  : Color.FromArgb(255 - (int)(r * ((255 - 230) / 240.0)), 240 - r, 240 - r));
          }
          
          • 0(或 NULL)或 min = max 时没有背景(即 Color.White)。
          • 对于所有正值,您会在 RGB(240, 255, 240) 和 RGB(0, 155, 0) 之间获得均匀分布的绿色。
          • 对于所有负值,您会在 RGB(255, 240, 240) 和 RGB(230, 0, 0) 之间获得均匀分布的红色。

          【讨论】:

          • 这没有回答原始问题。它不仅通过白色而不是黄色,而且在不同于请求的数字范围内运行。
          • +1 因为有一个适合我的绿色到白色到红色的算法,但确实没有回答 OP 问题。
          • 不管这回答什么问题……这就是天才。
          【解决方案11】:

          我使用此函数将 1400 MHz 和 3500 MHz 之间的 CPU 速度值映射到 rgb() 值以从绿色 -> 黄色 -> 红色

          function green_yellow_red(core_MHz, core_id){
            var core_color = ~~core_MHz.map(1400, 3500, 0, 510)
          
            if(core_color < 255){
              $('#cpu_core_'+core_id).css('background', 'rgb('+core_color+',255 , 0)')
            }else{
              core_color-=255
              $('#cpu_core_'+core_id).css('background', 'rgb(255 ,'+ (255-core_color) +', 0)')
            }
          }
          

          【讨论】:

            【解决方案12】:

            我为 UIColor 编写了一个 Swift 4 扩展,它将百分比 (0-100) 转换为从红色到绿色的 UIColor。

            我目前正在将它用于分析应用程序中的进度条。这是一个例子:

            let myNewColor = UIColor().greenRedProgress(percent: Int))
            

            这是扩展名:

            extension UIColor{
            
            func greenRedProgress(percent: Int) -> UIColor{
                let modVal = CGFloat((Double(percent).truncatingRemainder(dividingBy: 50) / 50) * 255)
                if percent <= 0{
                    return UIColor(red: 1.0, green: 0, blue: 0, alpha: 1)
                }else if percent >= 100{
                    return UIColor(red: 0, green: 1.0, blue: 0, alpha: 1)
                }else{
                    switch percent{
                        case 1..<50: return UIColor(red: 1.0, green: (modVal/255), blue: 0, alpha: 1)
                        case 51..<100: return UIColor(red: (255 - modVal)/255, green: 1.0, blue: 0, alpha: 1)
                        case 50: return UIColor(red: 1.0, green: 1.0, blue: 0, alpha: 1)
                        default: return UIColor(red: 0, green: 1.0, blue: 0, alpha: 1)
                    }
                }
            }}
            

            【讨论】:

              【解决方案13】:

              此方法(在 c# 中,但可以轻松翻译成其他语言)将采用百分比和颜色列表,并根据您的百分比返回渐变颜色。当您传递颜色时,它们需要按从 0 值到 100 值的顺序排列(因此您需要按绿色、黄色、红色的顺序传递)。如果您发现中间需要不同或更多颜色,只需按照您希望它们出现的顺序将它们添加到您传递的颜色列表中即可。

              public Color ColorBasedOnPercent(decimal percent, params Color[] colors)
                  {
                      if (colors.Length == 0)
                      {
                          //I am using Transparent as my default color if nothing was passed
                          return Color.Transparent;
                      }
                      if (percent > 1)
                      {
                          percent = percent / 100;
                      }
              
                      //find the two colors within your list of colors that the percent should fall between
                      var colorRangeIndex = (colors.Length - 1) * percent;
                      var minColorIndex = (int)Math.Truncate(colorRangeIndex);
                      var maxColorIndex = minColorIndex + 1;
                      var minColor = colors[minColorIndex];
              
                      if (maxColorIndex < colors.Length)
                      {
                          var maxColor = colors[maxColorIndex];
              
                          //get the differences between all the color values for the two colors you are fading between
                          var aScale = maxColor.A - minColor.A;
                          var redScale = maxColor.R - minColor.R;
                          var greenScale = maxColor.G - minColor.G;
                          var blueScale = maxColor.B - minColor.B;
              
                          //the decimal distance of how "far" this color should be from the minColor in the range
                          var gradientPct = colorRangeIndex - minColorIndex;
              
                          //for each piece of the color (ARGB), add a percentage(gradientPct) of the distance between the two colors
                          int getRGB(int originalRGB, int scale) => (int)Math.Round(originalRGB + (scale * gradientPct));
              
                          return Color.FromArgb(getRGB(minColor.A, aScale), getRGB(minColor.R, redScale), getRGB(minColor.G, greenScale), getRGB(minColor.B, blueScale));
                      }
                      return minColor;
                  }
              

              【讨论】:

                【解决方案14】:

                更多相同。只需 Delphi Pascal 编码并简化+锁定为信号量颜色(红色/黄色/绿色)。

                rectangle1.Fill.Color:=DefineColorSemaphore(newcolor);
                
                function TForm1.DefineColorSemaphore(valperc:integer):TAlphaColor;
                var
                   vcol: TAlphaColorRec;
                begin
                  vcol.B := 0;    // blue:  always 0
                  vcol.A := 255;  // alpha: 255=no
                  if (valperc < 50) then
                    begin
                       // starts @ RGB=255,0,0 and increases G 0->255
                       vcol.R := 255;
                       vcol.G := trunc(255*valperc/50);
                    end
                    else
                    begin
                       // starts @ RGB=255,255,0 and decreases R 255->0
                       vcol.R := 255-trunc(255* (valperc - 50)/50);
                       vcol.G := 255;
                    end;
                  result:= TAlphaColor(vcol);
                end;
                

                【讨论】:

                  【解决方案15】:

                  最近我打算用 Javascript 做同样的事情。我遵循了两个步骤。

                  1. 先在0-1范围内缩放值(scaledValue = (value - min) / (max - min))
                  2. 如果值小于或等于 0.5,则增加红色通道的值,如果值大于 0.5,则减少绿色通道的值

                  这是我用于此目的的代码。

                  var blue = 0.0, red = 0.0, green = 0.0;
                  
                  if(scaledValue <= 0.5)
                  {
                      red = (scaledValue * 2) * 255.0;
                      green = 255.0;
                      blue = 0;
                  }else
                  {
                      red = 255.0;
                      green = 255.0 + 255.0 - ((scaledValue  * 2)* 255);
                      blue = 0;
                  }
                  

                  A sample code for showing this works in C++

                  此解决方案的灵感来自@jterrace 答案。

                  【讨论】:

                    【解决方案16】:

                    // 在 WM_DRAWITEM 上用红黄绿渐变填充 OwnerDraw 控件

                    int cx = lpDis->rcItem.right - lpDis->rcItem.left;
                    
                    for (int x = 0; x < cx; x++)
                    {
                        COLORREF cr;
                    
                        double d = 255 * 2 * (double)x/(double)cx;
                    
                        cr = x <= cx/2 ?    RGB(255,     d,   0) :
                                            RGB(255 - d, 255, 0);
                    
                        HPEN hPen = CreatePen(PS_SOLID, 1, cr);
                        HPEN hOldPen = (HPEN)SelectObject(lpDis->hDC, hPen);
                        MoveToEx(lpDis->hDC, x, lpDis->rcItem.top, NULL);
                        LineTo(lpDis->hDC, x, lpDis->rcItem.bottom);
                        SelectObject(lpDis->hDC, hOldPen);
                        DeleteObject(hPen);
                    }
                    

                    Illustration

                    【讨论】:

                      【解决方案17】:

                      如果您使用的是 python,那么这可能会有所帮助...

                      
                      def rgb(p):# <-- percentage as parameter
                          #Starting with color red
                          d = [255,0,0]
                          #formula for finding green value by percentage
                          d[1] = int((510*p)/100)
                          print(d[1])
                          #if green value more than 255
                          #set green value 255
                          #reduce the red value from remaining green value
                          if d[1]>255:
                              d[0] -= d[1]-255
                              d[1] = 255
                              
                          return d
                      
                      print(rgb(0))
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2021-07-07
                        • 1970-01-01
                        • 1970-01-01
                        • 2013-09-27
                        • 1970-01-01
                        • 2011-05-08
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多