首页 > 解决方案 > 尽管`resample = Image.BICUBIC`,为什么PIL.Image.rotate()会导致质量下降

问题描述

根据https://stackoverflow.com/a/17822099/1639359使用resample=PIL.Image.BICUBIC应该通过轮换保持质量。这个问题是我对上述答案的评论的跟进,它对我不起作用。

我们有什么版本的 Python 和 PIL:

import sys
print(sys.version)
3.7.3 (default, Mar 27 2019, 22:11:17)
[GCC 7.3.0]
import PIL
import PIL.Image
print(PIL.__version__)
print(PIL.Image.__version__)
6.2.1
6.2.1

打开我们的测试图像,并保存它。
注意质量的损失;保存的文件比原始文件小得多:

img = PIL.Image.open('test_image.jpg')
holdexif = img.info['exif']
img.save('testsave.jpg',"jpeg",exif=holdexif)

%ls -l 'test_image.jpg'
%ls -l 'testsave.jpg'
-rwxrwxrwx 1 dino dino 1926859 Dec 24 21:28 test_image.jpg*
-rwxrwxrwx 1 dino dino 452343 Dec 27 13:16 testsave.jpg*

Per Determining JPG quality in Python (PIL)
设置quality='keep'可防止保存时质量下降:

img.save('testsave.jpg',"jpeg",exif=holdexif,quality='keep')

%ls -l 'test_image.jpg'
%ls -l 'testsave.jpg'
-rwxrwxrwx 1 dino dino 1926859 Dec 24 21:28 test_image.jpg*
-rwxrwxrwx 1 dino dino 1926911 Dec 27 13:16 testsave.jpg*

如果我们旋转图像,会发生两件事:

print(img.format)
JPEG
rotated_img = img.rotate(-90,resample=PIL.Image.BICUBIC,expand=True)
print(img.format)
print(rotated_img.format)
JPEG
None

保存旋转的文件显示质量损失:

rotated_img.format="JPEG"  # quality='keep' will raise exception if format != 'JPEG'
rotated_img.save('testsave.jpg',"jpeg",exif=holdexif,quality='keep')
%ls -l 'test_image.jpg'
%ls -l 'testsave.jpg'
-rwxrwxrwx 1 dino dino 1926859 Dec 24 21:28 test_image.jpg*
-rwxrwxrwx 1 dino dino 450997 Dec 27 13:16 testsave.jpg*

问题:

1. 如果有的话,我做错了什么?

2. 为什么img.format旋转消失?还有什么正在消失?

3.顺便说一句,有没有另一种方法来检测质量损失(我只知道保存文件并看到它要小得多)。


在@MarkRansom 的评论之后,我想为我的问题添加一些颜色:虽然我已经编码多年,但我直到上周才开始玩图像。 毫无疑问,我对图像处理的了解充其量是最少的,对事物的工作方式存在重大差距和误解。

也就是说,从编码的角度来看,我希望对象上的方法几乎只会执行该方法所建议的操作,而不会产生副作用。例如,我希望 rotate() 只旋转图像,而不是同时清除元数据。即使,为了效率起见,PIL 包的默认行为是始终删除元数据,我希望有一个选项(全局或基于每个方法),例如preserve_metadata=True

关于“判断质量的唯一好方法”是“看图像本身”,我当然可以理解这是绝对的情况。然而,在相对的基础上,最值得注意的是,在比较处理前后的“相同”图像时,在我看来,可能有一些方法可以物理测量或至少估计处理前后的质量差异。(当然,我对图像的了解还不够,无法知道最好的方法是什么;这也是我提出问题的部分原因)。在我看来(至少从我的初学者的角度来看),人们经常想做任何想要做的处理,而质量损失很少或没有损失同时。感谢您的耐心和帮助填补我的知识空白,并提供答案。

标签: python-imaging-library

解决方案


通常,任何图像旋转都会导致图像质量下降,这仅仅是因为输出需要对输入进行插值,而不是从输入到输出的 1:1 映射。对于 90 度的倍数的旋转,可以获得 1:1 映射并进行无损旋转。目前尚不清楚 PIL/Pillow 是否足够聪明地做到这一点,但它可能会。您的示例旋转了 -90 度,因此您可能会走运。

元数据正在丢失,因为rotate生成了一个新图像,它不会修改现有图像。确定哪些元数据可能与新图像相关并不容易,因此最安全的做法是不复制任何元数据。正如您所发现的,可以手动复制您认为重要的任何内容。我认为没有自动复制任何内容的选项。

正如评论中所指出的,使用文件大小来判断图像质量是一个非常糟糕的指标。较小的尺寸暗示质量较差,但不一定如此;JPEG 压缩的全部前提是在正常观看中根本看不到某些图像质量下降。视觉比较是终极测试。如果您必须进行自动比较,有一些方法可以做到这一点,但我认为没有任何一种方法成为无可争议的最佳比较方法。


推荐阅读