Есть ли способ открыть закрытый объект изображения?

#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 (больше).