5
$\begingroup$

I'm trying to get a grey linear-RGB-triple that is equally bright as another (colorful) RGB-triple.

I have to admit, that there is great confusion for me with all the color stuff, even though I read a lot of wikipedia articles, but I don't really get the big picture. I'm kind of lost and need help.

Wikipedia seems to mention a formula to receive the perceived brightness of a linear RGB color.
So I can measure the brightness of my color and do something like this I suppose:

public Vector3d get_equally_bright_grey(Vector3d color) {
    for (double c = 0.0; c <= 1.0; c += 0.001) {
        Vector3d grey = new Vector3d(c, c, c);
        if (brightness(color) == brightness(grey)){
            return grey;
        }
    }
}

But there has to be something other :)


Some context:

My input colors were spectral distributions that I converted to XYZ values (after Bruce Lindbloom). Then I have converted those XYZ values to linear RGB (again with Bruce). And here comes my question.

I know that the Y component of my XYZ triples is also something like the luminance, but I don't know how I generate a grey color XYZ color from this either..


$\endgroup$

2 Answers 2

5
$\begingroup$

The easiest way to get the perceived brightness of a color is to calculate the Luma. Finding the grey color with the same luma is easy - just set all of the RGB components to the desired luma value. That works because the coefficients for calculating the luma sum up to 1.

public Vector3d get_equally_bright_grey(Vector3d color) {
    double luma = color.x * 0.299 + color.y * 0.587 + color.z * 0.114;
    return new Vector3d(luma, luma, luma);
}
$\endgroup$
5
  • $\begingroup$ Thanks for your response! Two questions: 1) The wiki article uses R' G' B' in the equation which corespond to "gamma-compressed" values. So wouldn't give me this wrong numbers because I'm using linear RGB? 2) Could you explain why you've chosen this formula from the article? I'm confused why this does apply to my case and not the one with 0.2126 ... $\endgroup$
    – PeteParly
    Nov 1, 2016 at 20:58
  • $\begingroup$ @PeteParly It's a matter of choice. I tend to use this formula for calculating the brightness of colors in linear space, because it gives subjectively more pleasing results than the rather aggressive Rec. 709 formula, at least on my monitor. As for gamma-compressed colors, the wiki article mentions the same formula is arbitrarily used for both gamma and linear color spaces, despite it giving different results. $\endgroup$ Nov 1, 2016 at 21:41
  • $\begingroup$ @PeteParly The best thing you can do is to try out multiple formulas and choose the one that works for you. I'm not aware of any particular standard, besides the Lab color space, which tries to more closely approximate human vision: en.wikipedia.org/wiki/Lab_color_space Using it is a bit more involved, though. To get just the gray color, you'd have to convert your RGB color to Lab, then set the a and b components to 0, effectively removing chrominance, and then convert it back to the RGB space of your choice. $\endgroup$ Nov 1, 2016 at 21:44
  • $\begingroup$ @PeteParly you can do better if you have a colorimeter, than you can make a icc profile and be more exact for your monitor $\endgroup$
    – joojaa
    Nov 2, 2016 at 17:02
  • $\begingroup$ This is copy pasted in terms of weights and incorrect. What is missed in those three weight values is the fact that for any given colour space the weights are different. The weights are determined by the given primary lamp's luminance position, or Y. The values given 0.299, 0.587, and 0.114 are archaic and incorrect. For any given set of encoded values representing sRGB / 709 lights, the correct values are 0.2126, 0.7152, and 0.0722. Do not use the weights posted in the answer. It is not subjective. $\endgroup$
    – troy_s
    Dec 27, 2016 at 16:20
1
$\begingroup$

As @Quinchilion mentioned, the calculation is done using three weights applied to the color components:

luminance = color.r * r_weight + color.g * g_weight + color.b * b_weight;

There are many coefficients that can be found on the internet, there are two sample in an old OpenGL note:

https://www.opengl.org/archives/resources/code/samples/advanced/advanced97/notes/node140.html

The weights that @Quinchilion presents in his answer are used in the Analog YPbPr (0.299, 0.587, 0.114) standard. It's also called BT 601 luma (a.k.a. "luminance").

The ones proposed by SGI (link above) are (0.3086, 0.6094, 0.0820). These probably better apply to a nice CRT color monitor.

As shown in the link proposed by @Quinchilion and mentioned by @troy_s, the BT 709 uses (0.2126, 0.7152, 0.0722). This is what modern HDTV and monitors use. This is a video thing that happens in your video board or your monitor (it depends the type of connector you're using.)

Older HDTV monitors use (0.212, 0.701, 0.087). I'm not too sure how you can know which one you have, though. They say 1035i is the cutoff.

So, the analog video Y component calculation should definitely not be used if you're working on images being displayed on a modern 1080p or better monitor. The BT 709 is certainly the best choice today. If you work on a software that various people will use, having a preference screen where the end user can choose would be best (unless you want to be able to compare what they see and what you see software wise, then stick to one specific set of weights.)

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.