JJC
JJC

Reputation: 65

How do I use Pillow's Image.convert() with a custom color palette?

I want to reduce the bit depth (color depth) of an image down to a set of custom colours in Python. Essentially to give the program a set of x colors and have it associate each pixel in a full color image with the closest color from the given list. I am having trouble with the Pillow library as evidenced below.

This code will correctly reduce the colors in image 'Z.png' down to only 4 colors, based on a palette of colors created from the image itself:

from PIL import Image

colorImage = Image.open("Z.png")
imageWithColorPalette = colorImage.convert("P", palette=Image.ADAPTIVE, colors=4)
imageWithColorPalette.save("Output.png")

from IPython.display import Image
Image('Output.png')

This code is similar except I have attempted to use my own color palette. The problem is this code returns the exact same image as the above code and seems to just go with an adaptive palette and ignore the custom one I have attempted to specify:

from PIL import Image

pall = [
    0, 0, 0,
    255, 0, 0,
    255, 255, 0,
    255, 153, 0,
]

colorImage = Image.open("Z.png")
imageWithColorPalette = colorImage.convert("P", palette=pall, colors=4)
imageWithColorPalette.save("Output.png")

from IPython.display import Image
Image('Output.png')

Based on the documentaion from here: https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.convert and here https://pillow.readthedocs.io/en/3.0.x/reference/ImagePalette.html. I assume my pall is given in an incorrect format/size or that I need to include a matrix argument in the convert method. According to the documentation the matrix argument is 'An optional conversion matrix. If given, this should be 4- or 12-tuple containing floating point values.' which I am unsure how to implement.

Whatever the problem is I'm very stuck and would appriciate some help.

Alternativley, is there a better Python library to use for this task as I'm open to suggestions.

Upvotes: 4

Views: 7746

Answers (1)

Harben
Harben

Reputation: 1856

I believe this is along the lines of what you want

from PIL import Image

if __name__ == '__main__':
    palette = [
        159, 4, 22,
        98, 190, 48,
        122, 130, 188,
        67, 153, 0,
    ]

    img = Image.open('img.jpg')
    
    p_img = Image.new('P', (16, 16))
    p_img.putpalette(palette * 64)

    conv = img.quantize(palette=p_img, dither=0)
    conv.show()

    

Upvotes: 5

Related Questions