Search code examples
pythonpython-imaging-librarycolor-depth

PIL Image convert from I mode to P mode


I have this depth image:

enter image description here

that I load with PIL like:

depth_image = Image.open('stereo.png')

If I print the mode of the image it shows mode I, that is (32-bit signed integer pixels) according to the documentation.

This is correct since the image values range from 0 to 255. I'd like to colorize this depth image for better visualization so I tried to convert it to P mode with a palette like:

depth_image = depth_image.convert('P', palette=custom_palette)
depth_image.save("colorized.png")

But the result is a black and white image like this:

enter image description here

I'm sure the palette is ok, since there are 256 colors in int format all in a single array.

I've tried to convert it to RGB before saving like:

depth_image = depth_image.convert('RGB')

Also I tried adding the palette afterwards like:

depth_image = depth_image.putpalette(custom_palette)

And if I try to save it without converting it to RGB I get a:

    depth_image.save("here.png")
AttributeError: 'NoneType' object has no attribute 'save'

So far I'll try converting the image to a numpy array and then map the colors from there, but I was wondering what was I missing out regarding PIL. I was looking around the documentation but didn't find much regarding I to P conversion.


Solution

  • I think the issue is that your values are scaled to the range 0..65535 rather than 0..255.

    If you do this, you will see the values are larger than you expected:

    i = Image.open('depth.png') 
    n = np.array(i) 
    
    print(n.max(),n.mean())
    # prints 32257, 6437.173
    

    So, I quickly tried:

    n = (n/256).astype(np.uint8)
    r = Image.fromarray(n)
    r=r.convert('P') 
    r.putpalette(custom_palette)     # I grabbed this from your pastebin
    

    enter image description here