Как изменить размер изображения с помощью PIL и сохранить его соотношение сторон?

Есть ли очевидный способ сделать это, который мне не хватает? Я просто пытаюсь сделать миниатюры.

Поскольку этот вопрос довольно старый, но полезный, а подушка предпочтительнее, для учебника на основе подушек взгляните на это: Pillow.readthedocs.org/en/latest/handbook/…

Wtower 26.03.2015 13:27

Я создал небольшую библиотеку для изменения размера изображений, она может помочь: github.com/charlesthk/python-resize-image

Charlesthk 28.04.2015 17:49

Последний выпуск PIL был в 2006 году. Насколько я знаю, пакет подушек является заменой. Последний выпуск Pillow состоялся 2 апреля 2020 года.

David Medinets 17.04.2020 04:41
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
498
3
799 950
21
Перейти к ответу Данный вопрос помечен как решенный

Ответы 21

Ответ принят как подходящий

Определите максимальный размер. Затем вычислите коэффициент изменения размера, взяв min(maxwidth/width, maxheight/height).

Подходящий размер - oldsize*ratio.

Для этого есть, конечно, библиотечный метод: метод Image.thumbnail.
. Ниже приведен (отредактированный) пример из Документация PIL.

import os, sys
import Image

size = 128, 128

for infile in sys.argv[1:]:
    outfile = os.path.splitext(infile)[0] + ".thumbnail"
    if infile != outfile:
        try:
            im = Image.open(infile)
            im.thumbnail(size, Image.ANTIALIAS)
            im.save(outfile, "JPEG")
        except IOError:
            print "cannot create thumbnail for '%s'" % infile

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

gnud 08.12.2011 12:29

PIL устанавливает высоту нового изображения равной заданному размеру (здесь 128) и вычисляет ширину, чтобы сохранить соотношение сторон. Есть ли способ исправить ширину вместо высоты? возможно я задам это отдельным вопросом.

eugene 13.12.2012 12:22

@ Евгений: попробовать что-нибудь вроде s= img.size(); ratio = MAXWIDTH/s[0]; newimg = img.resize((s[0]*ratio, s[1]*ratio), Image.ANTIALIAS)? (это для деления с плавающей запятой :)

gnud 13.12.2012 16:23

Гарантирует ли использование вышеизложенного, что окончательное сохраненное изображение будет размером 128x128?

mt88 08.08.2015 00:26

Обратите внимание, что ANTIALIAS больше не является предпочтительным для пользователей популярной вилки Pillow от PIL. Pillow.readthedocs.org/en/3.0.x/releasenotes/…

Joshmaker 23.12.2015 18:48

Для этого не требуется ANTIALIAS начиная с версии Pillow 2.5 и выше.

Mark 26.05.2016 19:55

Python 3 документация для PIL говорит, что thumbnail работает только в том случае, если результирующее изображение меньше исходного. Из-за этого я бы предположил, что использование resize - лучший способ.

So S 29.01.2017 00:22

Решение, предоставленное @tomvon, сработало для меня лучше, потому что оно включало, как рассчитать соотношение

Jose Luis de la Rosa 02.07.2017 20:19

По умолчанию метод PIL save() имеет низкое качество, вы можете использовать image.save(file_path, quality=quality_value) для изменения качества.

codezjx 21.10.2017 11:40

Можем ли мы таким же образом обрезать изображение?

Arpit Singh 10.05.2018 10:31

@ArpitSingh для обрезки используйте метод Image.crop - Pillow.readthedocs.io/en/3.1.x/reference/…

gnud 10.05.2018 22:37

в документах говорится: In Pillow 2.5 the default filter for thumbnail() was changed from NEAREST to ANTIALIAS

pnd 28.06.2018 16:31

Если вы пытаетесь сохранить такое же соотношение сторон, разве вы не измените размер на какой-то процент от исходного размера?

Например, половина оригинального размера

half = 0.5
out = im.resize( [int(half * s) for s in im.size] )

Возможно, изображения были разных размеров, и результат изменения размера должен был быть одинакового размера.

Steen 03.03.2010 01:59

Для меня это было очень простое и элегантное решение.

JoeTheShmoe 23.09.2020 04:08

Очень сексуально. В этом примере используется понимание списка. Также можно использовать генератор (заключенный в круглые скобки): out = im.resize( (int(half * s) for s in im.size) )

howdoicode 07.11.2020 00:56

Этот скрипт изменит размер изображения (somepic.jpg) с помощью PIL (Python Imaging Library) до ширины 300 пикселей и высоты, пропорциональной новой ширине. Для этого он определяет, какой процент от исходной ширины составляет 300 пикселей (img.size [0]), а затем умножает исходную высоту (img.size [1]) на этот процент. Измените «basewidth» на любое другое число, чтобы изменить ширину ваших изображений по умолчанию.

