Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

  1. What are the difference between them?
  2. Can we convert from one to another?
  3. What are the examples of image for both mode?
like image 263
bigchaipat Avatar asked Sep 13 '18 05:09

bigchaipat


People also ask

What is PIL image format?

Python Imaging Library is a free and open-source additional library for the Python programming language that adds support for opening, manipulating, and saving many different image file formats. It is available for Windows, Mac OS X and Linux. The latest version of PIL is 1.1.

What image types can PIL open?

Each of the images in the list can be single or multiframe images. This is currently supported for GIF, PDF, PNG, TIFF, and WebP. It is also supported for ICO and ICNS.

What is PIL P?

PIL is the Python Imaging Library which provides the python interpreter with image editing capabilities. The Image module provides a class with the same name which is used to represent a PIL image.

What is PIL in image processing?

Pillow is a fork of the Python Imaging Library (PIL). PIL is a library that offers several standard procedures for manipulating images. It's a powerful library but hasn't been updated since 2009 and doesn't support Python 3. Pillow builds on this, adding more features and support for Python 3.


2 Answers

  • Normally, images are RGB, which means they have 3 channels, one for red, one for green and one for blue. That normally means that each pixel takes 3 bytes of storage, one for red, one for green and one for blue.

  • If you have a P mode image, that means it is palettised. That means there is a palette with up to 256 different colours in it, and instead of storing 3 bytes for R, G and B for each pixel, you store 1 byte which is the index into the palette. This confers both advantages and disadvantages. The advantage is that your image requires 1/3 of the space in memory and on disk. The disadvantage is that it can only represent 256 unique colours - so you may get banding or artefacts.

  • If you have an L mode image, that means it is a single channel image - normally interpreted as greyscale. The L means that is just stores the Luminance. It is very compact, but only stores a greyscale, not colour.


You can tell which mode your image has by looking at:

image.mode 

If your image is palettised it will be P, or PA if palettised with an alpha channel as well. If your image is greyscale it will be L, or LA if greyscale with alpha channel.

You convert between them using the convert(mode) function, e.g. to go to RGB mode, use:

image.convert('RGB') 

I used the word "normally" quite a lot! Why? Because you can do abnormal things!

  • You can store a grey-looking image in an RGB format. All you do, is make the red component equal to the green component equal to the blue component (R=G=B) and it will appear grey but be stored in an inefficient RGB format that takes 3x the space it might otherwise need to.

  • You can store a grey-looking image in a P format, you just make sure all the palette entries have the R=G=B.


Here's the kicker... if you want and expect an RGB image, you should just convert to RGB on opening:

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

that way you will never have problems with GIF files (which are always palettised) nor with PNG files which can be palettised and can be greyscale or RGB. You will not normally get problems with JPEG images because they are pretty much always RGB anyway.


Here's an example to demonstrate. Start with this red-blue gradient image:

enter image description here

Let's use IPython to look at in RGB space. First, look at the Red channel:

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.

like image 143
Mark Setchell Avatar answered Sep 20 '22 21:09

Mark Setchell


"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

like image 33
cemsazara Avatar answered Sep 21 '22 21:09

cemsazara