【问题标题】:Algorithm to modify brightness for RGB image?修改RGB图像亮度的算法?
【发布时间】:2012-06-22 20:23:11
【问题描述】:

我知道 RGB -> Luminance 有一个公式,但我需要给定一个亮度参数来修改图像的 RGB 值。我该怎么做?

谢谢

【问题讨论】:

    标签: image-processing rgb


    【解决方案1】:

    最简单的方法是将每个 R、G、B 值乘以某个常数——如果常数 >1,它会变亮,如果

    这不仅比从 RGB 转换为 HSL 再转换回来更简单,而且更接近于您在物理对象上照射不同量的光时发生的情况。

    【讨论】:

    • 是的,在模型 L = (R+G+B)/3 下可以得出相同的结果,但某些亮度模型不使用该假设(请参阅我链接的维基百科页面。)由于 OP 含糊不清,我决定成为“一般”。
    • @ChrisA。它真的能解决同样的问题吗?我认为 L 和 S 之间存在一些交互,例如,如果你进行剧烈的改变,这会造成非常糟糕的事情。
    • 好点!正是为什么我试图在我的答案中尽可能少地假设并保持一般性。我记得虽然马克知道它确实如此,但我现在正试图支持这一点,只是为了好奇。
    • 你是对的马克,饱和度对 RGB 有一些有趣的影响。我对L = (R+G+B)/3 的评论纯粹是出于数学动机,但这显然不是通常定义的方式。但是您的优点也是对您自己的答案的反驳。例如,尝试使用像 mspaint 中具有 HSL 和 RGB 的色轮。将 RGB 乘以标量并不总是一对一的变化,无论如何都是 L。
    • 通过转换为 HSL 来修改亮度和通过上述技术修改亮度是否一定相同?我的意思是说,这种转换的亮度和亮度是否相等?
    【解决方案2】:

    从RGB映射到HSL(Hue/saturation/luminance),保持色相和饱和度不变,只修改亮度,然后进行HSL到RGB的反向映射。

    You can read more about the RGB to HSL and HSL to RGB transformations here.

    【讨论】:

    • HSL 与物理学或心理物理学无关,它只是 RGB 欧几里得坐标的极坐标改写。此外,HSL 中的“L”表示亮度,而不是亮度。亮度是以 Cd/m² 为单位的物理指标。 HSL 非常糟糕,不应该用于像素操作。在转换为 RGB 之前,它最多对 GUI 参数有用。
    【解决方案3】:

    添加到 Mark Ransom 的答案:最好使用带有 255 常量的所述因子并将其添加到当前颜色值:

    float brightnessFac = //between -1.0 and 1.0    
    byte brightnessRed = red + (255f * brightnessFac);
    

    如果你只使用 0.0 到 1.0 之间的因子

    byte brightnessRed = red * brightnessFac;
    

    0 值保持为零。

    【讨论】:

      【解决方案4】:

      我的建议与ChrisA.的回答相同,但有一点不同:

      请改用HSP color space,因为它是 Photoshop 算法的近似值,效果更好。


      为了不只是链接到 HSP 的网站(坦率地说应该绰绰有余;只是我不想在没有示例的情况下回答),这是我的 C# 实现,它遵循该网站的:

      #region Definitions
      //Perceived brightness to Red ratio.
      private const double Pr = .299;
      //Perceived brightness to Green ratio.
      private const double Pg = .587;
      //Perceived brightness to Blue ratio.
      private const double Pb = .114;
      #endregion
      
      //Expected ranges: Hue = 0-359... Other values = 0-1
      public static ColorRGB ToRGB(double hue, double saturation, double perceivedBrightness, double alpha) {
          //Check values within expected range
          hue = hue < 0 ? 0 : hue > 359 ? 359 : hue;
          saturation = saturation < 0 ? 0 : saturation > 1 ? 1 : saturation;
          perceivedBrightness = perceivedBrightness < 0 ? 0 : perceivedBrightness > 1 ? 1 : perceivedBrightness;
          alpha = alpha < 0 ? 0 : alpha > 1 ? 1 : alpha;
          //Conversion
          var minOverMax = 1 - saturation;
          double r, g, b;
          if (minOverMax > 0) {
              double part;
              if (hue < 0.166666666666667D) { //R>G>B
                  hue = 6 * (hue - 0); part = 1 + hue * (1 / minOverMax - 1);
                  b = perceivedBrightness / Math.Sqrt(Pr / minOverMax / minOverMax + Pg * part * part + Pb);
                  r = b / minOverMax; g = b + hue * (r - b);
              }
              else if (hue < 0.333333333333333D) { //G>R>B
                  hue = 6 * (-hue + 0.333333333333333D); part = 1 + hue * (1 / minOverMax - 1);
                  b = perceivedBrightness / Math.Sqrt(Pg / minOverMax / minOverMax + Pr * part * part + Pb);
                  g = b / minOverMax; r = b + hue * (g - b);
              }
              else if (hue < 0.5D) {   //  G>B>R
                  hue = 6 * (hue - 0.333333333333333D); part = 1 + hue * (1 / minOverMax - 1);
                  r = perceivedBrightness / Math.Sqrt(Pg / minOverMax / minOverMax + Pb * part * part + Pr);
                  g = r / minOverMax; b = r + hue * (g - r);
              }
              else if (hue < 0.666666666666667D) { //B>G>R
                  hue = 6 * (-hue + 0.666666666666667D); part = 1 + hue * (1 / minOverMax - 1);
                  r = perceivedBrightness / Math.Sqrt(Pb / minOverMax / minOverMax + Pg * part * part + Pr);
                  b = r / minOverMax; g = r + hue * (b - r);
              }
              else if (hue < 0.833333333333333D) { //B>R>G
                  hue = 6 * (hue - 0.666666666666667D); part = 1 + hue * (1 / minOverMax - 1);
                  g = perceivedBrightness / Math.Sqrt(Pb / minOverMax / minOverMax + Pr * part * part + Pg);
                  b = g / minOverMax; r = g + hue * (b - g);
              }
              else { //R>B>G
                  hue = 6 * (-hue + 1D); part = 1 + hue * (1 / minOverMax - 1);
                  g = perceivedBrightness / Math.Sqrt(Pr / minOverMax / minOverMax + Pb * part * part + Pg);
                  r = g / minOverMax; b = g + hue * (r - g);
              }
          }
          else {
              if (hue < 0.166666666666667D) { //R>G>B
                  hue = 6 * (hue - 0D); r = Math.Sqrt(perceivedBrightness * perceivedBrightness / (Pr + Pg * hue * hue)); g = r * hue; b = 0;
              }
              else if (hue < 0.333333333333333D) { //G>R>B
                  hue = 6 * (-hue + 0.333333333333333D); g = Math.Sqrt(perceivedBrightness * perceivedBrightness / (Pg + Pr * hue * hue)); r = g * hue; b = 0;
              }
              else if (hue < 0.5D) { //G>B>R
                  hue = 6 * (hue - 0.333333333333333D); g = Math.Sqrt(perceivedBrightness * perceivedBrightness / (Pg + Pb * hue * hue)); b = g * hue; r = 0;
              }
              else if (hue < 0.666666666666667D) { //B>G>R
                  hue = 6 * (-hue + 0.666666666666667D); b = Math.Sqrt(perceivedBrightness * perceivedBrightness / (Pb + Pg * hue * hue)); g = b * hue; r = 0;
              }
              else if (hue < 0.833333333333333D) { //B>R>G
                  hue = 6 * (hue - 0.666666666666667D); b = Math.Sqrt(perceivedBrightness * perceivedBrightness / (Pb + Pr * hue * hue)); r = b * hue; g = 0;
              }
              else { //R>B>G
                  hue = 6 * (-hue + 1D); r = Math.Sqrt(perceivedBrightness * perceivedBrightness / (Pr + Pb * hue * hue)); b = r * hue; g = 0;
              }
          }
          return new ColorRGB(r, g, b, alpha);
      }
      
      //Expected ranges: 0-1 on all components
      public static ColorHSP FromRGB(double red, double green, double blue, double alpha) {
          //Guarantee RGB values are in the correct ranges
          red = red < 0 ? 0 : red > 1 ? 1 : red;
          green = green < 0 ? 0 : green > 1 ? 1 : green;
          blue = blue < 0 ? 0 : blue > 1 ? 1 : blue;
          alpha = alpha < 0 ? 0 : alpha > 1 ? 1 : alpha;
          //Prepare & cache values for conversion
          var max = MathExtensions.Max(red, green, blue);
          var min = MathExtensions.Min(red, green, blue);
          var delta = max - min;
          double h, s, p = Math.Sqrt(0.299 * red + 0.587 * green + 0.114 * blue);
          //Conversion
          if (delta.Equals(0)) h = 0;
          else if (max.Equals(red)) {
              h = (green - blue) / delta % 6;
          }
          else if (max.Equals(green)) h = (blue - red) / delta + 2;
          else h = (red - green) / delta + 4;
          h *= 60;
          if (h < 0) h += 360;
          if (p.Equals(0))
              s = 0;
          else
              s = delta / p;
          //Result
          return new ColorHSP(h, s, p, alpha);
      }
      

      【讨论】:

        【解决方案5】:
        import java.io. * ;
        import java.awt.Color;
        import javax.imageio.ImageIO;
        import java.io. * ;
        import java.awt.image.BufferedImage;
        
        class Psp {
        
            public static void main(String a[]) {
                try {
        
                    File input = new File("abc.jpg");
                    File output = new File("output1.jpg");
                    BufferedImage picture1 = ImageIO.read(input); // original
                    BufferedImage picture2 = new BufferedImage(picture1.getWidth(), picture1.getHeight(), BufferedImage.TYPE_INT_RGB);
                    int width = picture1.getWidth();
                    int height = picture1.getHeight();
        
                    int factor = 50;
                    for (int y = 0; y < height; y++) { //loops for images
                        for (int x = 0; x < width; x++) {
        
                            Color c = new Color(picture1.getRGB(x, y));
                            int r = c.getRed() + factor;
                            int b = c.getBlue() + factor;
                            int g = c.getGreen() + factor;
        
                            if (r >= 256) {
                                r = 255;
                            } else if (r < 0) {
                                r = 0;
                            }
        
                            if (g >= 256) {
                                g = 255;
                            } else if (g < 0) {
                                g = 0;
                            }
        
                            if (b >= 256) {
                                b = 255;
                            } else if (b < 0) {
                                b = 0;
                            }
                            picture2.setRGB(x, y, new Color(r, g, b).getRGB());
        
                        }
                    }
        
                    ImageIO.write(picture2, "jpg", output);
                } catch(Exception e) {
                    System.out.println(e);
                }
        
            }
        
        }
        

        【讨论】:

          【解决方案6】:

          你可以试试 LookupTable 和 LookupOp;这样您就可以通过修改 LookupTable 来调整图片的亮度。 使图片变亮只是为 RGB 增加一些值。

          BufferedImage dstImage = new BufferedImage(input.getWidth(), input.getHeight(),BufferedImage.TYPE_3BYTE_BGR);
                  LookupTable lookupTable = new ShortLookupTable(0, data);
                  LookupOp op = new LookupOp(lookupTable, null);
                  op.filter(toBeTone, dstImage);
          

          【讨论】:

            【解决方案7】:

            调整图像的亮度是可以完成的最简单的图像处理操作之一。所涉及的只是为每个红色、绿色和蓝色分量添加所需的亮度变化。

            会是这样的:

            colour = GetPixelColour(x, y)
               newRed   = Truncate(Red(colour)   + brightness)
               newGreen = Truncate(Green(colour) + brightness)
               newBlue  = Truncate(Blue(colour)  + brightness)
               PutPixelColour(x, y) = RGB(newRed, newGreen, newBlue)
            

            确保红色、绿色和蓝色的新值在有效范围内的代码。

            Procedure Truncate(value)
                  If value < 0 Then value = 0
                  If value > 255 Then value = 255
                  Return value
               EndProcedure
            

            【讨论】:

            • 不,这是与亮度不同的“加权混合白色”。
            猜你喜欢
            • 2015-03-19
            • 2012-06-13
            • 1970-01-01
            • 2013-01-04
            • 1970-01-01
            • 1970-01-01
            • 2017-12-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多