代码之家  ›  专栏  ›  技术社区  ›  robmerica

确定RGB颜色亮度的公式

  •  346
  • robmerica  · 技术社区  · 17 年前

    18 回复  |  直到 5 年前
        1
  •  532
  •   Lionel Rowe    5 年前

    根据您的需要,方法可能会有所不同。以下是计算亮度的3种方法:

    • 亮度(特定颜色空间的标准): (0.2126*R + 0.7152*G + 0.0722*B) source img

    • (0.299*R + 0.587*G + 0.114*B) source img

    • 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 ) (感谢 @MatthewHerbst source img

    [编辑:添加使用命名css颜色的示例,按每个方法排序。]

        2
  •  331
  •   Glenn Slayden    10 年前

    我认为您正在寻找的是RGB-> Luma

    光度/数字 ITU BT.709

    Y = 0.2126 R + 0.7152 G + 0.0722 B
    

    数字的 ITU BT.601 (赋予R和B组件更大的权重):

    Y = 0.299 R + 0.587 G + 0.114 B
    

    如果您愿意以精度换取性能,则此近似公式有两个:

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

    这些可以通过以下方式快速计算:

    Y = (R+R+B+G+G+G)/6
    
    Y = (R+R+R+B+G+G+G+G)>>3
    
        3
  •  116
  •   aleclarson    6 年前

    我已经比较了公认答案中的三种算法。我在循环中生成了颜色,其中只使用了大约每400种颜色。每种颜色由2x2像素表示,颜色从最暗到最亮(从左到右,从上到下)排序。

    第一张照片- Luminance (relative)

    0.2126 * R + 0.7152 * G + 0.0722 * B
    

    第二张照片- http://www.w3.org/TR/AERT#color-contrast

    0.299 * R + 0.587 * G + 0.114 * B
    

    第三张照片- HSP Color Model

    sqrt(0.299 * R^2 + 0.587 * G^2 + 0.114 * B^2)
    

    第四幅画- WCAG 2.0 SC 1.4.3 relative luminance contrast ratio 公式(见 @Synchro's 答复 here )

    Perceived brightness algorithm comparison

        4
  •  111
  •   Myndex    5 年前

    “已接受”答案不正确且不完整

    @jive-dadson @EddingtonsMonkey 回答,并表示支持 @nils-pipenbrinck 正在链接或引用错误、无关、过时或已损坏的来源。

    简要地:

    • sRGB必须是 在应用系数之前。
    • 感知亮度(L*)和人类感知一样是非线性的。
    • HSV和HSL在感知方面甚至一点也不精确。
    • 0.03928(来自过时的早期草稿)。
    • 这本书可能有用 (即相对于感知)

    以下是正确和完整的答案:

    因为这条线索在搜索引擎中出现的频率很高,我添加这个答案是为了澄清关于这个主题的各种误解。

    是光的线性测量,光谱加权用于正常视觉,但不用于光的非线性感知。它可以是一个相对的衡量标准, Y 比如在CIEXYZ,或者 L 2. L* ) .

    感知亮度 L* 知觉亮度 ,并且是非线性的,近似于人类视觉的非线性响应曲线。

    是一种感知属性,它没有“物理”度量。但是,某些颜色外观模型确实具有 ,通常表示为 “Q” 用于感知亮度,与感知亮度不同。

    (

    伽马射线

    确定可感知的亮度 ,首先将gamma编码的RGB图像值转换为线性亮度( L Y )


    要查找亮度,请执行以下操作:

    …因为很明显它在什么地方丢了。。。

    第一步:

    将所有sRGB 8位整数值转换为十进制0.0-1.0

      vR = sR / 255;
      vG = sG / 255;
      vB = sB / 255;
    

    第二步:

    将gamma编码的RGB转换为线性值。例如,sRGB(计算机标准)要求功率曲线约为V^2.2,但“精确”转换为:

    sRGB to Linear


    伪代码:

    function sRGBtoLin(colorChannel) {
            // Send this function a decimal sRGB gamma encoded color value
            // between 0.0 and 1.0, and it returns a linearized value.
    
        if ( colorChannel <= 0.04045 ) {
                return colorChannel / 12.92;
            } else {
                return pow((( colorChannel + 0.055)/1.055),2.4));
            }
        }
    

    第三步:

    Apply coefficients Y = R * 0.2126 + G * 0.7152 + B *  0.0722

    使用上述函数的伪代码:

    Y = (0.2126 * sRGBtoLin(vR) + 0.7152 * sRGBtoLin(vG) + 0.0722 * sRGBtoLin(vB))
    

    要找到可感知的亮度:

    第四步:

    L* from Y equation
    伪代码:

    function YtoLstar(Y) {
            // Send this function a luminance value between 0.0 and 1.0,
            // and it returns L* which is "perceptual lightness"
    
        if ( Y <= (216/24389) {       // The CIE standard states 0.008856 but 216/24389 is the intent for 0.008856451679036
                return Y * (24389/27);  // The CIE standard states 903.3, but 24389/27 is the intent, making 903.296296296296296
            } else {
                return pow(Y,(1/3)) * 116 - 16;
            }
        }
    

    L*是从0(黑色)到100(白色)的值,其中50是感知的“中灰色”。L*=50相当于Y=18.4,换句话说,是一张18%的灰色卡片,代表摄影曝光的中间部分(Ansel Adams V区)。

    参考资料:

    IEC 61966-2-1:1999 Standard
    Wikipedia sRGB
    Wikipedia CIELAB
    Wikipedia CIEXYZ
    Charles Poynton's Gamma FAQ

        5
  •  66
  •   xjcl    5 年前

    对于典型的计算机材料,颜色空间是sRGB。sRGB的正确数字约为0.21、0.72和0.07。sRGB的Gamma是一个复合函数,它近似于1/(2.2)的幂运算。这里是C++的全部内容。

    // sRGB luminance(Y) values
    const double rY = 0.212655;
    const double gY = 0.715158;
    const double bY = 0.072187;
    
    // Inverse of sRGB "gamma" function. (approx 2.2)
    double inv_gam_sRGB(int ic) {
        double c = ic/255.0;
        if ( c <= 0.04045 )
            return c/12.92;
        else 
            return pow(((c+0.055)/(1.055)),2.4);
    }
    
    // sRGB "gamma" function (approx 2.2)
    int gam_sRGB(double v) {
        if(v<=0.0031308)
          v *= 12.92;
        else 
          v = 1.055*pow(v,1.0/2.4)-0.055;
        return int(v*255+0.5); // This is correct in C++. Other languages may not
                               // require +0.5
    }
    
    // GRAY VALUE ("brightness")
    int gray(int r, int g, int b) {
        return gam_sRGB(
                rY*inv_gam_sRGB(r) +
                gY*inv_gam_sRGB(g) +
                bY*inv_gam_sRGB(b)
        );
    }
    
        6
  •  14
  •   Gust van de Wal user41410    6 年前

    我建议您选择W3C标准推荐的公式,而不是在这里提到的随机选择公式中迷失方向。

    WCAG 2.0 SC 1.4.3 relative luminance contrast ratio 公式。它生成的值适用于评估WCAG合规性所需的比率,如 this page

    /**
     * Calculate relative luminance in sRGB colour space for use in WCAG 2.0 compliance
     * @link http://www.w3.org/TR/WCAG20/#relativeluminancedef
     * @param string $col A 3 or 6-digit hex colour string
     * @return float
     * @author Marcus Bointon <marcus@synchromedia.co.uk>
     */
    function relativeluminance($col) {
        //Remove any leading #
        $col = trim($col, '#');
        //Convert 3-digit to 6-digit
        if (strlen($col) == 3) {
            $col = $col[0] . $col[0] . $col[1] . $col[1] . $col[2] . $col[2];
        }
        //Convert hex to 0-1 scale
        $components = array(
            'r' => hexdec(substr($col, 0, 2)) / 255,
            'g' => hexdec(substr($col, 2, 2)) / 255,
            'b' => hexdec(substr($col, 4, 2)) / 255
        );
        //Correct for sRGB
        foreach($components as $c => $v) {
            if ($v <= 0.04045) {
                $components[$c] = $v / 12.92;
            } else {
                $components[$c] = pow((($v + 0.055) / 1.055), 2.4);
            }
        }
        //Calculate relative luminance using ITU-R BT. 709 coefficients
        return ($components['r'] * 0.2126) + ($components['g'] * 0.7152) + ($components['b'] * 0.0722);
    }
    
    /**
     * Calculate contrast ratio acording to WCAG 2.0 formula
     * Will return a value between 1 (no contrast) and 21 (max contrast)
     * @link http://www.w3.org/TR/WCAG20/#contrast-ratiodef
     * @param string $c1 A 3 or 6-digit hex colour string
     * @param string $c2 A 3 or 6-digit hex colour string
     * @return float
     * @author Marcus Bointon <marcus@synchromedia.co.uk>
     */
    function contrastratio($c1, $c2) {
        $y1 = relativeluminance($c1);
        $y2 = relativeluminance($c2);
        //Arrange so $y1 is lightest
        if ($y1 < $y2) {
            $y3 = $y1;
            $y1 = $y2;
            $y2 = $y3;
        }
        return ($y1 + 0.05) / ($y2 + 0.05);
    }
    
        7
  •  11
  •   Community Mohan Dere    6 年前

    我发现 this code

        8
  •  10
  •   Nils Pipenbrinck    17 年前

    要补充所有其他人所说的话:

    所有这些方程在实践中都很有效,但如果需要非常精确,则必须首先将颜色转换为线性颜色空间(应用逆图像gamma),然后对原色进行加权平均,如果要显示颜色-

    在深灰色中,ingnoring gamma和doing Right gamma之间的亮度差异高达20%。

        9
  •  8
  •   bobobobo    13 年前

    this formulation for RGB=>HSV 只使用v=MAX3(r,g,b)。换句话说,您可以使用 最大限度 属于(r,g,b)作为HSV中的V。

    我在第575页的 Hearn & Baker 这也是他们计算“价值”的方式。

    From Hearn&Baker pg 319

        10
  •  5
  •   catamphetamine    6 年前

    getPerceivedLightness(rgb) 用于十六进制RGB颜色的函数。 通过Fairchild和Perrotta亮度校正公式处理Helmholtz-Kohlrauch效应。

    /**
     * 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))))
    }
    
        11
  •  2
  •   Gust van de Wal user41410    6 年前

    // reverses the rgb gamma
    #define inverseGamma(t) (((t) <= 0.0404482362771076) ? ((t)/12.92) : pow(((t) + 0.055)/1.055, 2.4))
    
    //CIE L*a*b* f function (used to convert XYZ to L*a*b*)  http://en.wikipedia.org/wiki/Lab_color_space
    #define LABF(t) ((t >= 8.85645167903563082e-3) ? powf(t,0.333333333333333) : (841.0/108.0)*(t) + (4.0/29.0))
    
    
    float
    rgbToCIEL(PIXEL p)
    {
       float y;
       float r=p.r/255.0;
       float g=p.g/255.0;
       float b=p.b/255.0;
    
       r=inverseGamma(r);
       g=inverseGamma(g);
       b=inverseGamma(b);
    
       //Observer = 2°, Illuminant = D65 
       y = 0.2125862307855955516*r + 0.7151703037034108499*g + 0.07220049864333622685*b;
    
       // At this point we've done RGBtoXYZ now do XYZ to Lab
    
       // y /= WHITEPOINT_Y; The white point for y in D65 is 1.0
    
        y = LABF(y);
    
       /* This is the "normal conversion which produces values scaled to 100
        Lab.L = 116.0*y - 16.0;
       */
       return(1.16*y - 0.16); // return values for 0.0 >=L <=1.0
    }
    
        12
  •  1
  •   Ian Hopkinson    17 年前

    wikipedia article 根据您使用的语言,您可能会得到库转换。

    H是色调,是颜色的数值(即红色、绿色…)

    S是颜色的饱和度,即颜色的“强度”

    V是颜色的“亮度”。

        13
  •  1
  •   Gandalf Gandalf    17 年前

    http://www.scantips.com/lumin.html

    我认为RGB颜色空间相对于L2欧几里德距离是感知不均匀的。 统一空间包括CIE实验室和LUV。

        14
  •  1
  •   Dave Collier    10 年前

    Jive Dadson的反gamma公式在Javascript中实现时需要删除半调整,即函数gam_sRGB的返回值需要为return int(v*255);不返回整数(v*255+.5);半调整四舍五入,这可能导致R=G=B上的值过高,即灰色三元组。R=G=B三元组上的灰度转换应产生等于R的值;这是这个公式有效的一个证明。 看见 Nine Shades of Greyscale

        15
  •  1
  •   vortex    9 年前

    Y = 0.267 R + 0.642 G + 0.091 B
    

    接近但明显不同于长期确定的ITU系数。我想知道,对于每个观察者来说,这些系数是否会有所不同,因为我们的眼睛视网膜上可能有不同数量的视锥细胞和视杆细胞,特别是不同类型视锥细胞之间的比例可能会有所不同。

    国际电联BT.709:

    Y = 0.2126 R + 0.7152 G + 0.0722 B
    

    Y = 0.299 R + 0.587 G + 0.114 B
    

    是的,我大概有正常的色觉。

        16
  •  0
  •   Jacob    17 年前

    HSV的“V”可能就是您所寻找的。MATLAB有一个rgb2hsv函数,前面引用的维基百科文章中充满了伪代码。如果RGB2HSV转换不可行,则精度较低的模型将是图像的灰度版本。

        17
  •  0
  •   Emil    13 年前

    This link 深入解释一切,包括为什么这些乘数常数在R、G和B值之前存在。

        18
  •  0
  •   Pierre-louis Stenger    9 年前

    为了用R确定颜色的亮度,我将RGB系统颜色转换为HSV系统颜色。

    在我的脚本中,出于其他原因,我以前使用十六进制系统代码,但您也可以从RGB系统代码开始 rgb2hsv {grDevices} here .

     sample <- c("#010101", "#303030", "#A6A4A4", "#020202", "#010100")
     hsvc <-rgb2hsv(col2rgb(sample)) # convert HEX to HSV
     value <- as.data.frame(hsvc) # create data.frame
     value <- value[3,] # extract the information of brightness
     order(value) # ordrer the color by brightness
    
        19
  •  -1
  •   Pavel P    8 年前

    为清楚起见,需要使用平方根的公式

    sqrt(coefficient * (colour_value^2))

    sqrt((coefficient * colour_value))^2

    Nine Shades of Greyscale

        20
  •  -2
  •   Ben S    17 年前

    请定义亮度。如果你想知道这种颜色有多接近白色,你可以使用它 Euclidean Distance from(255,255,255)

    推荐文章