Обрезка изображения в Django вызывает значительное увеличение памяти - PullRequest
2 голосов
/ 28 февраля 2012

Недавно я столкнулся с проблемой с моим проектом Django и использованием памяти в WebFaction.

Вот два процесса, выполняющиеся в памяти для этого проекта на веб-фракции:

30396  4-20:20:00 13486 
30404  4-20:20:00 13487 

После запуска представления один из процессов существенно увеличится:

69720  4-20:20:22 13486 
30404  4-20:20:22 13487 

Как вы можете видеть, первый процесс более чем удвоился в использовании памяти! Поскольку эта функция будет использоваться часто, мне нужно выяснить, что происходит. Я полагаю, что я сузил его до следующего вида (это трехэтапный процесс загрузки изображения, добавления деталей, обрезки эскиза).

Вот вид ниже. Он получает объект фотографии, загружает изображение из файла, получает координаты прямоугольника, которые отправил пользователь, а затем создает изображение размером 200 200. Это вновь созданное изображение записывается обратно на диск с .thumbnail в имени файла, и объект фото сохраняется.

@login_required
def upload3(request, photo_pk):
    photo = get_object_or_404(Photo, pk=photo_pk, user=request.user)
    if request.method == "POST":
        form = upload3Form(request.POST)
        if form.is_valid():
            im = Image.open(photo.image.path)
            try:
                box =(form.cleaned_data['x1'],form.cleaned_data['y1'],form.cleaned_data['x2'],form.cleaned_data['y2'])
            except:
                box = ('0','0','1000','1000')
            cropped = im.crop(box)
            cropped.thumbnail((200,200),Image.ANTIALIAS)
            result = os.path.splitext(photo.image.path)
            cropped.save(result[0] + '.thumbnail' + result[1])
            photo.status = 3
            photo.save()

Буду очень признателен за любые идеи о том, что я могу делать неправильно.

Update 1: все изображения, используемые для тестирования, имеют формат JPEG, имеют размеры около 3600 x 2700 и около 2 МБ на изображение.

Ответы [ 2 ]

2 голосов
/ 06 марта 2012

2M для сжатого изображения JPEG, но без сжатия, 3600 x 2700 truecolor будет около 38M (9 720 000 пикселей при 4B на пиксель), что близко к увеличению используемой памяти.

ЭтоЭто известная проблема с PIL, я могу создать пиксельную бомбу, отправив вам черное изображение размером 40000x40000 пикселей в виде png.Всегда проверяйте разрешение перед загрузкой (или защищайте код с помощью блока обработки / исключения OutOfMemory).Посмотрите, позволяет ли использование атрибута im.tile для обработки фрагмента изображения по фрагменту уменьшить объем занимаемой памяти.

Может быть стоит проверить:

Некоторые альтернативы, которые, как говорят, лучше обрабатывают память при работе с большими изображениями:

  • GDAL (Библиотека абстракции геопространственных данных)
  • OIIO (OpenImageIO)
  • Махотас (NumPy)

[обновление]

Знаете ли вы, есть ли способ в PIL освободить объекты из памяти?Потому что в теории это было бы лучше для этого представления, так как мне нужно, чтобы оно работало так, как оно работает, но просто обрабатывало изображение лучше.

  • Чтобы избежать скачков памяти, вы можете обнаружить огромные изображенияи попробуйте обработать их порциями, используя im.tile вместо im.crop (к сожалению, работа на более низком уровне).
  • Вы можете удалить промежуточные объекты изображения как можно скорее, чтобы получить более короткие шипы (используямодуль gc позволяет принудительно очистить сборщик мусора).
0 голосов
/ 15 марта 2012

После долгих копаний и тупиков, я попробовал что-то, что нигде не предлагалось, и это сработало.

На каждом объекте, который содержал объект изображения, используемый в PIL, я должен был удалить объект, как только закончилЭто.Так, например:

im = Image.open(photo.image.path)
try:
    box  =(form.cleaned_data['x1'],form.cleaned_data['y1'],form.cleaned_data['x2'],form.cleaned_data['y2'])
except:
    box = ('0','0','1000','1000')
cropped = im.crop(box)
newimage = cropped.resize((form.cleaned_data['dw'],form.cleaned_data['dh']),Image.ANTIALIAS)
del im
del cropped 

Итак, как только я закончу с объектом, я вызываю del для этого элемента.Кажется, это решило проблему.У меня больше нет памяти, и я не могу быть счастливее.

...