from PIL import Image

basewidth = 300
img = Image.open('somepic.jpg')
wpercent = (basewidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((basewidth,hsize), Image.ANTIALIAS)
img.save('somepic.jpg')

Если вы используете этот скрипт в Zope как внешний метод, вам понадобится строка «from PIL import Image», чтобы избежать конфликтов пространства имен с Zope «Image».

tomvon 16.01.2009 22:20

Этот код дает мне 0-байтовый выходной файл sompic.jpg. Почему это происходит? Я использую Python 3.x

imrek 26.03.2017 16:09

- Обновление: то же самое происходит в Python 2.7.

imrek 26.03.2017 16:15

Возможно, я догадался. Если вы сохраняете .jpeg, используйте img.save('sompic.jpg', 'JPEG').

imrek 26.03.2017 16:31

nit: для PIL.Image.ANTIALIAS нет опции resize, на самом деле это должен быть PIL.Image.LANCZOS, хотя они оба имеют значение 1, см. Pillow.readthedocs.io/en/3.1.x/reference/…

Fred Wu 02.05.2017 00:57

Различия между эскизом и изменением размера?

Daniel Möller 11.08.2017 20:40

@FredWu PIL.Image.ANTIALIAS находится в PIL версии 1.1.7. Это идет с Anaconda3 v5.x

J'e 07.06.2018 15:44

протестировано и РАБОТАЕТ с python 2.7.15, а также работает с файлами PNG без необходимости редактирования

Marc Maxmeister 20.02.2019 21:19

Это повернет некоторые изображения (дополнительная информация и решение здесь stackoverflow.com/questions/4228530/…)

Ronen Ness 25.03.2020 00:07

Я также рекомендую использовать метод эскизов PIL, потому что он избавляет вас от всех проблем с соотношением сторон.

Однако есть один важный совет: замените

im.thumbnail(size)

с

im.thumbnail(size,Image.ANTIALIAS)

по умолчанию PIL использует фильтр Image.NEAREST для изменения размера, что приводит к хорошей производительности, но плохому качеству.

При этом вы можете только уменьшить размер изображения. Увеличить размер с помощью Image.thumbnail невозможно.

burny 01.10.2019 13:08

PIL уже имеет возможность обрезать изображение

img = ImageOps.fit(img, size, Image.ANTIALIAS)

Это просто обрезает изображение, оно не поддерживает соотношение сторон.

Radu 22.12.2013 20:19

Это никак не отвечает на вопрос.

AMC 27.02.2020 22:03

Мой некрасивый пример.

Функция получает файл типа: «pic [0-9a-z]. [Extension]», изменяет их размер до 120x120, перемещает раздел в центр и сохраняет в «ico [0-9a-z]. [Extension]», работает с портретом и пейзаж:

def imageResize(filepath):
    from PIL import Image
    file_dir=os.path.split(filepath)
    img = Image.open(filepath)

    if img.size[0] > img.size[1]:
        aspect = img.size[1]/120
        new_size = (img.size[0]/aspect, 120)
    else:
        aspect = img.size[0]/120
        new_size = (120, img.size[1]/aspect)
    img.resize(new_size).save(file_dir[0]+'/ico'+file_dir[1][3:])
    img = Image.open(file_dir[0]+'/ico'+file_dir[1][3:])

    if img.size[0] > img.size[1]:
        new_img = img.crop( (
            (((img.size[0])-120)/2),
            0,
            120+(((img.size[0])-120)/2),
            120
        ) )
    else:
        new_img = img.crop( (
            0,
            (((img.size[1])-120)/2),
            120,
            120+(((img.size[1])-120)/2)
        ) )

    new_img.save(file_dir[0]+'/ico'+file_dir[1][3:])

Основываясь на @tomvon, я закончил использовать следующее (выберите свой случай):

а) Изменение размера (Я знаю новую ширину, поэтому мне нужна новая высота)

new_width  = 680
new_height = new_width * height / width 

б) Изменение ширины (Я знаю новую высоту, поэтому мне нужна новая ширина)

new_height = 680
new_width  = new_height * width / height

Тогда просто:

img = img.resize((new_width, new_height), Image.ANTIALIAS)

Все ваши переменные перепутаны. В вашем сообщении говорится об изменении ширины, а затем об изменении высоты. А в вызове resize вы используете new_width как для высоты, так и для ширины?

Zachafer 20.01.2016 08:34

Предложил исправление для этого @Zachafer

Mo Beigi 09.08.2016 17:58

Лучше преобразовать их в целое число

Black Thunder 10.11.2019 22:20
from PIL import Image
from resizeimage import resizeimage

