Converting RGB to grayscale/intensity
Asked Answered
R

8

152

When converting from RGB to grayscale, it is said that specific weights to channels R, G, and B ought to be applied. These weights are: 0.2989, 0.5870, 0.1140.

It is said that the reason for this is different human perception/sensibility towards these three colors. Sometimes it is also said these are the values used to compute NTSC signal.

However, I didn't find a good reference for this on the web. What is the source of these values?

See also these previous questions: here and here.

Radom answered 26/3, 2009 at 19:39 Comment(2)
CCIR 601. See this wikipedia fragment: en.wikipedia.org/wiki/…Kristine
@pnizzle poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC9Radom
J
101

The specific numbers in the question are from CCIR 601 (see Wikipedia article).

If you convert RGB -> grayscale with slightly different numbers / different methods, you won't see much difference at all on a normal computer screen under normal lighting conditions -- try it.

Here are some more links on color in general:

Wikipedia Luma

Bruce Lindbloom 's outstanding web site

chapter 4 on Color in the book by Colin Ware, "Information Visualization", isbn 1-55860-819-2; this long link to Ware in books.google.com may or may not work

cambridgeincolor : excellent, well-written "tutorials on how to acquire, interpret and process digital photographs using a visually-oriented approach that emphasizes concept over procedure"

Should you run into "linear" vs "nonlinear" RGB, here's part of an old note to myself on this. Repeat, in practice you won't see much difference.


### RGB -> ^gamma -> Y -> L*

In color science, the common RGB values, as in html rgb( 10%, 20%, 30% ), are called "nonlinear" or Gamma corrected. "Linear" values are defined as

Rlin = R^gamma,  Glin = G^gamma,  Blin = B^gamma

where gamma is 2.2 for many PCs. The usual R G B are sometimes written as R' G' B' (R' = Rlin ^ (1/gamma)) (purists tongue-click) but here I'll drop the '.

Brightness on a CRT display is proportional to RGBlin = RGB ^ gamma, so 50% gray on a CRT is quite dark: .5 ^ 2.2 = 22% of maximum brightness. (LCD displays are more complex; furthermore, some graphics cards compensate for gamma.)

To get the measure of lightness called L* from RGB, first divide R G B by 255, and compute

Y = .2126 * R^gamma + .7152 * G^gamma + .0722 * B^gamma

This is Y in XYZ color space; it is a measure of color "luminance". (The real formulas are not exactly x^gamma, but close; stick with x^gamma for a first pass.)

Finally,

L* = 116 * Y ^ 1/3 - 16

"... aspires to perceptual uniformity [and] closely matches human perception of lightness." -- Wikipedia Lab color space

Jambeau answered 27/3, 2009 at 12:16 Comment(3)
Y = 0.2126 * R + 0.7152 * G + 0.0722 * B - Wikipedia (en.wikipedia.org/wiki/Grayscale)Toehold
Hi, can I get a equivalent panchromatic image by displaying the RGB color image as a grayscale image? Or whether can the intensity componnet of HIS format image converted from RGB represent a panchromatic image?Isolde
@emberbillow, there are many ways of mapping color to grayscale, some of which will work maybe well enough, some of the time. What program are you using, have you read its doc ? You could just try-it-and-see on several of your test images.Jambeau
R
17

I found this publication referenced in an answer to a previous similar question. It is very helpful, and the page has several sample images:

Perceptual Evaluation of Color-to-Grayscale Image Conversions by Martin Čadík, Computer Graphics Forum, Vol 27, 2008

The publication explores several other methods to generate grayscale images with different outcomes:

  • CIE Y
  • Color2Gray
  • Decolorize
  • Smith08
  • Rasche05
  • Bala04
  • Neumann07

Interestingly, it concludes that there is no universally best conversion method, as each performed better or worse than others depending on input.

Radom answered 26/3, 2009 at 21:54 Comment(0)
N
10

Heres some code in c to convert rgb to grayscale. The real weighting used for rgb to grayscale conversion is 0.3R+0.6G+0.11B. these weights arent absolutely critical so you can play with them. I have made them 0.25R+ 0.5G+0.25B. It produces a slightly darker image.

NOTE: The following code assumes xRGB 32bit pixel format

unsigned int *pntrBWImage=(unsigned int*)..data pointer..;  //assumes 4*width*height bytes with 32 bits i.e. 4 bytes per pixel
unsigned int fourBytes;
        unsigned char r,g,b;
        for (int index=0;index<width*height;index++)
        {
            fourBytes=pntrBWImage[index];//caches 4 bytes at a time
            r=(fourBytes>>16);
            g=(fourBytes>>8);
            b=fourBytes;

            I_Out[index] = (r >>2)+ (g>>1) + (b>>2); //This runs in 0.00065s on my pc and produces slightly darker results
            //I_Out[index]=((unsigned int)(r+g+b))/3;     //This runs in 0.0011s on my pc and produces a pure average
        }
