#### [SOLVED] How can I convert an RGB image into grayscale in Python?

I'm trying to use `matplotlib` to read in an RGB image and convert it to grayscale.

In matlab I use this:

``````img = rgb2gray(imread('image.png'));
``````

In the matplotlib tutorial they don't cover it. They just read in the image

``````import matplotlib.image as mpimg
``````

and then they slice the array, but that's not the same thing as converting RGB to grayscale from what I understand.

``````lum_img = img[:,:,0]
``````

I find it hard to believe that numpy or matplotlib doesn't have a built-in function to convert from rgb to gray. Isn't this a common operation in image processing?

I wrote a very simple function that works with the image imported using `imread` in 5 minutes. It's horribly inefficient, but that's why I was hoping for a professional implementation built-in.

Sebastian has improved my function, but I'm still hoping to find the built-in one.

matlab's (NTSC/PAL) implementation:

``````import numpy as np

def rgb2gray(rgb):

r, g, b = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2]
gray = 0.2989 * r + 0.5870 * g + 0.1140 * b

return gray
`````` #### @dtk 2016-08-19 23:35:17

If you're using NumPy/SciPy already you may as well use:

`scipy.ndimage.imread(file_name, mode='L')` #### @Cecil Curry 2017-11-16 07:39:43

Both `scipy.ndimage.imread()` and `scipy.misc.imread()` are formally deprecated in SciPy 1.0.0 and will be permanently removed in SciPy 1.2.0. While SciPy's documentation recommends `imageio.imread()` as a suitable replacement, this function's API is bare bones to the point of absurdity. It provides no support for grayscale conversion and thus remains unsuitable for many applications – including ours. `</sigh>` #### @0x90 2018-08-07 01:30:42

@CecilCurry, how do you convert a colored image in gray scale using imageio? #### @yangjie 2015-06-30 10:39:19

You can also use scikit-image, which provides some functions to convert an image in `ndarray`, like `rgb2gray`.

``````from skimage import color
from skimage import io

``````

Notes: The weights used in this conversion are calibrated for contemporary CRT phosphors: Y = 0.2125 R + 0.7154 G + 0.0721 B

Alternatively, you can read image in grayscale by:

``````from skimage import io
`````` #### @Sam 2015-12-01 20:24:56

is it normal that I'm getting 0<values<1 ? Am I supposed to multiply them by 255 to get the real gray scale? #### @Sam 2015-12-01 20:56:04

knowing that my aim is to use GLCM features (greycoprops) #### @Halogen 2019-03-30 20:06:37

Note for io.imread: "as_grey" has been deprecated in favor of "as_gray". Same usage, just Americanized spelling. :) #### @Mert Beşiktepe 2019-11-14 21:31:31