def resize_file(in_file, out_file, size):
    with open(in_file) as fd:
        image = resizeimage.resize_thumbnail(Image.open(fd), size)
    image.save(out_file)
    image.close()

resize_file('foo.tif', 'foo_small.jpg', (256, 256))

Я использую эту библиотеку:

pip install python-resize-image
from PIL import Image

img = Image.open('/your image path/image.jpg') # image extension *.png,*.jpg
new_width  = 200
new_height = 300
img = img.resize((new_width, new_height), Image.ANTIALIAS)
img.save('output image name.png') # format may what you want *.png, *jpg, *.gif

При этом соотношение сторон исходного изображения не сохраняется. Это приводит к увеличению изображения до 200x300, что приводит к сжатию или растяжению изображения.

burny 01.10.2019 13:07

Это никак не отвечает на вопрос.

AMC 27.02.2020 22:03

Просто обновите этот вопрос с помощью более современной оболочки Эта библиотека обертывает подушку (вилку PIL) https://pypi.org/project/python-resize-image/

Позволить вам сделать что-то вроде этого: -

from PIL import Image
from resizeimage import resizeimage

fd_img = open('test-image.jpeg', 'r')
img = Image.open(fd_img)
img = resizeimage.resize_width(img, 200)
img.save('test-image-width.jpeg', img.format)
fd_img.close()

Кучи больше примеров в приведенной выше ссылке.

resize_contain выглядит весьма полезным!

Anytoe 14.07.2019 22:25

Простой метод сохранения ограниченных соотношений и передачи максимальной ширины / высоты. Не самый красивый, но выполняет свою работу и его легко понять:

def resize(img_path, max_px_size, output_folder):
    with Image.open(img_path) as img:
        width_0, height_0 = img.size
        out_f_name = os.path.split(img_path)[-1]
        out_f_path = os.path.join(output_folder, out_f_name)

        if max((width_0, height_0)) <= max_px_size:
            print('writing {} to disk (no change from original)'.format(out_f_path))
            img.save(out_f_path)
            return

        if width_0 > height_0:
            wpercent = max_px_size / float(width_0)
            hsize = int(float(height_0) * float(wpercent))
            img = img.resize((max_px_size, hsize), Image.ANTIALIAS)
            print('writing {} to disk'.format(out_f_path))
            img.save(out_f_path)
            return

        if width_0 < height_0:
            hpercent = max_px_size / float(height_0)
            wsize = int(float(width_0) * float(hpercent))
            img = img.resize((max_px_size, wsize), Image.ANTIALIAS)
            print('writing {} to disk'.format(out_f_path))
            img.save(out_f_path)
            return

Вот скрипт python, который использует эту функцию для запуска пакетного изменения размера изображения.

Если вы не хотите / вам не нужно открывать изображение с помощью Pillow, используйте это:

from PIL import Image

new_img_arr = numpy.array(Image.fromarray(img_arr).resize((new_width, new_height), Image.ANTIALIAS))

Я пытался изменить размер некоторых изображений для видео слайд-шоу, и из-за этого мне нужен был не один максимальный размер, а максимальная ширина и и максимальная высота (размер видеокадра) .
И всегда была возможность портретного видео ...
Метод Image.thumbnail был многообещающим, но я не мог масштабировать его до меньшего размера.

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

from PIL import Image

def get_resized_img(img_path, video_size):
    img = Image.open(img_path)
    width, height = video_size  # these are the MAX dimensions
    video_ratio = width / height
    img_ratio = img.size[0] / img.size[1]
    if video_ratio >= 1:  # the video is wide
        if img_ratio <= video_ratio:  # image is not wide enough
            width_new = int(height * img_ratio)
            size_new = width_new, height
        else:  # image is wider than video
            height_new = int(width / img_ratio)
            size_new = width, height_new
    else:  # the video is tall
        if img_ratio >= video_ratio:  # image is not tall enough
            height_new = int(width / img_ratio)
            size_new = width, height_new
        else:  # image is taller than video
            width_new = int(height * img_ratio)
            size_new = width_new, height
    return img.resize(size_new, resample=Image.LANCZOS)

Я изменил размер изображения таким образом, и оно работает очень хорошо

from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile
import os, sys
from PIL import Image


def imageResize(image):
    outputIoStream = BytesIO()
    imageTemproaryResized = imageTemproary.resize( (1920,1080), Image.ANTIALIAS) 
    imageTemproaryResized.save(outputIoStream , format='PNG', quality='10') 
    outputIoStream.seek(0)
    uploadedImage = InMemoryUploadedFile(outputIoStream,'ImageField', "%s.jpg" % image.name.split('.')[0], 'image/jpeg', sys.getsizeof(outputIoStream), None)

    ## For upload local folder
    fs = FileSystemStorage()
    filename = fs.save(uploadedImage.name, uploadedImage)