Neel answered 30/1, 2011 at 0:18 Comment(4)
0.3 0.6 0.11 don't add to 1. Wikipedia seems to suggest 0.30 0.59 0.11.Tomasz
True, but the only result of them not adding to 1 will be a very slight change in intensity. The proposed method of 0.25,0.5,0.25 does add to 1 but it wouldnt matter if it didnt. It is an optimization so giving up a tiny bit of accuracy is a reasonable tradeoff.Neel
@Neel Neither set of coefficients are correct. .3,.6,.11 is the old NTSC standard, not sRGB/Rec709 (which is what the web and most computers use). And your 0.25,0.5,0.25 is not a reasonable tradeoff — B is only 7% of luminance, you're wrong by 347%. The coefficients for sRGB/r709 (after linearization): Rlin * 0.2126 + Glin * 0.7152 + Blin * 0.0722 = Y These spectral weightings are derived from human spectral perception. You can't just jam in whatever numbers you want for convenience and hope to be accurate. You need to linearize sRGB and then apply the correct coefficients.Gnosis
If you are in a situation where divide is too expensive, an approximation that uses a single multiply with shifts and adds is: 0.11111111 * ((G + (G<<1) + R) <<1) + B). This is equivalent to (2*R+6*G+B) / 9) or 0.222 R + 0.666 G + 0.111 B. Before going to production, compare to an accurate formula for various test cases.Ause
I
6

Check out the Color FAQ for information on this. These values come from the standardization of RGB values that we use in our displays. Actually, according to the Color FAQ, the values you are using are outdated, as they are the values used for the original NTSC standard and not modern monitors.

Iterate answered 26/3, 2009 at 19:51 Comment(0)
G
3

What is the source of these values?

The "source" of the coefficients posted are the NTSC specifications which can be seen in Rec601 and Characteristics of Television.

The "ultimate source" are the CIE circa 1931 experiments on human color perception. The spectral response of human vision is not uniform. Experiments led to weighting of tristimulus values based on perception. Our L, M, and S cones1 are sensitive to the light wavelengths we identify as "Red", "Green", and "Blue" (respectively), which is where the tristimulus primary colors are derived.2

The linear light3 spectral weightings for sRGB (and Rec709) are:

Rlin * 0.2126 + Glin * 0.7152 + Blin * 0.0722 = Y

These are specific to the sRGB and Rec709 colorspaces, which are intended to represent computer monitors (sRGB) or HDTV monitors (Rec709), and are detailed in the ITU documents for Rec709 and also BT.2380-2 (10/2018)

FOOTNOTES (1) Cones are the color detecting cells of the eye's retina.
(2) However, the chosen tristimulus wavelengths are NOT at the "peak" of each cone type - instead tristimulus values are chosen such that they stimulate on particular cone type substantially more than another, i.e. separation of stimulus.
(3) You need to linearize your sRGB values before applying the coefficients. I discuss this in another answer here.

Gnosis answered 20/5, 2019 at 5:15 Comment(0)
V
1

Starting a list to enumerate how different software packages do it. Here is a good CVPR paper to read as well.

FreeImage

#define LUMA_REC709(r, g, b)    (0.2126F * r + 0.7152F * g + 0.0722F * b)
#define GREY(r, g, b) (BYTE)(LUMA_REC709(r, g, b) + 0.5F)

OpenCV

nVidia Performance Primitives

Intel Performance Primitives

Matlab

nGray =  0.299F * R + 0.587F * G + 0.114F * B; 
Verduzco answered 24/3, 2021 at 15:25 Comment(0)
U
-2

These values vary from person to person, especially for people who are colorblind.

Upwards answered 18/8, 2016 at 1:4 Comment(1)
I don't understand why people downvote this post. It's true. What we use is an average, good enough but the comment is more than relevant.Kaohsiung
G
-8

is all this really necessary, human perception and CRT vs LCD will vary, but the R G B intensity does not, Why not L = (R + G + B)/3 and set the new RGB to L, L, L?

Glycogenesis answered 13/3, 2018 at 13:45 Comment(1)
Simply averaging all three R,G,B primaries treats them as perceptually equal, which is not the case for the human vision system.Toughen

© 2022 - 2024 — McMap. All rights reserved.