Вопрос-Ответ

What is the difference between images in 'P' and 'L' mode in PIL?

В чем разница между изображениями в режиме 'P' и 'L' в PIL?

Согласно https://pillow.readthedocs.io/en/3.1.x/handbook/concepts.html#concept-modes,


  1. В чем разница между ними?

  2. Можем ли мы преобразовать одно из них в другое?

  3. Каковы примеры изображений для обоих режимов?

Переведено автоматически
Ответ 1

  • Обычно изображения имеют цвет RGB, что означает, что у них есть 3 канала: один для красного, один для зеленого и один для синего. Обычно это означает, что каждый пиксель занимает 3 байта памяти, один для красного, один для зеленого и один для синего.



  • Если у вас есть изображение в режиме P, это означает, что оно палитрировано. Это означает, что в палитре может быть до 256 различных цветов, и вместо сохранения 3 байт для R, G и B для каждого пикселя вы сохраняете 1 байт, который является индексом в палитре. Это дает как преимущества, так и недостатки. Преимущество в том, что вашему изображению требуется 1/3 места в памяти и на диске. Недостатком является то, что он может представлять только 256 уникальных цветов - так что вы можете получить полосы или артефакты.



  • Если у вас есть изображение в L режиме, это означает, что это изображение с одним каналом, которое обычно интерпретируется как оттенки серого. L Означает, что это просто сохраняет яркость. Он очень компактный, но сохраняет только оттенки серого, а не цвет.




Вы можете определить, какой режим у вашего изображения, посмотрев на:

image.mode

Если ваше изображение имеет палитру, оно будет таким P, или PA если оно также имеет палитру с альфа-каналом. Если ваше изображение в оттенках серого, оно будет в L, или LA если в оттенках серого с альфа-каналом.

Вы конвертируете между ними с помощью функции 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)

Notice it has 255 at the top because it is red, and 0 at the bottom because there is no red there.

Now let's look at the Green channel, it is 0 everywhere because there is no green.

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)

And finally, let's look at the Blue channel. It is 0 at the top where the image is pure Red and 255 at the bottom where the image is pure Blue.

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)

Now let's look at the same image in palette mode.

# 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

Now get the indices into the palette:

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)

Now you can see that the top row of the image has palette index 15, which, if you look it up in the preceding palette, you will see is Red.

Now let's look at the same image in L mode - remember L means "Luminance" which is just a fancy way of saying "brightness" on a scale of black to white, i.e. greyscale :

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

So, now the top row of the image is 76 and the bottom row is 29. What are those? Well, the formula for converting RGB to L is:


L = R * 299/1000 + G * 587/1000 + B * 114/1000


So, in the top row, R=255, G=0, B=0, so the Luminance has become:

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

And on the bottom row, R=0, G=0, B=255, so the Luminance has become:

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

Keywords: Python, PIL, Pillow, palette, image processing, prime.

Ответ 2

"L" mode maps to black and white pixels (and in between). "P" mode maps with a color palette. You can convert image to one of these modes.

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

enter image description here

Ответ 3

The “L” mode represents grayscale here.... So it can hold any of 256 shades of gray (includes black and white as Gray shades).

The “P” mode can hold 256 different colors like red, blue, green, etc...

Conversion from one to another, if you mean converting images from grayscale to color or vice versa... Yes it is possible...

Examples: 8-bit black and white image (technically grayscale image) are “L” and any 8-bit color images are “P” mode.

2023-04-26 02:11 python python-imaging-library