如何使用PIL调整图像大小并保持其纵横比?


437

有什么明显的方法可以实现我所缺少的吗?我只是想制作缩略图。


9
由于这个问题已经很久了,但是很有用,并且枕头是首选,对于基于枕头的教程,请看一下:pillow.readthedocs.org/en/latest/handbook/…–
Wtower

3
我创建了一个用于调整图像大小的小型库,它可以提供任何帮助:github.com/charlesthk/python-resize-image
Charlesthk

PIL的最新版本是2006年。据我所知,枕头包装是其替代品。枕头的最新版本是2020
。– David Medinets

Answers:


477

定义最大大小。然后,通过计算调整大小比例min(maxwidth/width, maxheight/height)

适当的大小是oldsize*ratio

当然,还有一个库方法可以做到这一点:method 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),并计算宽度以保持宽高比。有没有办法固定宽度而不是高度?也许我会在另一个问题中提出这个问题。
eugene

6
@Eugene:尝试类似的东西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/...
Joshmaker

8
PIL的Python 3 文档说,thumbnail仅当生成的图像小于原始图像时,该方法才有效。因此,我猜想使用resize是更好的方法。
所以S

253

该脚本将使用PIL(Python影像库)将图像(somepic.jpg)调整为300像素的宽度,并且高度与新宽度成比例。它通过确定原始宽度(img.size [0])的300个像素的百分比,然后将原始高度(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中将此脚本用作外部方法,则需要“ from PIL import Image”行,以避免名称空间与Zope的“ Image”冲突。
tomvon

这段代码为我提供了一个0字节的输出文件sompic.jpg。为什么会这样?我正在使用Python 3.x
imrek

–更新:在Python 2.7中也是如此。
imrek

我可能已经知道了。如果要保存.jpeg,请使用img.save('sompic.jpg', 'JPEG')
imrek

5
尼特:没有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,我完成了以下操作(选择您的情况):

a)调整高度我知道新的宽度,所以我需要新的高度

new_width  = 680
new_height = new_width * height / width 

b)调整宽度我知道新的高度,所以我需要新的宽度

new_height = 680
new_width  = new_height * width / height

然后:

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

6
您的变量都混在一起了。您的帖子说调整宽度,然后调整高度。在resize通话中,您同时使用new_width高度和宽度吗?
Zachafer '16

建议修复@Zachafer
Mo Beigi

1
更好地将它们转换为整数
Black Thunder

18

PIL已经可以选择裁剪图像

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

20
仅裁剪图像,不保持宽高比。
Radu

2
这不会以任何方式回答问题。
AMC

15
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

12

如果您尝试保持相同的宽高比,那么是否不按原始尺寸的某个百分比调整尺寸?

例如,原始尺寸的一半

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

像魅力一样工作!所以谢谢!
Denis Savenko

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')
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.