You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用PIL.Image.open打开图片时像素数据为何被修改?以及PIL创建保存的图片读取后像素值异常问题

关于PIL(Pillow)图像操作的两个常见问题解答

问题1:为何使用PIL.Image.open打开图片时,像素数据会发生修改?

这其实大多和图像格式的特性以及Pillow的默认处理逻辑有关,常见原因有这几个:

  • 有损压缩格式的解码损耗:如果你的原图是JPEG这类有损压缩格式,保存时就已经经过了压缩量化,再次用Image.open打开解码时,输出的像素和原始未压缩数据必然会有细微差异——这是JPEG算法的固有特性,没法完全避免。
  • 颜色模式自动转换:Pillow打开某些特殊模式的图片时,会自动转成更通用的模式。比如打开索引色(P模式)的PNG,默认会转为RGB模式;打开CMYK模式的图片,也可能自动转成RGB,转换过程中像素值会被重新计算。
  • EXIF方向校正:如果图片带有EXIF方向信息,Pillow默认会自动校正图片方向,这相当于对像素做了旋转/翻转操作,自然会改变像素的位置和排列。

问题2:保存JPG后像素值全部变为1,和原数据不符?

这个问题的核心是JPEG格式的局限性加上你的像素数据特性共同导致的:

  1. JPEG的有损压缩与量化机制:JPEG是为真实照片设计的有损压缩格式,它会把图像分成8x8的像素块做量化压缩。你设置的像素值是(0,1,0)——绿色通道仅为1(几乎接近黑色),其他通道为0。这种极低的像素值在JPEG量化过程中,会被压缩算法“合并”成相近数值,甚至直接统一为1,因为算法认为这么小的差异对视觉没有影响。
  2. JPEG不支持低精度颜色深度:Pillow创建的默认RGB模式是8位通道(每个通道取值0-255),但你用的是0和1这类极小值,JPEG的压缩算法对这类极端小值的保留效果极差。如果需要精确保存像素值,应该用PNG这类无损压缩格式,而非JPG。
  3. 小尺寸图片的块填充问题:你的图片只有12个像素(比如1x12的尺寸),JPEG处理时会把它补全到8x8的最小块尺寸(64像素),补全的像素会用周边值填充,再一起压缩,这也会干扰原有像素值的准确性。

给你个修正的示例,改用PNG格式就能精确保存像素数据:

from PIL import Image

data = [(0,1,0)] * 12
img = Image.new('RGB', (12, 1))  # 明确指定12x1的RGB图片尺寸
img.putdata(data)
img.save('sample.png')  # 用PNG无损格式保存

# 重新打开验证
new_img = Image.open('sample.png')
print(list(new_img.getdata()))  # 此时会得到正确的[(0,1,0), ...]序列

内容的提问来源于stack exchange,提问作者Tom Keen

火山引擎 最新活动