PIL: Convert RGB image to a specific 8-bit palette

2020-03-12 08:08发布

Using the Python Imaging Library, I can call

img.convert("P", palette=Image.ADAPTIVE)

or

img.convert("P", palette=Image.WEB)

but is there a way to convert to an arbitrary palette?

p = []
for i in range(0, 256):
    p.append(i, 0, 0)
img.convert("P", palette=p)

where it'll map each pixel to the closest colour found in the image? Or is this supported for Image.WEB and nothing else?

2条回答
甜甜的少女心
2楼-- · 2020-03-12 08:17

While looking through the source code of convert() I saw that it references im.quantize. quantize can take a palette argument. If you provide an Image that has a palette, this function will take that palette and apply it to the image.

Example:

    src = Image.open("sourcefilewithpalette.bmp")
    new = Image.open("unconvertednew24bit.bmp")
    converted = new.quantize(palette=src)
    converted.save("converted.bmp")

The other provided answer didn't work for me (it did some really bad double palette conversion or something,) but this solution did.

查看更多
够拽才男人
3楼-- · 2020-03-12 08:33

The ImagePalette module docs's first example shows how to attach a palette to an image, but that image must already be of mode "P" or "L". One can, however, adapt the example to convert a full RGB image to a palette of your choice:

from __future__ import division
import Image

palette = []
levels = 8
stepsize = 256 // levels
for i in range(256):
    v = i // stepsize * stepsize
    palette.extend((v, v, v))

assert len(palette) == 768

original_path = 'original.jpg'
original = Image.open(original_path)
converted = Image.new('P', original.size)
converted.putpalette(palette)
converted.paste(original, (0, 0))
converted.show()
查看更多
登录 后发表回答