Formula to determine perceived brightness of RGB color

377,210

Solution 1

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.]

Solution 2

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

Solution 3

The "Accepted" Answer is Incorrect and Incomplete

The only answers that are accurate are the @jive-dadson and @EddingtonsMonkey answers, and in support @nils-pipenbrinck. The other answers (including the accepted) are linking to or citing sources that are either wrong, irrelevant, obsolete, or broken.

Briefly:

  • sRGB must be LINEARIZED before applying the coefficients.
  • Luminance (L or Y) is linear as is light.
  • Perceived lightness (L*) is nonlinear as is human perception.
  • HSV and HSL are not even remotely accurate in terms of perception.
  • The IEC standard for sRGB specifies a threshold of 0.04045 it is NOT 0.03928 (that was from an obsolete early draft).
  • To be useful (i.e. relative to perception), Euclidian distances require a perceptually uniform Cartesian vector space such as CIELAB. sRGB is not one.

What follows is a correct and complete answer:

Because this thread appears highly in search engines, I am adding this answer to clarify the various misconceptions on the subject.

Luminance is a linear measure of light, spectrally weighted for normal vision but not adjusted for the non-linear perception of lightness. It can be a relative measure, Y as in CIEXYZ, or as L, an absolute measure in cd/m2 (not to be confused with L*).

Perceived lightness is used by some vision models such as CIELAB, here L* (Lstar) is a value of perceptual lightness, and is non-linear to approximate the human vision non-linear response curve. (That is, linear to perception but therefore non linear to light).

Brightness is a perceptual attribute, it does not have a "physical" measure. However some color appearance models do have a value, usualy denoted as "Q" for perceived brightness, which is different than perceived lightness.

Luma ( prime) is a gamma encoded, weighted signal used in some video encodings (Y´I´Q´). It is not to be confused with linear luminance.

Gamma or transfer curve (TRC) is a curve that is often similar to the perceptual curve, and is commonly applied to image data for storage or broadcast to reduce perceived noise and/or improve data utilization (and related reasons).

To determine perceived lightness, first convert gamma encoded R´G´B´ image values to linear luminance (L or Y ) and then to non-linear perceived lightness (L*)


TO FIND LUMINANCE:

...Because apparently it was lost somewhere...

Step One:

Convert all sRGB 8 bit integer values to decimal 0.0-1.0

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

Step Two:

Convert a gamma encoded RGB to a linear value. sRGB (computer standard) for instance requires a power curve of approximately V^2.2, though the "accurate" transform is:

sRGB to Linear

Where V´ is the gamma-encoded R, G, or B channel of sRGB.
Pseudocode:

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

Step Three:

To find Luminance (Y) apply the standard coefficients for sRGB:

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

Pseudocode using above functions:

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

TO FIND PERCEIVED LIGHTNESS:

Step Four:

Take luminance Y from above, and transform to L*

L* from Y equation
Pseudocode:

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* is a value from 0 (black) to 100 (white) where 50 is the perceptual "middle grey". L* = 50 is the equivalent of Y = 18.4, or in other words an 18% grey card, representing the middle of a photographic exposure (Ansel Adams zone V).

References:

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

Solution 4

I have made comparison of the three algorithms in the accepted answer. I generated colors in cycle where only about every 400th color was used. Each color is represented by 2x2 pixels, colors are sorted from darkest to lightest (left to right, top to bottom).

1st picture - Luminance (relative)

0.2126 * R + 0.7152 * G + 0.0722 * B

2nd picture - http://www.w3.org/TR/AERT#color-contrast

0.299 * R + 0.587 * G + 0.114 * B

3rd picture - HSP Color Model

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

