Как я могу преобразовать изображение 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.
Код
Спектакль
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)))
- Выход
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))
- сравнение
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'))
- импорт
import skimage.color import skimage.io import random import time from PIL import Image import numpy as np import scipy.ndimage import IPython.display
- Версии
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()
непосредственно для преобразования.