PIL 中“P”和“L”模式下的图像有什么区别?

新手上路,请多包涵
阅读 1.3k
2 个回答
  • 通常,图像是 RGB,这意味着它们有 3 个通道,一个用于红色,一个用于绿色,一个用于蓝色。这通常意味着每个像素占用 3 个字节的存储空间,一个用于红色,一个用于绿色,一个用于蓝色。

  • 如果您有 P 模式图像,则表示它已调色。这意味着调色板中有多达 256 种不同的颜色,而不是为每个像素存储 3 个字节的 R、G 和 B,而是存储 1 个字节,它是调色板的索引。这既有优点也有缺点。优点是您的图像需要内存和磁盘空间的 1/3。缺点是它只能表示 256 种独特的颜色 - 因此您可能会出现 条纹 或人工制品。

  • 如果您有 L 模式图像,这意味着它是单通道图像 - 通常被解释为灰度。 L 意味着只存储亮度。它非常紧凑,但只存储灰度,不存储颜色。


您可以通过查看以下内容来判断您的图像具有哪种 模式

 image.mode

如果您的图像被调色,它将是 P ,或者 PA 如果也使用 alpha 通道调色。如果您的图像是灰度图像,它将是 L ,或者 LA 如果灰度具有 alpha 通道。

您可以使用 convert(mode) 函数在它们之间进行转换,例如,要进入 RGB 模式,请使用:

 image.convert('RGB')


我经常使用 “正常” 这个词!为什么?因为你可以做出不正常的事情!

  • 您可以以 RGB 格式存储灰色图像。您所做的就是使红色分量等于绿色分量等于蓝色分量 (R=G=B),它会显示为灰色,但会以低效的 RGB 格式存储,占用 3 倍的空间。

  • 您可以以 P 格式存储灰色图像,只需确保所有调色板条目都具有 R=G=B。


更重要的是……如果您想要并期待 RGB 图像,您应该在打开时转换为 RGB:

 im = Image.open("image.jpg").convert('RGB')

这样一来,您将永远不会遇到 GIF 文件(总是调色板)或 PNG 文件(可以调色板并且可以是灰度或 RGB)的问题。 JPEG 图像通常不会出现问题,因为它们几乎总是 RGB。


这是一个演示的例子。从这个红蓝渐变图像开始:

在此处输入图像描述

让我们使用 IPython 在 RGB 空间中查看。首先看红色通道:

 In [21]: im = Image.open('a.png').convert('RGB')

In [22]: np.array(im.getchannel(0))
Out[22]:
array([[255, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255],
       [254, 254, 254, ..., 254, 254, 254],
       ...,
       [  1,   1,   1, ...,   1,   1,   1],
       [  0,   0,   0, ...,   0,   0,   0],
       [  0,   0,   0, ...,   0,   0,   0]], dtype=uint8)

请注意,它在顶部有 255,因为它是红色的,在底部有 0,因为那里没有红色。

现在我们来看绿色通道,因为没有绿色,到处都是0。

 In [23]: np.array(im.getchannel(1))
Out[23]:
array([[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]], dtype=uint8)

最后,让我们看看蓝色通道。在图像为纯红色的顶部为 0,在图像为纯蓝色的底部为 255。

 In [24]: np.array(im.getchannel(2))
Out[24]:
array([[  0,   0,   0, ...,   0,   0,   0],
       [  0,   0,   0, ...,   0,   0,   0],
       [  1,   1,   1, ...,   1,   1,   1],
       ...,
       [254, 254, 254, ..., 254, 254, 254],
       [255, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255]], dtype=uint8)

现在让我们在调色板模式下查看同一图像。

 # Convert to palette mode
im = Image.open('a.png').convert('P')

# Extract the palette and reshape as 256 entries of 3 RGB bytes each
In [27]: np.array(im.getpalette()).reshape(256,3)
Out[27]:
array([[  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],
       [ 51,   0,   0],
       [102,   0,   0],
       [153,   0,   0],
       [204,   0,   0],
       [255,   0,   0],      <--- entry 15 = rgb(255,0,0) = Red
       [  0,  51,   0],
       [ 51,  51,   0],
       [102,  51,   0],
       [153,  51,   0],
       [204,  51,   0],
       [255,  51,   0],
       [  0, 102,   0],
       [ 51, 102,   0],
       [102, 102,   0],
       [153, 102,   0],
       [204, 102,   0],
       [255, 102,   0],
       [  0, 153,   0],
       [ 51, 153,   0],
       [102, 153,   0],
       [153, 153,   0],
       [204, 153,   0],
       [255, 153,   0],
       [  0, 204,   0],
       [ 51, 204,   0],
       [102, 204,   0],
       [153, 204,   0],
       [204, 204,   0],
       [255, 204,   0],
       [  0, 255,   0],
       [ 51, 255,   0],
       [102, 255,   0],
       [153, 255,   0],
       [204, 255,   0],
       [255, 255,   0],
       ...
       ... up to 256 entries

现在将索引放入调色板:

 In [28]: np.array(im.getchannel(0))
Out[28]:
array([[ 15,  15,  15, ...,  15,  15,  15],
       [ 15,  15,  15, ...,  15,  15,  15],
       [ 15,  15,  15, ...,  15,  15,  15],
       ...,
       [190, 190, 190, ..., 190, 190, 190],
       [190, 190, 190, ..., 190, 190, 190],
       [190, 190, 190, ..., 190, 190, 190]], dtype=uint8)

现在您可以看到图像的顶行有调色板索引 15,如果您在前面的调色板中查找它,您会看到它是红色的。

现在让我们在 L 模式下查看相同的图像 - 记住 L 的意思是 “亮度” ,这只是在黑到白的尺度上说 “亮度” 的一种奇特方式,即灰度:

 # Open into greyscale, or L mode
In [1]: im = Image.open('a.png').convert('L')

# Dump the pixels
In [2]: np.array(im.getchannel(0))
Out[2]:
array([[76, 76, 76, ..., 76, 76, 76],
       [76, 76, 76, ..., 76, 76, 76],
       [76, 76, 76, ..., 76, 76, 76],
       ...,
       [29, 29, 29, ..., 29, 29, 29],
       [29, 29, 29, ..., 29, 29, 29],
       [29, 29, 29, ..., 29, 29, 29]], dtype=uint8)

那么,现在图像的顶行是 76,底行是 29。它们是什么?那么,将 RGB 转换为 L 的公式是:

L = R * 2991000 + G * 5871000 + B * 1141000

因此,在第一行中,R=255、G=0、B=0,因此亮度变为:

 L = 255 * 299/1000 + 0 + 0
L = 76

在底行,R=0,G=0,B=255,所以亮度变成:

 L = 0 + 0 + 255 * 114/1000
L = 29

关键词:Python、PIL、Pillow、调色板、图像处理、素数。

原文由 Mark Setchell 发布,翻译遵循 CC BY-SA 4.0 许可协议

“L”模式映射到黑色和白色像素(以及介于两者之间)。 “P”模式贴图带有调色板。您可以将图像转换为其中一种模式。

 from PIL import Image

im = Image.open("im.jpg")
im_l = im.convert('L')
im_p = im.convert('P')

im.show()
im_l.show()
im_p.show()

在此处输入图像描述

原文由 cemsazara 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题