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


438

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


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

3
Я создал небольшую библиотеку для изменения размера изображений, она может быть полезна
Charlesthk

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

Ответы:


477

Определите максимальный размер. Затем вычислите коэффициент изменения размера, взяв 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

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

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

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

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

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

254

Этот скрипт изменит размер изображения (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('sompic.jpg') 

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

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

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

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

5
nit: нет никакой PIL.Image.ANTIALIASвозможности resize, должно быть на самом деле PIL.Image.LANCZOS, хотя они оба имеют 1ценность, см. pillow.readthedocs.io/en/3.1.x/reference/…
Фред Ву,

66

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

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

im.thumbnail(size)

с

im.thumbnail(size,Image.ANTIALIAS)

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


2
При этом вы можете только уменьшить размер изображения. Невозможно увеличить размер с Image.thumbnail.
ожог

45

Основываясь на @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)

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

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

1
Лучше конвертировать их в целое число
Black Thunder

18

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

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

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

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

16
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

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

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

13

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

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

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

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

7
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

7

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

from PIL import Image

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

4

Просто обновите этот вопрос более современной оболочкой. Эта библиотека обертывает Pillow (форк 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()

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


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

4

Я пытался изменить размеры некоторых изображений для видео слайд-шоу, и поэтому я хотел не только одно максимальное измерение, но максимальную ширину и максимальную высоту (размер видеокадра).
И всегда была возможность портретного видео ...
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)

3

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

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, который использует эту функцию для запуска изменения размера изображения.


3

Обновили ответ выше по "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')

Работай как шарм! Так что спасибо тебе!
Денис Савенко

2

Мой безобразный пример.

Функция получает файл наподобие «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:])

2

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

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)

2

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

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

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");

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

Я надеюсь, что это может быть полезным для кого-то там!


0

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

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()и где находится?
Энтони

0
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))

-1

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

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')
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.