I would like to colorize a 16-bit depth image with a RGB colormap in matplotlib. Technically, 3 channels with 8 bit per channel should be enough to have distinct rgb values for all 2^16 possible depth values.
A standard color map 'viridis' does result in <1000 distinct values even though the original depth image had more than twice of that.
I tried creating the colormap with a larger number of samples plt.get_cmap('viridis', 2**16)
, but it is still not enough.
Some code to describe what I am trying to do:
def depth_to_rgb(path):
depth_map = Image.open(path)
pixel = np.array(depth_map)
pixel = (pixel - np.min(pixel)) / np.ptp(pixel)
cm = plt.get_cmap('viridis', 2**16)
pixel_colored = np.uint8(np.rint(cm(pixel) * 255))[:, :, :3]
return Image.fromarray(pixel_colored)
I can slightly increase the number of distinct values in the map by creating a custom cm, but it is still not enough:
cm = mlp.colors.LinearSegmentedColormap.from_list("",
["red", "green", "yellow"], N=2**16)
Is there a colormap with enough values or how could I create one? Solutions related to the Pillow Image Library are also appreciated.
EDIT
Apparently (thanks to ImportanceOfBeingErnest) the resulting colormap has indeed 2**16 values, but np.uint8(np.rint(cm(pixel) * 255))
caused some of them to fall on the same colors. I only printed the number of distinct colors in the resulting image. I guess I have to do a somehow different mapping, but the original question is answered.
Viridis has 256 colors. It is a ListedColormap
, which means when resampling it, it will still give you a maximum of the initial number of colors. So plt.get_cmap('viridis', 2**16)
will still get you the 256 initial colors.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
cmap = plt.get_cmap("viridis", 2**16)
a = cmap(np.linspace(0,1,2**16))
print(len(a))
print(len(np.unique(a, axis=0)))
prints
65536
256
But LinearSegmentedColormap.from_list
with a larger N should work.
cmap = mcolors.LinearSegmentedColormap.from_list("", ["red", "green", "yellow"], N=2**16)
a = cmap(np.linspace(0,1,2**16))
print(len(a))
print(len(np.unique(a, axis=0)))
prints
65536
65536
If you wanted a viridis colormap with 2^16 entries, you can still interpolate in between the existing 256 colors,
cmap = mcolors.LinearSegmentedColormap.from_list("", plt.cm.viridis.colors, N=2**16)
this would result in 65536 colors as above.