Обновили ответ "tomvon" выше

from PIL import Image

img = Image.open(image_path)

width, height = img.size[:2]

if height > width:
    baseheight = 64
    hpercent = (baseheight/float(img.size[1]))
    wsize = int((float(img.size[0])*float(hpercent)))
    img = img.resize((wsize, baseheight), Image.ANTIALIAS)
    img.save('resized.jpg')
else:
    basewidth = 64
    wpercent = (basewidth/float(img.size[0]))
    hsize = int((float(img.size[1])*float(wpercent)))
    img = img.resize((basewidth,hsize), Image.ANTIALIAS)
    img.save('resized.jpg')

Откройте ваш файл изображения

from PIL import Image
im = Image.open("image.png")

Используйте метод PIL Image.resize (size, resample = 0), где вы заменяете (ширину, высоту) вашего изображения кортежем размера 2.

Это отобразит ваше изображение в исходном размере:

display(im.resize((int(im.size[0]),int(im.size[1])), 0) )

Это отобразит ваше изображение в 1/2 размера:

display(im.resize((int(im.size[0]/2),int(im.size[1]/2)), 0) )

Это отобразит ваше изображение в размере 1/3:

display(im.resize((int(im.size[0]/3),int(im.size[1]/3)), 0) )

Это отобразит ваше изображение в 1/4 размера:

display(im.resize((int(im.size[0]/4),int(im.size[1]/4)), 0) )

и т. д. и т. д.

Что такое display() и где он находится?

Anthony 11.05.2020 04:32

@Anthony, display() - это функция iPython, которую можно использовать в Jupyter Notebook для отображения изображений.

Qinjie 09.07.2020 05:11

Вы можете изменить размер изображения с помощью кода ниже:

From PIL import Image
img=Image.open('Filename.jpg') # paste image in python folder
print(img.size())
new_img=img.resize((400,400))
new_img.save('new_filename.jpg')

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

Вам не нужны точки с запятой (;), я оставлю их, чтобы напомнить себе о синтаксисе языков, которые я использую чаще.

from PIL import Image

img_path = "filename.png";
img = Image.open(img_path);     # puts our image to the buffer of the PIL.Image object

width, height = img.size;
asp_rat = width/height;

# Enter new width (in pixels)
new_width = 50;

# Enter new height (in pixels)
new_height = 54;

new_rat = new_width/new_height;

if (new_rat == asp_rat):
    img = img.resize((new_width, new_height), Image.ANTIALIAS); 

# adjusts the height to match the width
# NOTE: if you want to adjust the width to the height, instead -> 
# uncomment the second line (new_width) and comment the first one (new_height)
else:
    new_height = round(new_width / asp_rat);
    #new_width = round(new_height * asp_rat);
    img = img.resize((new_width, new_height), Image.ANTIALIAS);

# usage: resize((x,y), resample)
# resample filter -> PIL.Image.BILINEAR, PIL.Image.NEAREST (default), PIL.Image.BICUBIC, etc..
# https://pillow.readthedocs.io/en/3.1.x/reference/Image.html#PIL.Image.Image.resize

# Enter the name under which you would like to save the new image
img.save("outputname.png");

И это сделано. Я старался задокументировать это как можно больше, чтобы было понятно.

Надеюсь, это может быть кому-то полезно!

import cv2
from skimage import data 
import matplotlib.pyplot as plt
from skimage.util import img_as_ubyte
from skimage import io
filename='abc.png'
image=plt.imread(filename)
im=cv2.imread('abc.png')
print(im.shape)
im.resize(300,300)
print(im.shape)
plt.imshow(image)

К сожалению, это не отвечает на вопрос, который явно касается библиотеки PIL - и не сохраняет соотношение сторон !. Кроме того, вы можете дать некое описание своего подхода, чтобы объяснить свои мысли.

max 09.08.2020 08:39

Следующий скрипт создает красивые эскизы всех изображений JPEG с сохранением соотношений сторон с максимальным разрешением 128x128.

from PIL import Image
img = Image.open("D:\\Pictures\\John.jpg")
img.thumbnail((680,680))
img.save("D:\\Pictures\\John_resize.jpg")

Вы можете комбинировать Image.thumbnail PIL с sys.maxsize, если ваш предел изменения размера только для одного измерения (ширина или высота).

Например, если вы хотите изменить размер изображения так, чтобы его высота была не более 100 пикселей, сохраняя при этом соотношение сторон, вы можете сделать что-то вроде этого:

import sys
from PIL import Image

image.thumbnail([sys.maxsize, 100], Image.ANTIALIAS)

Имейте в виду, что Image.thumbnail изменит размер изображения на месте, в отличие от Image.resize, который вместо этого возвращает измененное изображение без изменения исходного.

Другие вопросы по теме