Как я могу преобразовать изображение 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

15 ответов

Решение

Как насчет того, чтобы сделать это с подушкой:

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

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

Y' = 0.299 R + 0.587 G + 0.114 B 

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

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

def rgb2gray(rgb):
    return np.dot(rgb[...,:3], [0.299, 0.587, 0.114])

img = mpimg.imread('image.png')     
gray = rgb2gray(img)    
plt.imshow(gray, cmap = plt.get_cmap('gray'))
plt.show()

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

from skimage import color
from skimage import io

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

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

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

from skimage import io
img = io.imread('image.png', as_grey=True)

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

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

pil : 1,037 секунды

scipy: 1,040 секунды

sk : 2.120 секунд

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

SkImage: SkImage

PIL : PIL

SciPy : SciPy

Original: оригинал

Diff :

Код

  1. Спектакль

    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)
    

    для k, v в run_times.items(): print('{:5}: {:0.3f} секунд'. формат (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
    

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

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

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

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

Самый быстрый и актуальный способ - использовать подушку, установленную через pip install Pillow,

Код тогда:

from PIL import Image
img = Image.open('input_file.jpg').convert('L')
img.save('output_file.jpg')

Используя эту формулу

Y' = 0.299 R + 0.587 G + 0.114 B 

Мы можем

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

pic = imageio.imread('(image)')
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'))

Однако программа GIMP, преобразующая цвета в изображения в градациях серого, имеет три алгоритма для выполнения этой задачи.

Учебник обманывает, потому что он начинается с изображения в градациях серого, закодированного в RGB, поэтому они просто нарезают один цветной канал и рассматривают его как оттенки серого. Основные шаги, которые вам нужно сделать, - это преобразование из цветового пространства RGB в цветовое пространство, которое кодируется с помощью чего-то, приближающего модель яркости / цветности, например, YUV/YIQ или HSL/HSV, затем отрезать канал, подобный яркости, и использовать его как ваше изображение в градациях серого. matplotlib не предоставляет механизм для преобразования в YUV/YIQ, но он позволяет преобразовать в HSV.

Попробуйте использовать matplotlib.colors.rgb_to_hsv(img) затем нарезать последнее значение (V) из массива для градаций серого. Это не совсем то же самое, что значение яркости, но это означает, что вы можете делать все это в matplotlib,

Фон:

Кроме того, вы можете использовать PIL или встроенный colorsys.rgb_to_yiq() преобразовать в цветовое пространство с истинным значением яркости. Вы также можете пойти ва-банк и выпустить свой собственный конвертер только для яркости, хотя это, вероятно, излишне.

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

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       

image = mpimg.imread("your_image.png")   
grayImage = rgb_to_gray(image)  
plt.imshow(grayImage)
plt.show()

Если вы уже используете NumPy/SciPy, вы также можете использовать:

scipy.ndimage.imread(file_name, mode='L')

Hth, DTK

С OpenCV все просто:

      import cv2

im = cv2.imread("flower.jpg")

# To Grayscale
im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imwrite("grayscale.jpg", im)

# To Black & White
im = cv2.threshold(im, 127, 255, cv2.THRESH_BINARY)[1]
cv2.imwrite("black-white.jpg", im)

Используйте img.Convert(), поддерживает режимы "L", "RGB" и "CMYK".

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)

Выход:

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

Я пришел к этому вопросу через Google, ища способ конвертировать уже загруженное изображение в оттенки серого.

Вот способ сделать это с помощью SciPy:

import scipy.misc
import scipy.ndimage

# Load an example image
# Use scipy.ndimage.imread(file_name, mode='L') if you have your own
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)

Когда значения в пикселе во всех трех цветовых каналах (RGB) одинаковы, этот пиксель всегда будет в формате оттенков серого.

Один из простых и интуитивно понятных методов преобразования изображения RGB в оттенки серого - это взятие среднего значения всех цветовых каналов в каждом пикселе и присвоение значения этому пикселю.

      import numpy as np
from PIL import Image

img=np.array(Image.open('sample.jpg')) #Input - Color image
gray_img=img.copy()

for clr in range(img.shape[2]):
    gray_img[:,:,clr]=img.mean(axis=2) #Take mean of all 3 color channels of each pixel and assign it back to that pixel(in copied image)

#plt.imshow(gray_img) #Result - Grayscale image

Входное изображение:

Выходное изображение:

Предполагая, что мое изображение трехканальное в исходном виде.

      my_image = cv2.imread("./5d10e5939c5101174c54bb98.png")
#greyscaling the image
image_sum = my_image.sum(axis=2)
new_image = image_sum/image_sum.max() 

new_imageэто мое одноканальное изображение в оттенках серого

      plt.figure(figsize=[12,8])
plt.imshow(new_image, cmap=plt.cm.gray)
plt.show()

[ Это без использования cv2 cv2.COLOR_BGR2GRAYпараметр или PIL .convert('L')метод ]

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

Ты можешь использовать greyscale() непосредственно для преобразования.

Другие вопросы по тегам