4th picture - WCAG 2.0 SC 1.4.3 relative luminance and contrast ratio formula (see @Synchro's answer here)

Pattern can be sometimes spotted on 1st and 2nd picture depending on the number of colors in one row. I never spotted any pattern on picture from 3rd or 4th algorithm.

If i had to choose i would go with algorithm number 3 since its much easier to implement and its about 33% faster than the 4th.

Perceived brightness algorithm comparison

Solution 5

Below is the only CORRECT algorithm for converting sRGB images, as used in browsers etc., to grayscale.

It is necessary to apply an inverse of the gamma function for the color space before calculating the inner product. Then you apply the gamma function to the reduced value. Failure to incorporate the gamma function can result in errors of up to 20%.

For typical computer stuff, the color space is sRGB. The right numbers for sRGB are approx. 0.21, 0.72, 0.07. Gamma for sRGB is a composite function that approximates exponentiation by 1/(2.2). Here is the whole thing in 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)
    );
}
Share:
377,210
Muhammad Umer
Author by

Muhammad Umer

Updated on November 27, 2021

Comments

  • Muhammad Umer
    Muhammad Umer over 2 years

    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 together and having higher sums be brighter, but I'm kind of at a loss as to where to start.

  • Anonymous
    Anonymous about 15 years
    Yes, it all depends on the application. All these models including human subjective perception...
  • S..K
    S..K about 15 years
    Note also that all of these are probably for linear 0-1 RGB, and you probably have gamma-corrected 0-255 RGB. They are not converted like you think they are.
  • Beska
    Beska about 15 years
    I like that you put in precise values, but also included a quick "close enough" type shortcut. +1.
  • Anonymous
    Anonymous over 14 years
    For the first two the source is in the other answers. As for the final one - I think it was from the lectures on television or graphics...
  • mistertodd
    mistertodd almost 14 years
    Problem with the HSV color space is that you can have the same saturation and value, but different hue's, for blue and yellow. Yellow is much brighter than blue. Same goes for HSL.
  • Nemi
    Nemi almost 14 years
    I think your last formula is incorrect. I get it returning black for a dark blue color.
  • Jonathan Dumaine
    Jonathan Dumaine over 13 years
    How come your 'calculated quickly' values don't include blue in the approximation at all?
  • Franci Penov
    Franci Penov over 13 years
    @Jonathan Dumaine - the two quick calculation formulas both include blue - 1st one is (2*Red + Blue + 3*Green)/6, 2nd one is (3*Red + Blue + 4*Green)>>3. granted, in both quick approximations, Blue has the lowest weight, but it's still there.
  • Jonathan Dumaine
    Jonathan Dumaine over 13 years
    Hmm don't know why I didn't see the B's in there before.
  • Christopher Oezbek
    Christopher Oezbek almost 12 years
    @JonathanDumaine That's because the human eye is least perceptive to Blue ;-)
  • Jive Dadson
    Jive Dadson over 11 years
    Not correct. Before applying the linear transformation, one must first apply the inverse of the gamma function for the color space. Then after applying the linear function, the gamma function is applied.
  • JMD
    JMD about 11 years
    Why did you use a composite function to approximate the exponent? Why not just do a direct calculation? Thanks
  • Jive Dadson
    Jive Dadson about 11 years
    That is just the way sRGB is defined. I think the reason is that it avoids some numerical problems near zero. It would not make much difference if you just raised the numbers to the powers of 2.2 and 1/2.2.
  • Jack
    Jack about 11 years
    Luminance only accounts for human spectral sensitivity. It does not account the for the human non-linear perception of Luminance, which the CIE have standardised as "Lightness" (the L in the CIELAB color space) Depending on your application you may need to first calculate Luminance, and then Lightness ... en.wikipedia.org/wiki/Lightness
  • user151496
    user151496 about 10 years
    why would you prefer w3c definition? personally i have implemented both CCIR 601 and the w3c recommended one and i was much more satisfied with the CCIR 601 results
  • user151496
    user151496 about 10 years
    hsv gives you the "brightness" of a color in a technical sense. in a perceptual brightness hsv really fails
  • Synchro
    Synchro about 10 years
    Because, as I said, it's recommended by both the W3C and WCAG?
  • Synchro
    Synchro about 10 years
    The first two are linear, the last one is a bit arbitrary and does not incorporate gamma correction or sRGB color space correction.
  • Jerry Federspiel
    Jerry Federspiel over 9 years
    JMD - as part of work in a visual perception lab, I have done direct luminance measurements on CRT monitors and can confirm that there is a linear region of luminance at the bottom of the range of values.
  • Mark Ransom
    Mark Ransom over 9 years
    @alexstrange the first formula uses linear RGB values and the second uses gamma-corrected values. The first formula is more modern, the second dates from the invention of NTSC. And the range doesn't matter since there are no non-linear operations. The third formula appears to operate on gamma-corrected values, but as it isn't a standard it's harder to be sure.
  • milosmns
    milosmns over 9 years
    The quick version works well. Tested and applied to real-world app with thousands of users, everything looks fine.
  • Franci Penov
    Franci Penov over 9 years
    If the color components are limited to 8 bits, the perceived luminance option 2 can be calculated as fast as the option 1 with a 256 ints lookup table of the precomputed squares. And all three can be calculated really fast with a lookup table of each color value premultiplied with each coefficient. Though that does require a lot of memory.
  • CoffeDeveloper
    CoffeDeveloper over 9 years
    To me this is the best answer because oyu use a picture pattern that let you perceive if different hues are rendered with th same luminance. For me and my current monitor the 3rd picture is the "best looking" since it is also faster then 4th that's a plus
  • rjmunro
    rjmunro about 9 years
    The quick version is even faster if you do it as: Y = (R<<1+R+G<<2+B)>>3 (thats only 3-4 CPU cycles on ARM) but I guess a good compiler will do that optimisation for you.
  • DCBillen
    DCBillen almost 9 years
    I know this is very old, but its still out there to be searched. I don't think it can be correct. Shouldn't gray(255,255,255) = gray(255,0,0)+gray(0,255,0)+gray(0,0,255)? It doesn't.
  • Rahul Iyer
    Rahul Iyer almost 9 years
    In the last formula, is it (0.299*R)^2 or is it 0.299*(R^2) ?
  • rdb
    rdb over 8 years
    @DCBillen: no, since the values are in non-linear gamma-corrected sRGB space, you can't just add them up. If you wanted to add them up, you should do so before calling gam_sRGB.
  • log0
    log0 about 8 years
    there are parenthesis mistmatches
  • RufusVS
    RufusVS almost 8 years
    That is exactly what I needed. I was doing a classic "color bars" demo, and wanted to label them on top of the color with the best black-or-white choice!
  • RufusVS
    RufusVS almost 8 years
    unless the coefficient you use is the square root of the correct coefficient.
  • Stephen Smith
    Stephen Smith over 7 years
    Here's a jsfiddle that lets you pick colors and see the luminance, in case anybody else needs to see what kinds of values you get from these formulas. (Based on the last slowest formula) jsfiddle.net/sbrexep0
  • Jive Dadson
    Jive Dadson over 7 years
    @DCBillen Rdb is correct. The way to add them up is shown in the function int gray(int r, int g, int b), which "uncalls" gam_sRGB. It pains me that after four years, the correct answer is rated so low. :-) Not really.. I will get over it.
  • RedPolygon
    RedPolygon almost 7 years
    @KaizerSozay As it's written here it would mean 0.299*(R^2) (because exponentiation goes before multiplication)
  • Slipp D. Thompson
    Slipp D. Thompson almost 7 years
    @bobobobo From the Wikipedia pages for en.wikipedia.org/wiki/Relative_luminance and en.wikipedia.org/wiki/Grayscale . It's important to note that the R, G, & B multipliers are not based on any exact science; rather, they're just values that have been found to be the average luma perceived by the human eye for each channel. This was crucially important when there existed both B&W (grayscale) & color TV sets; the testing of the population was done around that time (1950s). More background at en.wikipedia.org/wiki/Color_television .
  • Jive Dadson
    Jive Dadson almost 7 years
    It sounds like you know your stuff, so I removed the +0.5
  • Jive Dadson
    Jive Dadson almost 7 years
    I did the experiment. In C++ it needs the +0.5, so I put it back in. I added a comment about translating to other languages.
  • Peter
    Peter almost 7 years
    Just for the record the link is dead, archive version here - web.archive.org/web/20150906055359/http://…
  • Mingye Wang
    Mingye Wang over 6 years
    When it comes to W3C on a11y, the newer WCAG guide specifies the 1st formula with suggestion for linearization: w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
  • Max
    Max over 6 years
    Your comparison image is incorrect because you did not provide the correct input to all of the functions. The first function requires linear RGB input; I can only reproduce the banding effect by providing nonlinear (i.e. gamma-corrected) RGB. Correcting this issue, you get no banding artifacts and the 1st function is the clear winner.
  • Max
    Max over 6 years
    @MarkRansom I have verified that the last uses gamma-corrected values. FWIW to my eye the first formula gives the best results, though it's expensive if your colors aren't in linear space. The last could be a nice hack if you don't want to undo the gamma.
  • Mark Ransom
    Mark Ransom over 6 years
    @Max formula #3 has been modified, now it's the same as #2 with an approximation of gamma to linear conversion. It's using a gamma of 2.0 instead of 2.2 to make things quicker. If you're going to use linear RGB I'd use the constants from formula #1 instead, my experience matches yours that #1 with linear is the best.
  • zenw0lf
    zenw0lf over 5 years
    @JiveDadson As I see it, it is applied right there where it says //Correct for sRGB. At least it is almost the same operation you have defined as inv_gam_sRGB. So I think this is correct.
  • Mark Ransom
    Mark Ransom about 5 years
    @Max the ^2 and sqrt included in the third formula are a quicker way of approximating linear RGB from non-linear RGB instead of the ^2.2 and ^(1/2.2) that would be more correct. Using nonlinear inputs instead of linear ones is extremely common unfortunately.
  • Myndex
    Myndex about 5 years
    The W3C formula is incorrect on a number of levels. It is not taking human perception into account, they are using "simple" contrast using luminance which is linear and not at all perceptually uniform. Among other things, it appears they based it on some standards as old as 1988 (!!!) which are not relevant today (those standards were based on monochrome monitors such as green/black, and referred to the total contrast from on to off, not considering greyscale nor colors).
  • Synchro
    Synchro about 5 years
    That’s complete rubbish. Luma is specifically perceptual - that’s why it has different coefficients for red, green, and blue. Age has nothing to do with it - the excellent CIE Lab perceptual colour space dates from 1976. The W3C space isn’t as good, however it is a good practical approximation that is easy to calculate. If you have something constructive to offer, post that instead of empty criticism.
  • Myndex
    Myndex about 5 years
    @Syncro no, luma is a GAMMA ENCODED (Y´) part of some video encodings (such as NTSC's YIQ). Luminance, i.e. Y as in CIEXYZ is LINEAR, and not at all perceptual. the W3C are using linear luminance, and simple contrast, which does not properly define contrast in the mid range (it is way off). Writing an article on this right now, I'll post the link when complete. Yes, CIELAB is excellent, but W3C ARE NOT USING IT. The outdated doc I am referring to is ANSI-HFES-100-1988, and not appropriate for on-screen color contrasts.
  • Tim Kuipers
    Tim Kuipers almost 5 years
    Your gray function performs a gamma compression afterwards, but luminance itself is the uncompressed gray value, so if you want to compute the brightness then leave out the call togam_sRGB. If you just want to convert colors in order to display them black-and-white, then you should leave it in.
  • Myndex
    Myndex almost 5 years
    HSV is not perceptually uniform (and it isn't even close). It is used only as a "convenient" way to adjust color, but it is not relevant to perception, and the V does not relate to the true value of L or Y (CIE Luminance).
  • Myndex
    Myndex almost 5 years
    Just to add/update: we are currently researching replacement algorithms that better model perceptual contrast (discussion in Github Issue 695). However, as a separate issue FYI the threshold for sRGB is 0.04045, and not 0.03928 which was referenced from an obsolete early sRGB draft. The authoritative IEC std uses 0.04045 and a pull request is forthcoming to correct this error in the WCAG. (ref: IEC 61966-2-1:1999) This is in Github issue 360, though to mention, in 8bit there is no actual difference — near end of thread 360 I have charts of errors including 0.04045/0.03928 in 8bit.
  • Myndex
    Myndex almost 5 years
    HSV and HSL are not perceptually accurate (and it's not even close). They are useful for "controls" for adjusting relative color, but not for accurate prediction of perceptual lightness. Use L* from CIELAB for perceptual lightness.
  • Myndex
    Myndex almost 5 years
    In your experiments did you linearize to remove the gamma component first? If you didn't that could explain your results. BUT ALSO, the coefficients are related to the CIE 1931 experiments and those are an average of 17 observers, so yes there is individual variance in results.
  • Myndex
    Myndex almost 5 years
    No, you can't use euclidian distance between sRGB values, sRGB is not a perceptually uniform Cartesian/vector space. If you want to use Euclidian distance as a measure of color difference, you need to at least convert to CIELAB, or better yet, use a CAM like CIECAM02.
  • Myndex
    Myndex almost 5 years
    @Rotem thank you — I saw some odd and incomplete statements and felt it would be helpful to nail it down, particularly as this thread still ranks highly on search engines.
  • Rotem
    Rotem almost 5 years
    I created a demonstration comparing BT.601 Luma and CIE 1976 L* Perceptual Gray, using few MATLAB commands: Luma=rgb2gray(RGB);LAB=rgb2lab(RGB);LAB(:,:,2:3)=0;Perceptua‌​lGray=lab2rgb(LAB);
  • sjahan
    sjahan over 4 years
    @Myndex I used your formulas to get to L*, but I still get some strange results, whatever the formula I use... With yours, L* of #d05858 is darker than L* of #c51c2a... Is there any way to get this right? Why does no formula work as expected? :(
  • catamphetamine
    catamphetamine over 4 years
    Hi. Your answer seems to be the most legit. However, I was solving a similar task today and found out about Helmholtz-Kohlrausch effect that makes red color more bright than gray color with the same Luminance. See my answer below for the Helmholtz-Kohlrausch effect correction and the true "perceived brightness" of a color.
  • Myndex
    Myndex over 4 years
    @sjahan L* of D05858 is 53.1, and L* of C51C2A is 42.6 — what results are you getting?? #777777 should be L* 50. Can you show me your code?
  • Myndex
    Myndex over 4 years
    @asdfasdfads Yes, L*a*b* does not take into account a number of psychophysical attributes. Helmholtz-Kohlrausch effect is one, but there are many others. CIELAB is not a "full" image assessment model by any means. In my post I was trying to cover the basic concepts as completely as possible without venturing into the very deep minutiae. The Hunt model, Fairchild's models, and others do a more complete job, but are also substantially more complex.
  • sjahan
    sjahan over 4 years
    @Myndex, nevermind, my implementation was fatigue-based and my poor results came from that :( Thank you very much for your help and your post which is of a great value!
  • Adrian McCarthy
    Adrian McCarthy almost 4 years
    Note that the incorrect threshold from the old sRGB standard is propagated in other publications, including the official description of the minimum text contrast test from Web Content Accessibility Guidelines 2.1. Since accessibility may have motivated the question, that may be useful information. w3.org/WAI/WCAG21/Techniques/general/G17.html#tests
  • Myndex
    Myndex almost 4 years
    @AdrianMcCarthy Hi Adrian, thanks, yes I know—I'm working on the new WCAG (Silver i.e. 3.0) right now, and that has been raised as an issue for some time (see my WCAG GitHub issue #695). It's not related to accessibility, just a mistake.... As it happens, this incorrect threshold is not "particularly bad" in 8 bit as it is being used there, but is nevertheless wrong. There hasn't been concerted effort to fix that issue as the new methodology in development is predicting contrast in a completely different way.
  • Lazar Ljubenović
    Lazar Ljubenović over 3 years
    Why does it say "the standard coefficients for sRGB" in step 3, when the previous step was going from sRGB to a linear RGB? I was under impression that linear RGB exists as to be "universal" among different chromaticity coordinates of RGB systems? The formula in step 2 you use is the one for sRGB, so why would in step 3 it matter which gamma-encoded RGB was used before transformation to linear?
  • Myndex
    Myndex over 3 years
    @Lazar Ljubenović the coefficients need to be applied to the linearized data, not gamma encoded data. And no, the coefficients are not universal, they vary per the color space. Remember that we humans do NOT see the visible spectrum evenly. Green makes up the majority of luminance, then red, and blue a very tiny (and sometimes negative) effect on perceived luminance. "RGB" is definitely not universal!! Different primaries require different coefficients.
  • Myndex
    Myndex over 3 years
    As I state in my separate answer, the math in this answer is generally incorrect and incomplete. #1 requires linearized sRGB which is not shown. #2 is for YCC NTSC and not sRGB. #3 is generally wrong in a lot of ways, but oddly was "more correct" before someone edited it to make it less correct! #3 is "sort of like L*" lightness, but not quite. The struck out version is ~5% incorrect, the M.Ransom version is ~15% incorrect and #1, #2 are ~40% incorrect if referenced to perceptual lightness (L*). None of these find luminance (Y), and none find perceptual brightness (Q).
  • Myndex
    Myndex about 3 years
    And to add to the thread, the replacement method for WCAG 3.0 is APCA, and can be seen at myndex.com/APCA/simple
  • Myndex
    Myndex about 3 years
    And to add: Also, the 1931 CIE values are based on a 2° observer, and in addition there are known errors in the blue region. The 10° observer values are significantly different as the S cones are not in the foveal central vision. In both cases, effort was made to avoid rod intrusion, keeping the luminance levels in the photopic area. If measurements are made in the mesopic region, rod intrusion will also skew results.
  • Klesun
    Klesun about 3 years
    Does that mean #FF0000 is as bright as #FFFFFF?
  • Klesun
    Klesun about 3 years
    I believe it's more like lightness = (max(r, g, b) + min(r, g, b)) / 2 in HSL
  • Kal
    Kal over 2 years
    @Max, you're absolutely right. See my answer for updated visuals of each algorithm, comparing gamma-compressed vs linear RGB input.
  • itachi
    itachi about 2 years
    @rjmunro I believe you are missing a few parenthesis, the addition operations will go first, so your code is the same as: Y = (R << (1 + R + G) << (2 + B)) >> 3. The correct snippet: int Y = ((R << 1) + R + (G << 2) + B) >> 3;.
  • Chris Dennis
    Chris Dennis almost 2 years
    Thank your for an excellent answer. One slight quibble: your function YtoLstar(Y) takes a value in the range 0 to 1, and returns one in the range 0 to 100, which is a bit confusing.
  • Myndex
    Myndex almost 2 years
    Hi @ChrisDennis thank you — so, commonly, Y is a 0.0-1.0 range, and L* is commonly 0-100. Sometimes Y is normalized to 0-100, in which case it must be shifted to 0.0-1.0 before applying the exponents for the power curve. L* is almost always a 0-100 range, and the ab color values are often ±128. L* is based/derived from Munsell value, which is 0-10 ... So, as for confusing, wait till you dig deeper into colorimetry—"confusing" is par for the course. (!!)
  • Chris Dennis
    Chris Dennis almost 2 years
    Fair enough, @Myndex. I've already found that colorimetry is a tricky subject.
  • OG Sean
    OG Sean almost 2 years
    Small typo... seems if ( Y <= (216/24389) { is missing a )
  • Myndex
    Myndex almost 2 years
    Hi @OGSean You are correct!! That's a typo (I'm kinda blind)... and since it was pseudocode, it was not actually tested. Thank you!!
  • OG Sean
    OG Sean almost 2 years
    I tested the formulas and they work well. Also for anyone else, pow() is Math.pow() in javascript.