Converting RGB to grayscale/intensity

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


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
        }

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.