Reputation: 2797
I have M vectors containing 4096 data points between 0 and 1 that represent the luminosity map of faces. This is a sample of the actual images.
Now, my purpose is to put them in a plotly visual, but to do so I need to provide a PIL object representing the image, This is my MVC
import PIL.Image as pilim
import matplotlib.cm as cm
import numpy as np
greys = cm.get_cmap('Greys')
num_images = 10
num_faces = faces.shape[0]
sample_images = np.random.choice(num_faces, num_images, replace=False)
for index in sample_images:
greyscale = np.apply_along_axis(greys, 0, faces[index]).reshape((64, 64, 4))
im = pilim.fromarray(greyscale, mode='RGBA')
im.save('test{}.png'.format(index)) greys = cm.get_cmap('Greys')
Faces is a ndarray with 698 samples. Something like the following sample
[[0.01617647 0.01617647 0.01617647 ... 0. 0. 0. ]
[0.01617647 0.01617647 0.01617647 ... 0. 0. 0. ]
[0.01617647 0.01617647 0.01617647 ... 0. 0. 0. ]]
and this is my depressing result
Upvotes: 1
Views: 3243
Reputation: 80359
PIL works with pixel data, so each of RGBA is a value from 0 to 255. A colormap default generates its RGBA values in the range 0-1. To convert them, you could multiply those by 255 and convert to 8 bit unsigned integers (uint8), like so:
greyscale = np.uint8(cmap(faces[index].reshape(64,64)) * 255)
But, matplotlib's colormaps also support a parameter to directly generate those bytes:
greyscale = cmap(faces[index].reshape(64,64), bytes=True)
You could reshape your arrays afterwards to (64,64,4), but it is easier and more readable to do the conversion before applying the colormap.
There is a choice of several sequential colormaps for this type of images. Appending an _r
to the name gives the reverse colormap (so dark and light reversed).
Here is some code to get you started:
import PIL.Image as pilim
import matplotlib.cm as cm
import numpy as np
from matplotlib import pyplot as plt
cmap = cm.get_cmap('copper_r') # 'bone_r', 'Greys', 'copper_r', 'Purple', ...
num_images = 1
faces = np.tile(np.linspace(0,1,4096), 698).reshape(698, 4096)
num_faces = faces.shape[0]
sample_images = np.random.choice(num_faces, num_images, replace=False)
print(sample_images)
for index in sample_images:
greyscale = cmap(faces[index].reshape(64,64), bytes=True)
im = pilim.fromarray(greyscale, mode='RGBA')
im.save(f'test{index}.png')
PS: There is also an imsave
function in matplotlib, which would further simplify the code:
for index in sample_images:
plt.imsave(f'test{index}.png', faces[index].reshape(64,64), cmap=cmap)
If the image would show up upside down, adding origin='lower'
to imsave
would reverse it.
Upvotes: 2
Reputation: 2797
The solution is actually pretty simple. There are two steps missing on my code:
Cast to uint8 in order to PIL to understand the array
greyscale = np.apply_along_axis(greys, 0, faces[index]).reshape((64, 64, 4))*255 greyscale = greyscale.astype(np.uint8) im = pilim.fromarray(greyscale)
Upvotes: 0