#python-3.x #image #memory-management #python-imaging-library
#python-3.x #изображение #управление памятью #python-imaging-library
Вопрос:
Я работаю над проектом, в котором мне нужно открыть несколько файлов изображений, а затем добавить фильтр, изменить размер изображения и затем сохранить.
Мой код выглядит так.
edited_images = [] # list where edited image object will be saved
def add_filter():
img_dir = "C:/Users/Images"
for image in os.listdir(img_dir):
image = Image.open(image)
image = image.filter(BLUR)
edited_images.append(image)
image.close()
def change_size():
...
Здесь я Image
каждый раз закрываю объект для управления памятью. В противном случае он пересечет 5 ГБ оперативной памяти для 500 изображений и так далее.
Теперь я хочу открыть эти Image
объекты, сохраненные в edited_images
, чтобы сохранить их. Как я могу этого добиться?
for image in edited_images:
print(image)
Я получаю эти результаты для приведенного выше кода:
<PIL.Image.Image image mode=RGB size=1024x1024 at 0x2343078A250>
<PIL.Image.Image image mode=RGB size=1024x1024 at 0x2343078A220>
<PIL.Image.Image image mode=RGB size=1024x1024 at 0x2343078AFD0>
Когда я запускаю это:
for image in edited_images:
image = Image.open(image)
image.save("C:UsersEdited_Images")
Для приведенного выше кода я получаю следующие результаты:
File "c:UsersImagesImage Processor.py", line 512, in <module>
apply_edits(image_folder, selected_images, finalized_edit_selection)
File "c:UsersImagesImage Processor.py", line 409, in apply_edits
image = Image.open(image)
File "C:Program FilesPython38libsite-packagesPILImage.py", line 2913, in open
prefix = fp.read(16)
AttributeError: 'Image' object has no attribute 'read'
Мне нужно использовать эти Image
объекты, сохраненные в edited_images
списке, для сохранения изображений.
Ответ №1:
Из документации по PIL.Image.close
:
Эта операция уничтожит ядро изображения и освободит его память. Данные изображения впоследствии будут непригодны для использования.
Итак, прежде всего, любые изменения в ваших изображениях будут потеряны, если они не были сохранены перед закрытием!
Заголовок Image
объекта сохраняется, поэтому вы получаете действительный вывод для print(image)
. Сравните этот код:
from PIL import Image
image = Image.open('path/to/your/image.png')
print(image, 'n')
print(image.getdata(), 'n')
image.close()
print(image, 'n')
print(image.getdata(), 'n')
Соответствующий вывод может быть:
<PIL.PngImagePlugin.PngImageFile image mode=RGB size=400x400 at 0x19C1F291BE0>
<ImagingCore object at 0x0000019C1F797370>
<PIL.PngImagePlugin.PngImageFile image mode=RGB size=400x400 at 0x19C1F291BE0>
Traceback (most recent call last):
File "...", line 9, in <module>
print(image.getdata(), 'n')
File "...libsite-packagesPILImage.py", line 1282, in getdata
self.load()
File "...libsite-packagesPILImageFile.py", line 160, in load
pixel = Image.Image.load(self)
File "...libsite-packagesPILImage.py", line 849, in load
return self.im.pixel_access(self.readonly)
File "...libsite-packagesPIL_util.py", line 19, in __getattr__
raise self.ex
ValueError: Operation on closed image
Ваша фактическая ошибка вызвана попыткой передать какой Image
-либо объект Image.open
, что просто невозможно, Image
закрыт рассматриваемый объект или нет.
Главный вопрос: почему бы вам просто не открывать, фильтровать, изменять размер и сохранять каждое изображение одно за другим в одном цикле? Например, вот так:
img_dir = "C:/Users/Images"
for filename in os.listdir(img_dir):
image = Image.open(filename)
image = image.filter(BLUR)
image = image.resize(...)
image.save(filename)
image.close()
Или, если вы действительно хотите, чтобы все процессы были разными, просто сохраните в конце вашей add_filter
функции. Затем вам потребуется повторно открыть все файлы в вашей change_size
функции. Итак, по коду что-то вроде этого:
def add_filter():
img_dir = "C:/Users/Images"
for filename in os.listdir(img_dir):
image = Image.open(filename)
image = image.filter(BLUR)
image.save(filename)
image.close()
def change_size():
img_dir = "C:/Users/Images"
for filename in os.listdir(img_dir):
image = Image.open(filename)
image = image.resize(...)
image.save(filename)
image.close()
Как вы видите, ваш список больше не нужен edited_images
(больше).