Python PIL、numpy和matplotlib生成的绘图颜色与原始图像截然不同

Python PIL、numpy和matplotlib生成的绘图颜色与原始图像截然不同,python,numpy,matplotlib,python-imaging-library,Python,Numpy,Matplotlib,Python Imaging Library,我正在尝试使用以下代码绘制一些图像: import numpy as np import matplotlib.pyplot as plt from PIL import Image if __name__ == "__main__": image2 = Image.open("Test Images/i3.png") image2 = np.asarray(image2) plt.imshow(image2, cmap="gray") plt.tight_lay

我正在尝试使用以下代码绘制一些图像:

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
if __name__ == "__main__":
    image2 = Image.open("Test Images/i3.png")
    image2 = np.asarray(image2)
    plt.imshow(image2, cmap="gray")
    plt.tight_layout()
    plt.show()
但它绘制的内容与我在图像查看器中看到的不同:

为什么会这样

原始图像:


这是因为PNG有调色板,所以像素数据是调色板索引
np.asarray
采用原始像素数据,不考虑调色板。

在PIL图像对象上使用,检测图像是否有调色板,并将像素数据转换为“真实”颜色。


这是原始数据的一部分,让您了解它的外观。铭文中包括大写字母“C”的一角:

这里吸引眼球的奇怪事情是,虽然黑色是
0
(预期),但出于某种原因,白色是
1
(而不是预期的
255
),其他颜色更高,但仍然很小,最高值是
20
。这暗示这是一个调色板的事情

当您
.imshow
此数据时,按顺序将这20个点映射到所用
彩色贴图的光谱上彼此间隔相等的点

可以显示调色板数据:

$ png-parser -d amdNt.png
<...>
Filename: amdNt.png | Size: 2925

(0)
IHDR:
Data size : 13
 - Width : 225
 - Height : 225
 - Bit depth : 8
 - Color type : Code = 3 ; Depth Allow = [1, 2, 4, 8] ; Each pixel is a palette index; a PLTE chunk must appear.
 - Compression method : 0
 - Filter method : 0
 - Interlace method : 0


(1)
PLTE:
Data size : 69
b'\x00\x00\x00\xff\xff\xff\xfe\xfe\xfe\x01\x01\x01\xfd\xfd\xfd\xb4\xb4\xb4\xb2\xb2\xb2\xb6\xb6\xb6\xaf\xaf\xaf\x05\x05\x05\xfa\xfa\xfa\x10\x10\x10\xbb\xbb\xbb\x16\x16\x16\xb8\xb8\xb8\x0e\x0e\x0e\xf5\xf5\xf5\xaa\xaa\xaa\xc0\xc0\xc0\xf0\xf0\xf0\x19\x19\x19\xc4\xc4\xc4\xa6\xa6\xa6'
<...>
$png解析器-d amdNt.png
文件名:amdNt.png |大小:2925
(0)
IHDR:
数据大小:13
-宽度:225
-身高:225
-位深:8
-颜色类型:代码=3;允许深度=[1,2,4,8];每个像素是调色板索引;必须出现PLTE块。
-压缩方法:0
-筛选方法:0
-隔行扫描方法:0
(1)
PLTE:
数据大小:69
\X0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 \x10 10 10 10 10 10 10 10 10 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ \ \ \ \ \ \xx10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 9\x19\xc4\xc4\xc4\xa6\xa6\xa6'
以及调色板本身:

为了理解托盘化(或索引化)图像,请看一看

短篇故事是:

  • 如果您希望并期望使用PIL生成灰度图像,则应始终使用:

    im=Image.open(“filename”).convert(“L”)

否则,您可能会得到调色板图像

  • 如果您希望并期望获得带有PIL的RGB图像,则应使用:

    im=Image.open(“filename”).convert(“RGB”)

如果您不这样做,PIL可能会给您一个调色板图像


此外,如果使用PIL打开图像,通常最好使用PIL显示图像并使用PIL保存,否则如果使用PIL打开并使用OpenCV显示图像,则可能会遇到RGB/BGR排序问题;如果使用
matplotlib
显示图像,则可能会遇到颜色贴图问题。我不是说您无法进行互操作,我只是说,如果没有频道顺序和值范围问题,混合库会有点困难。

如果您提供原始图像,将非常有帮助。只是将其添加到问题中。