Algorithm to modify brightness for RGB image?

后端 未结 6 1130
深忆病人
深忆病人 2020-12-10 05:33

I know there is formula for going RGB -> Luminance, but I need given a brightness parameter to modify the RGB values of an image. How do I do that?

Thanks

6条回答
  •  暖寄归人
    2020-12-10 06:11

    My recommendation would be the same as ChrisA.'s answer, with one difference:

    Use the HSP color space instead, as it is an approximation of Photoshop's algorithm and has better results.


    For the sake of not just linking to HSP's site (which frankly should be more than enough; it's just that I don't like to answer without examples), here is my C# implementation, which follows the site's:

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

提交回复
热议问题