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
中设置 vmin
和 vmax
在这里也不起作用。
奇怪的是,当转换为模式 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
----------------------------------------
最近,我一直在尝试使用 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
中设置 vmin
和 vmax
在这里也不起作用。
奇怪的是,当转换为模式 I;16
时,整个图像(仍然)在 32767
处被裁剪——我不明白也无法解释。所以,对应的剧情还是有问题的(见下图)
从 plt.imshow
获得正确输出的唯一方法似乎是将图像转换为某个 NumPy 数组,明确地将 dtype
设置为 np.uint16
,然后再转换回来到模式为 I;16
:
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
----------------------------------------