I believe this is the most useful answer to question at hand, output of this is also compatible with matplotlib and numpy. I am using the color object but my image is sort of reddish now and not gray (black and white). I need to use `cmap` as `gray' then only the image is shown as gray in `pyplot.imshow()` ? Any thoughts ? Where am I wrong? #### @unutbu 2012-08-30 16:48:29

How about doing it with Pillow:

``````from PIL import Image
img = Image.open('image.png').convert('LA')
img.save('greyscale.png')
``````

Using matplotlib and the formula

``````Y' = 0.2989 R + 0.5870 G + 0.1140 B
``````

you could do:

``````import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

def rgb2gray(rgb):
return np.dot(rgb[...,:3], [0.2989, 0.5870, 0.1140])

gray = rgb2gray(img)
plt.imshow(gray, cmap=plt.get_cmap('gray'), vmin=0, vmax=1)
plt.show()
`````` #### @Silas Ray 2012-08-30 16:53:37

If he has to use `matplotlib` for some other reason, he should be able to use the builtin `colorsys.rgb_to_yiq()` to transform plus a slice to get just the luma channel. #### @waspinator 2012-08-31 01:32:30

why `.convert('LA')`? why not `.convert('gray')`? Seems needlessly cryptic. The PIL documentation doesn't mention anything about 'LA' for the convert function. #### @waspinator 2012-08-31 02:17:44

Any reason why you chose to use rollaxis instead of an array slice? Is it supposed to be faster? Slices seem to be more readable. I'm still surprised that rgb2gray hasn't been implemented in the library yet. I guess this is the best I can hope for, for now. Thanks. #### @unutbu 2012-08-31 12:21:51

Although array slices like `r = rgb[...,0]` might be more readable (and the code may even be a bit faster), writing it out for `r`, `g` and `b` is a bit repetitive, and would not generalize well to more variables. I think either way has its advantages. #### @jsky 2015-05-26 06:50:58

using PIL: `cannot write mode LA as JPEG`, I needed to use L mode not LA #### @Dan Nguyen 2016-03-17 20:31:01

@jsky wish your comment was up higher! #### @dtk 2016-08-04 14:12:43

To get the exact same results as with Matlab's version (which differs marginally from the ITU-R 601-2 luma transform, I specified an adjusted matix: `img.convert('L', (0.2989, 0.5870, 0.1140, 0))`. #### @nviens 2017-10-23 22:05:27

This `img = Image.open('image.png').convert('LA')` needs to be `img = Image.open('image.png').convert('L')` #### @BluePython 2017-11-08 06:44:15

What is LA? Specifically what is L with alpha? #### @unutbu 2017-11-08 12:31:51

@BluePython: `LA` mode has luminosity (brightness) and alpha. If you use `LA` mode, then `greyscale.png` will be an RGBA image with the alpha channel of `image.png` preserved. If you use `L` mode, then `greyscale.png` will be an RGB image (with no alpha). #### @Mark Amery 2018-02-20 22:55:03

In case it matters for anyone's use-case, note that `LA` is an 8-bit mode and so `.convert('LA')` will reduce your color depth to 8-bit if it was originally higher. #### @Trenton 2019-01-12 00:57:11 #### @Apostolos 2019-03-18 08:06:40

I have seen this RGB arrangement (0.299R, 0.587B, 0.114G) in a couple of documentations, yet whatever RGB values I use in `np.dot(rgb[...,:3], [0.299, 0.587, 0.114])`, .e.g. 0.9, 0.9, 0.9 ... even 0.0, 0.1., 0.0 (There must be at least a non zero value) the result is always the same! Not for you? Any idea why? #### @unutbu 2019-03-18 11:57:48

@Apostolos: Thanks for pointing out this bug. The results are different, but depending on your image, not as different as they should be. `imshow` "normalizes" scalar data by default. Thus multiplying by `[0.0, 0.1, 0.0]` was equivalent to multiplying by `[0, 1, 0]` after normalization. To prevent `imshow` from doing this rescaling, use `vmin=0, vmax=1`. I've made this change above too. #### @Apostolos 2019-03-19 17:55:24

@unutbu, this is a great solution. Now we can talk! Note however, that -- with me at least -- it works only with `matplotlib.image` and with PNG files. It doesn't work with `imageio` and JPEG files. But who cares? :) #### @Manakin 2019-10-13 18:17:43

Cheers, was doing an online form and they only accepted 600 dpi grayscale, `L` worked for me as a `jpg` #### @M.Innat 2018-07-28 11:44:21

Using this formula

``````Y' = 0.299 R + 0.587 G + 0.114 B
``````

We can do

``````import imageio
import numpy as np
import matplotlib.pyplot as plt

gray = lambda rgb : np.dot(rgb[... , :3] , [0.299 , 0.587, 0.114])
gray = gray(pic)
plt.imshow(gray, cmap = plt.get_cmap(name = 'gray'))
``````

However, the GIMP converting color to grayscale image software has three algorithms to do the task. #### @naren 2018-02-03 07:19:19

Use img.Convert(), supports “L”, “RGB” and “CMYK.” mode

``````import numpy as np
from PIL import Image

img = Image.open("IMG/center_2018_02_03_00_34_32_784.jpg")
img.convert('L')

print np.array(img)
``````

Output:

``````[[135 123 134 ...,  30   3  14]
[137 130 137 ...,   9  20  13]
[170 177 183 ...,  14  10 250]
...,
[112  99  91 ...,  90  88  80]
[ 95 103 111 ..., 102  85 103]
[112  96  86 ..., 182 148 114]]
`````` #### @Allan Ruin 2019-03-04 05:28:16

should the 5th line be `img = img.convert('L')` ? #### @am.mansour 2017-11-19 19:02:26

you could do:

``````import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

def rgb_to_gray(img):
grayImage = np.zeros(img.shape)
R = np.array(img[:, :, 0])
G = np.array(img[:, :, 1])
B = np.array(img[:, :, 2])

R = (R *.299)
G = (G *.587)
B = (B *.114)

Avg = (R+G+B)
grayImage = img

for i in range(3):
grayImage[:,:,i] = Avg

return grayImage

grayImage = rgb_to_gray(image)
plt.imshow(grayImage)
plt.show()
`````` #### @Maximilian Peters 2017-07-26 23:06:42

Three of the suggested methods were tested for speed with 1000 RGBA PNG images (224 x 256 pixels) running with Python 3.5 on Ubuntu 16.04 LTS (Xeon E5 2670 with SSD).

Average run times

`pil :` 1.037 seconds

`scipy:` 1.040 seconds

`sk :` 2.120 seconds

PIL and SciPy gave identical `numpy` arrays (ranging from 0 to 255). SkImage gives arrays from 0 to 1. In addition the colors are converted slightly different, see the example from the CUB-200 dataset.

`SkImage:` `Original:` Code

1. Performance

``````run_times = dict(sk=list(), pil=list(), scipy=list())
for t in range(100):
start_time = time.time()
for i in range(1000):
z = random.choice(filenames_png)
run_times['sk'].append(time.time() - start_time)

start_time = time.time()
for i in range(1000):
z = random.choice(filenames_png)
img = np.array(Image.open(z).convert('L'))
run_times['pil'].append(time.time() - start_time)

start_time = time.time()
for i in range(1000):
z = random.choice(filenames_png)
run_times['scipy'].append(time.time() - start_time)

for k, v in run_times.items():
print('{:5}: {:0.3f} seconds'.format(k, sum(v) / len(v)))
``````

2. Output
``````z = 'Cardinal_0007_3025810472.jpg'
IPython.display.display(PIL.Image.fromarray(img1).convert('RGB'))
img2 = np.array(Image.open(z).convert('L'))
IPython.display.display(PIL.Image.fromarray(img2))
IPython.display.display(PIL.Image.fromarray(img3))
``````
3. Comparison
``````img_diff = np.ndarray(shape=img1.shape, dtype='float32')
img_diff.fill(128)
img_diff += (img1 - img3)
img_diff -= img_diff.min()
img_diff *= (255/img_diff.max())
IPython.display.display(PIL.Image.fromarray(img_diff).convert('RGB'))
``````
4. Imports
``````import skimage.color
import skimage.io
import random
import time
from PIL import Image
import numpy as np
import scipy.ndimage
import IPython.display
``````
5. Versions
``````skimage.version
0.13.0
scipy.version
0.19.1
np.version
1.13.1
`````` #### @Cecil Curry 2017-11-16 07:47:58

SciPy's image I/O is literally PIL/Pillow. Hence, testing SciPy is effectively retesting PIL/Pillow with negligible overhead introduced by SciPy's wrapper functions. It would have been much more useful to substitute OpenCV (which does not leverage PIL/Pillow) for SciPy (which does). Nonetheless, thanks for the dedicated benchmarking! The discernable slowdown imposed by SciKit is fascinating... and horrifying. #### @Maximilian Peters 2017-11-16 07:53:57

@CecilCurry Thanks for the idea with OpenCV! I'll add it when I find some free time. #### @Cyril N. 2018-09-07 09:46:56

Upvoted! Not an answer I was looking for, but very very interesting nonetheless :) You can always read the image file as grayscale right from the beginning using `imread` from OpenCV:

``````img = cv2.imread('messi5.jpg', 0)
``````

Furthermore, in case you want to read the image as RGB, do some processing and then convert to Gray Scale you could use `cvtcolor` from OpenCV:

``````gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
`````` #### @dtk 2016-08-19 23:25:11

Ftr: The `0` flag is `cv2.CV_LOAD_IMAGE_GRAYSCALE`. #### @Martin Thoma 2016-11-10 09:05:40

I came to this question via Google, searching for a way to convert an already loaded image to grayscale.

Here is a way to do it with SciPy:

``````import scipy.misc
import scipy.ndimage

img = scipy.misc.face()

# Convert the image
R = img[:, :, 0]
G = img[:, :, 1]
B = img[:, :, 2]
img_gray = R * 299. / 1000 + G * 587. / 1000 + B * 114. / 1000

# Show the image
scipy.misc.imshow(img_gray)
`````` #### @Akavall 2017-08-04 15:25:20

Nice. I just want to note the a shorter solution would be `img_gray = numpy.average(img, weights=[0.299, 0.587, 0.114], axis=2)` #### @Martin Thoma 2017-08-04 15:31:10

@Akavall Nice to know, thank you! Do you know if your shortcut is faster? If not, I would keep mine because it is easier to understand. #### @Akavall 2017-08-04 16:35:45

I did not time it, my gut feeling is `numpy.average` is a bit faster but not practically different. Your solution is clear and has relevant information about R,G,B, so I would keep it. My comment was more of an additional option, not a replacement. #### @Cecil Curry 2017-11-16 07:51:28

Both `scipy.ndimage.imread()` and `scipy.misc.imread()` are formally deprecated in SciPy 1.0.0 and will be permanently removed in SciPy 1.2.0. You probably just want to use Pillow's builtin grayscale conversion support (ala unutbu's answer), instead. #### @Qian Han 2016-03-16 08:35:51

``````image=myCamera.getImage().crop(xx,xx,xx,xx).scale(xx,xx).greyscale()
``````

You can use `greyscale()` directly for the transformation. #### @YPCrumble 2015-12-02 15:25:32

The fastest and current way is to use Pillow, installed via `pip install Pillow`.

The code is then:

``````from PIL import Image
img = Image.open('input_file.jpg').convert('L')
img.save('output_file.jpg')
`````` #### @Matt 2016-03-12 03:24:39

note that, if you're not chaining your methods like in the example above, `convert` returns a converted copy of the image #### @Andrew Matuk 2020-05-31 21:58:24

does not work for 32 bit PNG, values will be clamped to 255 #### @Silas Ray 2012-08-30 17:11:52

The tutorial is cheating because it is starting with a greyscale image encoded in RGB, so they are just slicing a single color channel and treating it as greyscale. The basic steps you need to do are to transform from the RGB colorspace to a colorspace that encodes with something approximating the luma/chroma model, such as YUV/YIQ or HSL/HSV, then slice off the luma-like channel and use that as your greyscale image. `matplotlib` does not appear to provide a mechanism to convert to YUV/YIQ, but it does let you convert to HSV.

Try using `matplotlib.colors.rgb_to_hsv(img)` then slicing the last value (V) from the array for your grayscale. It's not quite the same as a luma value, but it means you can do it all in `matplotlib`.

Background:

Alternatively, you could use PIL or the builtin `colorsys.rgb_to_yiq()` to convert to a colorspace with a true luma value. You could also go all in and roll your own luma-only converter, though that's probably overkill.

### [SOLVED] How to get the current time in Python

• 2009-01-06 04:54:23
• user46646
• 3411906 View
• 3023 Score
• Tags:   python datetime time

### [SOLVED] How to upgrade all Python packages with pip?

• 2010-04-27 09:23:25
• thedjpetersen
• 1273521 View
• 2140 Score
• Tags:   python pip