mmj
mmj

Reputation: 5780

Pillow conversion from RGB to indexed P mode

I have an RGB image with only 25 colors,

enter image description here

and I want to convert it to P mode to make it indexed (saving space, as far as I understand), but the resulting image, though in P mode and indexed, has got 70 colors instead of 25:

>>> from PIL import Image
>>> img = Image.open(r"test_rgb2p.png")
>>> img.mode
'RGB'
>>> len(img.getcolors())
25
>>> img = img.convert(mode='P')
>>> img.mode
'P'
>>> len(img.getcolors())
70

I guess that the convert command performs some kind of unnecessary resampling, because I see no reason why the number of colors should increment. In fact with GIMP I'm able to convert this same image to indexed colors and the number of colors does not change.

Is there a way to do this RGB to P mode conversion without changes in colors?

Upvotes: 2

Views: 1131

Answers (2)

Mark Ransom
Mark Ransom

Reputation: 308111

Pillow has no idea that the number of colors in your image is restricted, so it must invent a palette that it thinks can handle everything. You'll probably find that nearly none of those 70 colors is exactly identical to the colors in your image.

In fact if you look at the documentation for Image.convert you'll see that it defaults to a web palette. If you add palette=ADAPTIVE it might give better results:

img = img.convert(mode='P', palette=Image.Palette.ADAPTIVE)

Older versions of PIL/Pillow didn't have the Palette enumeration (I used 8.1.0 for this answer) and the constant is part of Image itself:

img = img.convert(mode='P', palette=Image.ADAPTIVE)

Upvotes: 1

Dexty
Dexty

Reputation: 1472

You could try

# Quantize the image to reduce the number of colors to 25
img = img.quantize(colors=25)

# Convert the image to P mode
img = img.convert(mode='P')

# Check the number of colors in the image
print(len(img.getcolors()))  # should print 25

This worked great for me at least!

Upvotes: 0

Related Questions