24

When converting an image in OpenCV from color to grayscale, what conversion algorithm is used? I tried to look this up in the source code on GitHub, but I did not have any success.

The lightness method averages the most prominent and least prominent colors:

  (max(R, G, B) + min(R, G, B)) / 2.

The average method simply averages the values:

  (R + G + B) / 3.

The luminosity method is a more sophisticated version of the average method. It also averages the values, but it forms a weighted average to account for human perception. We’re more sensitive to green than other colors, so green is weighted most heavily.

    The formula for luminosity is 0.21 R + 0.72 G + 0.07 B.

Here is an example of some conversion algorithms: http://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/

Steve
  • 2,764
  • 4
  • 27
  • 32
  • 1
    Why does your luminosity formula differ from your reference in the factor for G (0.71 vs. 0.72) - is this a typo or intentional? – Wolf Nov 12 '14 at 14:17
  • Note to other readers: Wolf's comment above no longer applies. The typo has been corrected. I was confused when I first read it, assuming that it must be the source that used 0.71 as the weight for G. Since 0.21 + 0.72 + 0.07 sums to 1, that is problematic. Both the source and post use 0.72. Hopefully this comment saves you a few minutes. – Allison B Dec 10 '22 at 15:10

2 Answers2

32

The color to grayscale algorithm is stated in the cvtColor() documentation. (search for RGB2GRAY). The formula used is the same as for CCIR 601:

Y = 0.299 R + 0.587 G + 0.114 B

The luminosity formula you gave is for ITU-R Recommendation BT. 709. If you want that you can specify CV_RGB2XYZ (e.g.) in the third parameter to cvtColor() then extract the Y channel.

You can get OpenCV to to do the "lightness" method you described by doing a CV_RGB2HLS conversion then extract the L channel. I don't think that OpenCV has a conversion for the "average" method, but if you explore the documentation you will see that there are a few other possibilities.

Bull
  • 11,771
  • 9
  • 42
  • 53
1

Just wanted to point out that:

img = cv2.imread(rgbImageFileName)
b1 = img[:,:,0] # Gives **Blue**
b2 = img[:,:,1] # Gives Green
b3 = img[:,:,2] # Gives **Red**

On the other hand, loading it as a numeric array works fine:

imgArray= gdalnumeric.LoadFile(rgbImageFileName)
Red = imgArray[0, :, :].astype('float32')
Green = imgArray[1, :, :].astype('float32')
Blue = imgArray[2, :, :].astype('float32')

So just watch out for these oddities.

But when converting to Grayscale cv2.cvtColor uses the the bands correctly. I compared pixel values using Matlab's rgb2gray.

Cheers

Avishek Dutta
  • 97
  • 2
  • 11