Formula to determine brightness of RGB color

前端 未结 20 3114
猫巷女王i
猫巷女王i 2020-11-21 23:16

I\'m looking for some kind of formula or algorithm to determine the brightness of a color given the RGB values. I know it can\'t be as simple as adding the RGB values toget

相关标签:
20条回答
  • 2020-11-21 23:55

    Interestingly, this formulation for RGB=>HSV just uses v=MAX3(r,g,b). In other words, you can use the maximum of (r,g,b) as the V in HSV.

    I checked and on page 575 of Hearn & Baker this is how they compute "Value" as well.

    From Hearn&Baker pg 319

    0 讨论(0)
  • 2020-11-21 23:55

    This link explains everything in depth, including why those multiplier constants exist before the R, G and B values.

    Edit: It has an explanation to one of the answers here too (0.299*R + 0.587*G + 0.114*B)

    0 讨论(0)
  • 2020-11-21 23:56

    I was solving a similar task today in javascript. I've settled on this getPerceivedLightness(rgb) function for a HEX RGB color. It deals with Helmholtz-Kohlrausch effect via Fairchild and Perrotta formula for luminance correction.

    /**
     * Converts RGB color to CIE 1931 XYZ color space.
     * https://www.image-engineering.de/library/technotes/958-how-to-convert-between-srgb-and-ciexyz
     * @param  {string} hex
     * @return {number[]}
     */
    export function rgbToXyz(hex) {
        const [r, g, b] = hexToRgb(hex).map(_ => _ / 255).map(sRGBtoLinearRGB)
        const X =  0.4124 * r + 0.3576 * g + 0.1805 * b
        const Y =  0.2126 * r + 0.7152 * g + 0.0722 * b
        const Z =  0.0193 * r + 0.1192 * g + 0.9505 * b
        // For some reason, X, Y and Z are multiplied by 100.
        return [X, Y, Z].map(_ => _ * 100)
    }
    
    /**
     * Undoes gamma-correction from an RGB-encoded color.
     * https://en.wikipedia.org/wiki/SRGB#Specification_of_the_transformation
     * https://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color
     * @param  {number}
     * @return {number}
     */
    function sRGBtoLinearRGB(color) {
        // Send this function a decimal sRGB gamma encoded color value
        // between 0.0 and 1.0, and it returns a linearized value.
        if (color <= 0.04045) {
            return color / 12.92
        } else {
            return Math.pow((color + 0.055) / 1.055, 2.4)
        }
    }
    
    /**
     * Converts hex color to RGB.
     * https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
     * @param  {string} hex
     * @return {number[]} [rgb]
     */
    function hexToRgb(hex) {
        const match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
        if (match) {
            match.shift()
            return match.map(_ => parseInt(_, 16))
        }
    }
    
    /**
     * Converts CIE 1931 XYZ colors to CIE L*a*b*.
     * The conversion formula comes from <http://www.easyrgb.com/en/math.php>.
     * https://github.com/cangoektas/xyz-to-lab/blob/master/src/index.js
     * @param   {number[]} color The CIE 1931 XYZ color to convert which refers to
     *                           the D65/2° standard illuminant.
     * @returns {number[]}       The color in the CIE L*a*b* color space.
     */
    // X, Y, Z of a "D65" light source.
    // "D65" is a standard 6500K Daylight light source.
    // https://en.wikipedia.org/wiki/Illuminant_D65
    const D65 = [95.047, 100, 108.883]
    export function xyzToLab([x, y, z]) {
      [x, y, z] = [x, y, z].map((v, i) => {
        v = v / D65[i]
        return v > 0.008856 ? Math.pow(v, 1 / 3) : v * 7.787 + 16 / 116
      })
      const l = 116 * y - 16
      const a = 500 * (x - y)
      const b = 200 * (y - z)
      return [l, a, b]
    }
    
    /**
     * Converts Lab color space to Luminance-Chroma-Hue color space.
     * http://www.brucelindbloom.com/index.html?Eqn_Lab_to_LCH.html
     * @param  {number[]}
     * @return {number[]}
     */
    export function labToLch([l, a, b]) {
        const c = Math.sqrt(a * a + b * b)
        const h = abToHue(a, b)
        return [l, c, h]
    }
    
    /**
     * Converts a and b of Lab color space to Hue of LCH color space.
     * https://stackoverflow.com/questions/53733379/conversion-of-cielab-to-cielchab-not-yielding-correct-result
     * @param  {number} a
     * @param  {number} b
     * @return {number}
     */
    function abToHue(a, b) {
        if (a >= 0 && b === 0) {
            return 0
        }
        if (a < 0 && b === 0) {
            return 180
        }
        if (a === 0 && b > 0) {
            return 90
        }
        if (a === 0 && b < 0) {
            return 270
        }
        let xBias
        if (a > 0 && b > 0) {
            xBias = 0
        } else if (a < 0) {
            xBias = 180
        } else if (a > 0 && b < 0) {
            xBias = 360
        }
        return radiansToDegrees(Math.atan(b / a)) + xBias
    }
    
    function radiansToDegrees(radians) {
        return radians * (180 / Math.PI)
    }
    
    function degreesToRadians(degrees) {
        return degrees * Math.PI / 180
    }
    
    /**
     * Saturated colors appear brighter to human eye.
     * That's called Helmholtz-Kohlrausch effect.
     * Fairchild and Pirrotta came up with a formula to
     * calculate a correction for that effect.
     * "Color Quality of Semiconductor and Conventional Light Sources":
     * https://books.google.ru/books?id=ptDJDQAAQBAJ&pg=PA45&lpg=PA45&dq=fairchild+pirrotta+correction&source=bl&ots=7gXR2MGJs7&sig=ACfU3U3uIHo0ZUdZB_Cz9F9NldKzBix0oQ&hl=ru&sa=X&ved=2ahUKEwi47LGivOvmAhUHEpoKHU_ICkIQ6AEwAXoECAkQAQ#v=onepage&q=fairchild%20pirrotta%20correction&f=false
     * @return {number}
     */
    function getLightnessUsingFairchildPirrottaCorrection([l, c, h]) {
        const l_ = 2.5 - 0.025 * l
        const g = 0.116 * Math.abs(Math.sin(degreesToRadians((h - 90) / 2))) + 0.085
        return l + l_ * g * c
    }
    
    export function getPerceivedLightness(hex) {
        return getLightnessUsingFairchildPirrottaCorrection(labToLch(xyzToLab(rgbToXyz(hex))))
    }
    
    0 讨论(0)
  • 2020-11-21 23:57

    The method could vary depending on your needs. Here are 3 ways to calculate Luminance:

    • Luminance (standard for certain colour spaces): (0.2126*R + 0.7152*G + 0.0722*B) source img

    • Luminance (perceived option 1): (0.299*R + 0.587*G + 0.114*B) source img

    • Luminance (perceived option 2, slower to calculate): sqrt( 0.241*R^2 + 0.691*G^2 + 0.068*B^2 )sqrt( 0.299*R^2 + 0.587*G^2 + 0.114*B^2 ) (thanks to @MatthewHerbst) source img

    [Edit: added examples using named css colors sorted with each method.]

    0 讨论(0)
  • 2020-11-22 00:00

    I think what you are looking for is the RGB -> Luma conversion formula.

    Photometric/digital ITU BT.709:

    Y = 0.2126 R + 0.7152 G + 0.0722 B
    

    Digital ITU BT.601 (gives more weight to the R and B components):

    Y = 0.299 R + 0.587 G + 0.114 B
    

    If you are willing to trade accuracy for perfomance, there are two approximation formulas for this one:

    Y = 0.33 R + 0.5 G + 0.16 B
    
    Y = 0.375 R + 0.5 G + 0.125 B
    

    These can be calculated quickly as

    Y = (R+R+B+G+G+G)/6
    
    Y = (R+R+R+B+G+G+G+G)>>3
    
    0 讨论(0)
  • 2020-11-22 00:00

    I found this code (written in C#) that does an excellent job of calculating the "brightness" of a color. In this scenario, the code is trying to determine whether to put white or black text over the color.

    0 讨论(0)
提交回复
热议问题