Python的PIL缩放图片时是否会保持宽高比?

50

PIL会将图像缩放为我给定的确切尺寸吗?还是说如果我使用Image.ANTIALIAS参数,它会尝试保持长宽比?

PIL会根据给定的参数进行图像缩放,如果只提供一个参数,则会调整图像的大小,但不考虑长宽比例。如果提供两个参数,则可以通过设置Image.ANTIALIAS参数来保持长宽比例。

1
抱歉,我编辑了我的问题,因为它太不清楚了。 - frederix
10个回答

77

使用缩略图方法,它将保持纵横比:

image = Image.open(source_path)
image.thumbnail((500,500), Image.ANTIALIAS)
image.save(dest_path, "JPEG")

7
从2.7.0版本开始,所有的调整大小方法都是抗锯齿(ANTIALIAS),而特定的抗锯齿滤镜的新名称为LANCZOS。(尽管现在仍保留antialias以保证向后兼容性) - hbrannan
13
请注意,缩略图方法在其他方面并不等同-它不会将图像放大到比原来更大,并且它作用于图像对象而不返回任何内容。 - kloddant
3
请注意,此函数会直接修改 Image 对象。如果您还需要使用完整分辨率的图像,请按照文档的说明将此方法应用于原始图像的 copy() 副本。 - Salvatore

24

链接中的答案使用了 - im.thumbnail,这一般建议使用吗?还是只有在处理缩略图时才用? - baxx

21

自Pillow 8.3以来,有以下方法可将图像按比例缩放以适合给定的框。

image = ImageOps.contain(image, (2048,2048))

6
根据意图,ImageOps.fit(image, size)也可能会有帮助。 - talljosh
@talljosh 这就是我在寻找的,麻烦您把这个作为答案发布一下! - Nikhil VJ
1
这个“contain”和“thumbnail”有什么不同? - Loonb
我认为contain允许扩展较小的图像。 - fabien-michel
PIL使用什么来填充/补齐? - merhoo

9
不,它不会。但你可以尝试以下操作:
im = PIL.Image.open("email.jpg"))
width, height = im.size
im = im.resize((width//2, height//2))

这里高度和宽度被相同的数值除开,保持了相同的比例。


3
你需要重新赋值im才能修改它的大小。使用im.resize并不会直接修改原始图像。im = im.resize((width//2, height//2)) - York Yang

7

好的,这需要几行代码才能得到你想要的结果。

首先找到比例,然后确定你想要的图像的一个维度(高度或宽度)。在我的情况下,我想要高度为100像素,让宽度相应调整,并最终使用该比例来找到新的高度或新的宽度。

所以首先找到图像的尺寸:

width, height = logo_img.size
ratio = width / height
      

然后,固定其中一个维度:

new_height = 100

接着计算该高度下的新宽度:

new_width = int(ratio * new_height)
            
logo_img = logo_img.resize((new_width, new_height))

当我尝试您的解决方案时,出现了错误。我收到了“_tkinter.TclError:图像“<PIL.Image.Image image mode=RGB size =20x20 at 0x7FB6A9494EF0>”不存在”的消息。有什么想法吗? - Robin
@Robin,你能否提供更多相关信息吗?比如说你是如何加载这张图片的,文件扩展名或路径是否正确? - Shreyas Vedpathak
@ Shreyas。谢谢你。我不想保存文件。我希望它加载到画布上。画布占据了显示器的一部分,因此我不能让图像超出框架的边界。当我保存文件时,您的解决方案有效,但如果我想在画布中使用调整大小的文件,则无效。是否有可能使用我们的代码将调整大小的图像重定向到画布? - Robin

7
是的,thumbnail()方法是在这里所需要的... 这个话题中没有提到的一件事情是 'size' 必须是一个列表或元组。所以,要调整大小为最大 500 像素的尺寸,您可以调用: image.thumbnail((500,500), Image.ANTIALIAS)
此外,请参考以下主题: 如何使用PIL调整图像大小并保持其宽高比?

6

这取决于您的需求,如果您希望可以设置固定的高度和宽度,或者如果您希望使用 aspect-ratio 进行调整大小。

对于按照纵横比调整大小,您可以尝试以下代码:

将新图像的宽度和高度均减半:

from PIL import Image
im = Image.open("image.jpg")
resized_im = im.resize((round(im.size[0]*0.5), round(im.size[1]*0.5)))
        
#Save the cropped image
resized_im.save('resizedimage.jpg')

使用固定宽度和比例动态高度进行调整:

from PIL import Image
new_width = 300
im = Image.open("img/7.jpeg")
concat = int(new_width/float(im.size[0]))
size = int((float(im.size[1])*float(concat)))
resized_im = im.resize((new_width,size), Image.ANTIALIAS)
#Save the cropped image
resized_im.save('resizedimage.jpg')

你能否基于新高度(new_height)而不是新宽度(new_width)来完成这个任务? - Robin

5

最近版本的Pillow库在PIL.ImageOps模块中提供了一些有用的方法。

根据您想要达到的具体效果,您可能需要寻找以下其中之一:

  • ImageOps.fit(image, size [, …]) (文档) – 调整图像大小并保持其宽高比,然后将其裁剪以适合给定的大小。

  • ImageOps.contain(image, size [, …]) (文档) – 调整图像大小并保持其宽高比,使其适合于给定的大小内。


谢谢分享。ImageOps.fit不就是Image.thumbnail吗? - Crashalot
1
@Crashalot,Image.thumbnailImageOps.contain类似。一个主要的区别是Image.thumbnail会直接在原图上进行编辑,而ImageOps.contain则会创建一个新的图像。此外,Image.thumbnail的文档中指出生成的缩略图大小不会超过给定的尺寸。但实际上我不知道它是否会比指定的尺寸更小。 - talljosh

1

一个完整的示例:

import PIL.Image


class ImageUtils(object):
    @classmethod
    def resize_image(cls, image: PIL.Image.Image, width=None, height=None) -> PIL.Image.Image:
        if height is None and width is not None:
            height = image.height * width // image.width
        elif width is None and height is not None:
            width = image.width * height // image.height
        elif height is None and width is None:
            raise RuntimeError("At lease one of width and height must be present")
        return image.resize((width, height))


def main():
    ImageUtils.resize_image(PIL.Image.open("old.png"), width=100).save("new.png")


if __name__ == '__main__':
    main()


-1
我认为以下是最简单的方法:
Img1 = img.resize((img.size),PIL.Image.ANTIALIAS)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接