python python-imaging-library

python - ¿Cuál es la diferencia entre las imágenes en modo ''P'' y ''L'' en PIL?



python-imaging-library (3)

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

  1. ¿Cuáles son las diferencias entre ellos?
  2. ¿Podemos convertir de uno a otro?
  3. ¿Cuáles son los ejemplos de imagen para ambos modos?

El modo "L" representa la escala de grises aquí ... Por lo tanto, puede contener cualquiera de 256 tonos de gris (incluye blanco y negro como gris).

El modo "P" puede contener 256 colores diferentes como rojo, azul, verde, etc.

Conversión entre sí, si quiere decir que las imágenes se convierten de escala de grises a color o viceversa ... Sí, es posible ...

Ejemplos: la imagen en blanco y negro de 8 bits (técnicamente la imagen en escala de grises) es "L" y cualquier imagen de color de 8 bits es el modo "P".


El modo "L" se asigna a píxeles blancos y negros (y entre ellos). El modo "P" se mapea con una paleta de colores. Puedes convertir la imagen a uno de estos modos.

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


  • Normalmente, las imágenes son RGB, lo que significa que tienen 3 canales, uno para el rojo, uno para el verde y otro para el azul. Eso normalmente significa que cada píxel toma 3 bytes de almacenamiento, uno para el rojo, uno para el verde y otro para el azul.

  • Si tienes una imagen en modo P, eso significa que está paletizada. Eso significa que hay una paleta con hasta 256 colores diferentes en ella, y en lugar de almacenar 3 bytes para R, G y B para cada píxel, almacena 1 byte, que es el índice en la paleta. Esto confiere ventajas y desventajas. La ventaja es que su imagen requiere 1/3 del espacio en la memoria y en el disco. La desventaja es que solo puede representar 256 colores únicos, por lo que puede obtener bandas o artefactos.

  • Si tiene una imagen en modo L, eso significa que es una imagen de un solo canal, normalmente interpretada en escala de grises. La L significa que solo se almacena la luminancia. Es muy compacto, pero solo almacena una escala de grises, no color.

Convierte entre ellos usando la función de convert(mode) , por ejemplo, para ir al modo RGB, use:

image.convert(''RGB'')

¡Usé la palabra "normalmente" bastante! ¿Por qué? ¡Porque puedes hacer cosas anormales!

  • Puede almacenar una imagen de aspecto gris en un formato RGB. Todo lo que hace es hacer que el componente rojo sea igual al componente verde igual al componente azul (R = G = B) y aparecerá en gris, pero se almacenará en un formato RGB ineficiente que ocupa 3 veces el espacio que podría necesitar.

  • Puede almacenar una imagen de aspecto gris en un formato P, solo asegúrese de que todas las entradas de la paleta tengan la R = G = B.

Aquí está el kicker ... si desea y espera una imagen RGB, debe convertir a RGB al abrir:

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

de esa manera, nunca tendrá problemas con los archivos GIF (que siempre están paletizados) ni con los archivos PNG, que se pueden paletizar y pueden ser en escala de grises o RGB. Normalmente no tendrás problemas con las imágenes JPEG porque de todas formas son casi siempre RGB.

Aquí hay un ejemplo para demostrar. Comience con esta imagen de degradado rojo-azul:

IPython para mirar en el espacio RGB. Primero, mira el canal rojo:

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)

Observe que tiene 255 en la parte superior porque es rojo y 0 en la parte inferior porque no hay rojo allí.

Ahora veamos el canal verde, es 0 en todas partes porque no hay verde.

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)

Y por último, echemos un vistazo al canal azul. Es 0 en la parte superior donde la imagen es rojo puro y 255 en la parte inferior donde la imagen es azul puro.

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)

Ahora veamos la misma imagen en el modo de paleta.

# 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

Ahora mete los índices en la paleta:

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)

Ahora puede ver que la fila superior de la imagen tiene un índice de paleta 15, que si lo mira en la paleta anterior, verá Rojo.

Ahora veamos la misma imagen en modo L: recuerde que L significa "luminancia", que es solo una forma elegante de decir "brillo" en una escala de negro a blanco, es decir, en escala de grises:

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

Entonces, ahora la fila superior de la imagen es 76 y la fila inferior es 29. ¿Qué son esos? Bueno, la fórmula para convertir RGB a L es:

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

Entonces, en la fila superior, R = 255, G = 0, B = 0, entonces la luminancia se ha convertido en:

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

Y en la fila inferior, R = 0, G = 0, B = 255, por lo que la luminancia se ha convertido en:

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