如何使用Pillow正确显示16位深度的灰度图像?
问题分析
你遇到的是PIL对16位深度灰度PNG的显示兼容性问题:
- 该图像模式为
I;16(16位无符号灰度),PIL的show()方法默认处理这类高深度图像时,未做灰度值的缩放映射,直接将16位数据按8位逻辑显示(0-255为有效范围,超出部分直接显示纯白,低于则纯黑),导致出现纯黑白异常。 - Notebook的
display函数和Aseprite重存后能正常显示,是因为前者会自动处理高深度图像的灰度映射,后者则将图像转为8位灰度后保存,避开了PIL的显示缺陷。
解决方案
以下几种方法可以解决这个问题:
方法1:手动将16位灰度映射为8位灰度
通过线性缩放把16位的0-65535范围值转换为8位的0-255范围,再显示:
from PIL import Image import numpy as np # 打开图像 img = Image.open('image.png') # 确认图像模式(应该输出 I;16 或类似) print(img.mode) # 仅针对16位灰度图处理 if img.mode.startswith('I;16'): # 转为numpy数组进行缩放 img_arr = np.array(img) # 线性映射到0-255 img_8bit = ((img_arr / 65535) * 255).astype(np.uint8) # 转回PIL图像并显示 img_8bit_pil = Image.fromarray(img_8bit, mode='L') img_8bit_pil.show() else: img.show()
方法2:用Matplotlib替代PIL的show()方法
Matplotlib能正确识别16位灰度的取值范围,直接显示原始灰度:
from PIL import Image import matplotlib.pyplot as plt img = Image.open('image.png') # 用灰度色图,并指定16位的取值范围 plt.imshow(img, cmap='gray', vmin=0, vmax=65535) # 隐藏坐标轴 plt.axis('off') plt.show()
方法3:修改PIL的转换逻辑
使用convert方法时指定转换参数,确保16位到8位的正确映射:
from PIL import Image img = Image.open('image.png') # 将16位灰度转为8位灰度,通过浮点模式中转保证精度 img_8bit = img.convert('L', mode='F') img_8bit.show()
内容的提问来源于stack exchange,提问作者Diogo Lima
相关产品推荐
相关产品推荐

