Вопрос-Ответ

How can I convert an RGB image into grayscale in Python?

Как я могу преобразовать изображение RGB в оттенки серого в Python?

Я пытаюсь использовать matplotlib для чтения в изображении RGB и преобразования его в оттенки серого.

В matlab я использую это:

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

В руководстве по matplotlib они не описывают это. Они просто читают в изображении

import matplotlib.image as mpimg
img = mpimg.imread('image.png')

а затем они нарезают массив, но это не то же самое, что преобразовать RGB в оттенки серого, насколько я понимаю.

lum_img = img[:,:,0]

Мне трудно поверить, что в numpy или matplotlib нет встроенной функции для преобразования rgb в серый. Разве это не обычная операция при обработке изображений?

Я написал очень простую функцию, которая работает с изображением, импортированным с помощью imread за 5 минут. Это ужасно неэффективно, но именно поэтому я надеялся на встроенную профессиональную реализацию.

Себастьян улучшил мою функцию, но я все еще надеюсь найти встроенную.

реализация matlab (NTSC / PAL):

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
Переведено автоматически
Ответ 1

Как насчет того, чтобы сделать это с помощью Pillow:

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

Если альфа-канал (прозрачность) присутствует во входном изображении и должен быть сохранен, используйте mode LA:

img = Image.open('image.png').convert('LA')

Используя matplotlib и формулу

Y' = 0.2989 R + 0.5870 G + 0.1140 B 

вы могли бы сделать:

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])

img = mpimg.imread('image.png')
gray = rgb2gray(img)
plt.imshow(gray, cmap=plt.get_cmap('gray'), vmin=0, vmax=1)
plt.show()
Ответ 2

Вы также можете использовать scikit-image, который предоставляет некоторые функции для преобразования изображения в ndarray, например rgb2gray.

from skimage import color
from skimage import io

img = color.rgb2gray(io.imread('image.png'))

Примечания: Веса, используемые в этом преобразовании, откалиброваны для современных люминофоров CRT: Y = 0,2125 R + 0,7154 G + 0,0721 B

В качестве альтернативы, вы можете прочитать изображение в оттенках серого с помощью:

from skimage import io
img = io.imread('image.png', as_gray=True)
Ответ 3

Три предложенных метода были протестированы на скорость с 1000 изображениями RGBA PNG (224 x 256 пикселей), работающими с Python 3.5 в Ubuntu 16.04 LTS (Xeon E5 2670 с SSD).

Среднее время выполнения

pil : 1.037 секунды

scipy: 1.040 секунд

sk : 2.120 секунды

PIL и SciPy выдали идентичные numpy массивы (в диапазоне от 0 до 255). SkImage выдает массивы от 0 до 1. Кроме того, цвета преобразуются немного по-другому, смотрите Пример из набора данных CUB-200.

SkImage: Просмотр

PIL : PIL

SciPy : SciPy

Original: Original

Diff : enter image description here

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)
    img = skimage.color.rgb2gray(skimage.io.imread(z))
    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)
    img = scipy.ndimage.imread(z, mode='L')
    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. Вывод
    z = 'Cardinal_0007_3025810472.jpg'
    img1 = skimage.color.rgb2gray(skimage.io.imread(z)) * 255
    IPython.display.display(PIL.Image.fromarray(img1).convert('RGB'))
    img2 = np.array(Image.open(z).convert('L'))
    IPython.display.display(PIL.Image.fromarray(img2))
    img3 = scipy.ndimage.imread(z, mode='L')
    IPython.display.display(PIL.Image.fromarray(img3))

  3. Сравнение
    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. Импорт
    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. Версии
    skimage.version
    0.13.0
    scipy.version
    0.19.1
    np.version
    1.13.1

Ответ 4

Вы всегда можете прочитать файл изображения в оттенках серого с самого начала, используя imread из OpenCV:

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

Кроме того, если вы хотите прочитать изображение как RGB, выполните некоторую обработку, а затем преобразуйте в оттенки серого, которые вы могли бы использовать cvtcolor из OpenCV:

gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
python matplotlib