修改RGB图像亮度的算法?

13

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

谢谢。

7个回答

23

最简单的方法是将每个R,G,B值乘以某个常数 - 如果该常数>1,则会使其更亮,如果<1,则会变暗。如果你要让它更亮,则必须测试每个值,以确保它不会超过最大值(通常为255)。

这不仅比从RGB转换为HSL然后再转回来更简单,而且更接近于当你照射不同量的光线在物体上时所发生的情况。


是的,在模型 L = (R+G+B)/3 下得到的确切结果相同,但某些亮度模型不使用该假设(请参见我链接的维基百科页面)。由于原帖不够明确,我决定保持“通用”。 - Chris A.
@ChrisA。这真的会得到相同的结果吗?例如,我认为L和S之间存在一些交互作用,如果您进行了大刀阔斧的更改,那么会出现一些非常糟糕的情况。 - Mark Ransom
好观点!这正是我在回答中尽量少假设并保持一般性的原因。我记得学过马克,但现在我正在试图为了好奇心而证实它是否确实如此。 - Chris A.
你说得对,马克,饱和度对RGB有一些有趣的影响。我关于L = (R+G+B)/3的评论纯粹是数学上的动机,但显然这不是通常的定义方式。但你的好观点也是你自己答案的反驳。例如,尝试使用像mspaint中具有HSL和RGB的颜色轮进行玩耍。将RGB乘以标量并不总是与任何意义上的L的变化一一对应。 - Chris A.
将亮度通过转换为HSL再转回来进行修改和通过上述技术进行修改的亮度修改必须相同吗?我的意思是说,对于这种转换,亮度和明度是否等效? - nimbudew
@Flipper 亮度和亮度可能是相同的,但色调和饱和度可能会有所不同。 - Mark Ransom

20

1
HSL与物理学或心理物理学没有任何关系,它只是RGB欧几里得坐标的极坐标重写。此外,HSL中的“L”表示亮度,而不是亮度。亮度是以Cd/m²为单位的物理度量。在像素操作中不应使用HSL,它最多只适用于GUI参数,在转换为RGB之前使用。 - Aurélien Pierre

4

我的建议与ChrisA.的答案相同,只有一个区别:

使用HSP颜色空间代替,因为它是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);
}

4

补充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的值保持为零。


0
你可以尝试使用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);

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

    }

}

-3

调整图像亮度是最简单的图像处理操作之一。所需做的就是将所需的亮度变化添加到每个红色、绿色和蓝色颜色分量中。

大致上会是这样:

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

1
不,这是“加权混合白色”而不是亮度。 - Vortico

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接