Image.open() 会扭曲灰度 PNG 图像吗?

Does Image.open() distort grayscale PNG images?

最近,我一直在尝试使用 Pillow 的 Image.open() 将一些灰度图像加载到我的 Python 程序中。但是,我一直发现图像失真,并且所有值都极化了。

这是 Mac 预览生成的图像:

而且,这是 Image.open() 函数生成的图像:

我的代码如下:

from PIL import Image, ImageOps
from pathlib import Path
import matplotlib.pyplot as plt

mod_path2 = Path("/Volumes/Sans/ROI/Images/sub-S03046_ses-E06791_run-1_bp-chest_vp-pa_dx.png")
b = Image.open(str(mod_path2))
plt.imshow(b)
plt.show()

而且,预览图的特征是:

我认为这可能与图像的颜色 space 或缺少 alpha 通道有关,因为正确加载了这两种颜色的图像。

没有 float 值,但您的 CT 扫描是 16 位无符号整数灰度图像。当使用Image.open打开这张图片时,对应的mode是用I给出的,这里是错误的,因为I是“32位有符号整数像素”,而我们宁愿有模式 I;16,它是“16 位无符号整数像素”。

b = Image.open('images/sub-S03046_ses-E06791_run-1_bp-chest_vp-pa_dx.png')
print('Pillow mode: {}'.format(b.mode))

min_val, max_val = b.getextrema()
print('Minimum value: {}, maximum value: {}'.format(min_val, max_val))

输出:

Pillow mode: I
Minimum value: 0, maximum value: 59551

现在,一般来说,plt.imshow 能够显示 Pillow Image 对象,但是在显示 I 模式 Image 对象时似乎有问题:它似乎(见下图,见图表右下角 window),假定的 32 位被解释为 RGBA 值。因此,即使在 plt.imshow 中设置 vminvmax 在这里也不起作用。

奇怪的是,当转换为模式 I;16 时,整个图像(仍然)在 32767 处被裁剪——我不明白也无法解释。所以,对应的剧情还是有问题的(见下图)

plt.imshow 获得正确输出的唯一方法似乎是将图像转换为某个 NumPy 数组,明确地将 dtype 设置为 np.uint16,然后再转换回来到模式为 I;16:

的 Pillow Image 对象
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image

b = Image.open('images/sub-S03046_ses-E06791_run-1_bp-chest_vp-pa_dx.png')
print('Pillow mode: {}'.format(b.mode))

min_val, max_val = b.getextrema()
print('Minimum value: {}, maximum value: {}'.format(min_val, max_val))

plt.figure(0, figsize=(18, 5))
plt.subplot(1, 3, 1), plt.imshow(b, vmin=min_val, vmax=max_val, cmap='gray')
plt.title('Pillow image, original mode I'), plt.colorbar()

plt.subplot(1, 3, 2), plt.imshow(b.convert('I;16'), vmin=min_val, vmax=max_val, cmap='gray')
plt.title('Pillow image, converted to mode I;16'), plt.colorbar()

b = Image.fromarray(np.asarray(b).astype(np.uint16), 'I;16')
plt.subplot(1, 3, 3), plt.imshow(b, vmin=min_val, vmax=max_val, cmap='gray')
plt.title('Pillow image after NumPy array conversion'), plt.colorbar()

plt.tight_layout(), plt.show()

输出:

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.16299-SP0
Python:        3.9.1
Matplotlib:    3.3.4
NumPy:         1.20.1
Pillow:        8.1.0
----------------------------------------