【问题标题】:Does Image.open() distort grayscale PNG images?Image.open() 会扭曲灰度 PNG 图像吗?
【发布时间】:2021-05-14 22:04:27
【问题描述】:

最近,我一直在尝试使用 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()

而且,预​​览图的特点是:

我认为这可能与图像的色彩空间或缺少 Alpha 通道有关,因为正确加载了两者的图像。

【问题讨论】:

  • 请分享您的 "不开心" 图片 - 最好通过 Dropbox 或 Google Drive,以免 imgur 更改它。另请显示您的实际、完整的最小代码。
  • @MarkSetchell。感谢您的回复。就我个人而言,我发现我电脑上的 imgur 和图像之间几乎没有什么区别。我也更新了代码。谢谢!
  • 显然 imgur 图片不是3050 x 2539。此外,由于您正在处理 CT 数据,因此您可能有一些带有任何值的float 格式,并且由于将float 值裁剪到[0.0 ... 1.0] 范围内而得到一些损坏的输出。这就是 Mark 特意要求提供原始图片的原因。
  • @MarkSetchell 这是图片的链接:drive.google.com/drive/folders/…
  • @HansHirse 谢谢,我已经分享了真实的图像。另外,如果剪辑真的发生了,有没有办法解决它?

标签: python image matplotlib python-imaging-library


【解决方案1】:

没有float 值,但您的 CT 扫描是 16 位无符号整数灰度图像。当使用Image.open 打开此图像时,对应的mode 会以I 给出,这里是错误的,因为I 是“32 位有符号整数像素”,而我们更希望有模式@ 987654329@,即“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 对象时似乎存在问题:似乎(见下图,见下图,绘图窗口的右上角),假定的 32 位被解释为 RGBA 值。因此,即使在 plt.imshow 中设置 vminvmax 在这里也不起作用。

奇怪的是,当转换为I;16 模式时,整个图像(仍然)被剪裁为32767——我不明白也无法解释。所以,相应的情节仍然是错误的(见下图)。

plt.imshow 获得正确输出的唯一方法似乎是将图像转换为某个 NumPy 数组,将dtype 显式设置为np.uint16,然后将其转换回 Pillow Image 对象模式I;16

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
----------------------------------------

【讨论】:

  • I;16 上限的问题是否在于具有这么多位的整数的最大值是 32767?如果是这种情况,是否有像 I;32(32 位无符号整数像素)这样的模式会更好?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-25
  • 2014-08-13
  • 2016-03-18
  • 2016-01-02
  • 2017-02-12
  • 2013-01-12
相关资源
最近更新 更多