web-dev-qa-db-fra.com

Quelle est la différence entre les images en mode «P» et «L» en PIL?

Selon https://pillow.readthedocs.io/en/3.1.x/handbook/concepts.html#concept-modes ,

  1. Quelle est la différence entre eux?
  2. Peut-on se convertir de l'un à l'autre?
  3. Quels sont les exemples d'images pour les deux modes?
9
bigchaipat
  • Normalement, les images sont RVB, ce qui signifie qu'elles ont 3 canaux, un pour le rouge, un pour le vert et un pour le bleu. Cela signifie normalement que chaque pixel prend 3 octets de stockage, un pour le rouge, un pour le vert et un pour le bleu.

  • Si vous avez une image en mode P, cela signifie qu'elle est palettisée. Cela signifie qu'il y a une palette contenant jusqu'à 256 couleurs différentes, et au lieu de stocker 3 octets pour R, G et B pour chaque pixel, vous stockez 1 octet qui est l'index dans la palette. Cela confère à la fois des avantages et des inconvénients. L'avantage est que votre image nécessite 1/3 de l'espace en mémoire et sur disque. L'inconvénient est qu'il ne peut représenter que 256 couleurs uniques - vous pouvez donc obtenir des bandes ou des artefacts.

  • Si vous avez une image en mode L, cela signifie qu'il s'agit d'une image à canal unique - normalement interprétée comme une échelle de gris. Le L signifie qu'il suffit de stocker la luminance. Il est très compact, mais ne stocke qu'une échelle de gris, pas une couleur.

Vous convertissez entre eux en utilisant la fonction convert(mode), par ex. pour passer en mode RVB, utilisez:

image.convert('RGB')

J'ai beaucoup utilisé le mot "normalement" ! Pourquoi? Parce que vous pouvez faire des choses anormales!

  • Vous pouvez stocker une image grise au format RVB. Tout ce que vous faites, c'est de rendre le composant rouge égal au composant vert égal au composant bleu (R = G = B) et il apparaîtra gris mais sera stocké dans un format RVB inefficace qui prend 3x l'espace dont il aurait autrement besoin.

  • Vous pouvez stocker une image grise au format P, assurez-vous simplement que toutes les entrées de la palette ont le R = G = B.


Voici le kicker ... si vous voulez et attendez une image RVB, vous devez simplement convertir en RVB à l'ouverture:

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

de cette façon, vous n'aurez jamais de problèmes avec les fichiers GIF (qui sont toujours palettisés) ni avec les fichiers PNG qui peuvent être palettisés et peuvent être en niveaux de gris ou RVB. Normalement, vous n'aurez pas de problèmes avec les images JPEG car elles sont à peu près toujours RVB de toute façon.


Voici un exemple à démontrer. Commencez avec cette image dégradé rouge-bleu:

enter image description here

Utilisons IPython pour regarder dans l'espace RVB. Tout d'abord, regardez le canal rouge:

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)

Notez qu'il a 255 en haut parce qu'il est rouge et 0 en bas car il n'y a pas de rouge là-bas.

Regardons maintenant le canal vert, c'est 0 partout car il n'y a pas de vert.

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)

Et enfin, regardons le canal bleu. Il est de 0 en haut où l'image est en rouge pur et de 255 en bas où l'image est en bleu pur.

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)

Regardons maintenant la même image en mode palette.

# 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

Maintenant, mettez les indices dans la 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)

Vous pouvez maintenant voir que la ligne supérieure de l'image a un index de palette 15, qui, si vous le recherchez dans la palette précédente, vous verrez est rouge.

Regardons maintenant la même image en mode L - rappelez-vous que L signifie "Luminance" qui est juste une façon élégante de dire "luminosité" sur une échelle de noir à blanc, c'est-à-dire en niveaux de gris:

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

Donc, maintenant, la ligne supérieure de l'image est 76 et la ligne inférieure est 29. Qu'est-ce que c'est? Eh bien, la formule pour convertir RVB en L est:

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

Donc, dans la rangée du haut, R = 255, G = 0, B = 0, donc la luminance est devenue:

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

Et sur la rangée du bas, R = 0, G = 0, B = 255, donc la luminance est devenue:

L = 0 + 0 + 255 * 114/100
L = 29
20
Mark Setchell

Le mode "L" correspond aux pixels noir et blanc (et entre les deux). Cartes en mode "P" avec une palette de couleurs. Vous pouvez convertir l'image dans l'un de ces 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

5
cemsazara

Le mode "L" représente les niveaux de gris ici .... Il peut donc contenir n'importe laquelle des 256 nuances de gris (comprend le noir et le blanc comme nuances de gris).

Le mode "P" peut contenir 256 couleurs différentes comme le rouge, le bleu, le vert etc ...

Conversion les uns des autres, si vous voulez convertir des images de niveaux de gris en couleurs ou vice versa .... Oui, c'est possible ....

Exemples: les images en noir et blanc 8 bits (image techniquement en niveaux de gris) sont en "L" et toutes les images en couleur 8 bits sont en mode "P".

3
Pavan Chandaka