Добрый день. В Pillow действительно уже есть метод
convert(). Можно им пользоваться, если не требуется какая-то особая формула. Дальше можно превратить в двумерный Numpy-массив.
import numpy as np
from PIL import Image
def open_grayscale(fp):
with Image.open(fp) as im:
return np.array(im.convert('L'), dtype=np.uint8)
Вообще, главное при работе с большими массивами в Python — не обрабатывать элементы по отдельности. В Numpy, если у массивов одинаковые размеры, их можно воспринимать как скаляры. В примере ниже, rgba разбирается на три массивоподобных двумерных представления (по сути,
прокси-объекты, обеспечивающие доступ к значениям оригинального массива по другим индексам; это еще называют
slicing — нарезание на ломтики). При умножении на скаляр, Numpy умножает весь массив или представление, а не один элемент. Дальше сложение происходит поэлементно.
def open_rgba(fp):
with Image.open(fp) as im:
return np.array(im.convert('RGBA'), dtype=np.float32)
rgba = open_rgba(fn)
grayscale = \
rgba[:, :, 0] * 0.299 + \
rgba[:, :, 1] * 0.587 + \
rgba[:, :, 2] * 0.114
print(rgba.shape)
print(grayscale.shape)
Image.fromarray(np.uint8(grayscale), 'L').show()
Время конвертации методом convert():
(5457, 3603)
real 0m0.271s
user 0m0.222s
sys 0m0.049s
Вторым способом:
(5457, 3603, 4)
(5457, 3603)
real 0m0.405s
user 0m0.288s
sys 0m0.116s