PIL jpeg如何保留像素颜色

7 投票
3 回答
5009 浏览
提问于 2025-04-17 19:31

我在做一些关于JPEG格式的实验,文档上说“100会完全禁用JPEG的量化阶段。”

不过,我在保存图片时还是发现了一些像素值的变化。以下是我的代码:

import Image
red = [20,30,40,50,60,70];
img = Image.new("RGB", [1, len(red)], (255,255,255))
pix = img.load()

for x in range(0,len(red)):
    pix[0,x] = (red[x],255,255)

img.save('test.jpg',quality=100)

img = Image.open('test.jpg')
pix = img.load()

for x in range(0,len(red)):
    print pix[0,x][0],

我得到了意想不到的输出:22 25 42 45 62 65。我该怎么做才能保持像素值不变呢?值得注意的是,我也尝试过用PHP的imagejpeg,当质量设置为100时,它给出的值是正确的。

我可以使用png格式来保持像素值,但我想知道背后的原因,以及是否有其他选项可以避免这种情况。

3 个回答

3

我想我找到了保持当前颜色子采样和其他质量细节的方法:

from PIL import Image, JpegImagePlugin as JIP

img = Image.open(filename)
img.save(
    filename + '2.jpg',                 # copy
    format='JPEG',
    exif=img.info['exif'],              # keep EXIF info
    optimize=True,
    qtables=img.quantization,           # keep quality
    subsampling=JIP.get_sampling(img),  # keep color res
)

根据这个网站 https://www.exiv2.org/tags.html,我发现JPEG文件中的EXIF信息里并没有保存YCbCrSubSampling这个标签:

在JPEG压缩数据中,使用的是JPEG标记,而不是这个标签。

这可能就是为什么在一个看起来不太显眼的地方还有另一个函数可以获取它。

(我相信我是在这里找到的: https://newbedev.com/determining-jpg-quality-in-python-pil

4

JPEG格式总是有损失的风险,具体可以参考这个链接:当质量设置为100时,JPEG是无损的吗?

如果你在做科学实验,最好使用其他格式。即使你不得不先用JPEG(这似乎不太可能),也应该立即转换成无损格式,以便进行分析和修改。

如果你真的想用Python尝试无损JPEG,可以试试jpegtran,这是来自独立JPEG小组的无损JPEG图像转换软件,但正如@Mark所说,这个工具的效果可能有限。

顺便提一下,量化在有损和无损压缩中都会用到,所以我猜:

...100完全禁用了JPEG的量化阶段。[1]

这意味着图像根本没有被压缩。

4

JPEG格式的图片处理过程有很多步骤,其中一些步骤会导致信息的损失。比如你用一张只有红色的图片来测试,就可能发现了一个大问题——下采样或色度子采样。这个过程会丢掉一半的颜色信息,因为我们的眼睛对亮度变化更敏感,而对颜色变化的敏感度较低。

有些JPEG编码器可以设置为关闭这种子采样,比如PIL和Pillow,你可以通过设置subsampling=0来实现。不过,即使这样也不能得到完全无损的文件,因为还有其他步骤也会导致信息的损失。

撰写回答