I have three (241, 241) numpy arrays which I would like to treat as the Red, Green and Blue components of an image.
I have tried this:
import numpy as np
from PIL import Image
arr = np.zeros((len(x), len(z), 3))
arr[:,:,0] = red_arr
arr[:,:,1] = green_arr
arr[:,:,2] = blue_arr
img = Image.fromarray(arr, 'RGB')
img.show()
But the resulting image just looks like noise:
Can anyone tell me what I am doing wrong please?
As an example, my red_arr is an array of floats that looks like this:
In your comment you specify that the red_arr
, etc. are arrays of the range -4000 to 4000.
But if we take a look at the specifications of the Image.from_array
modes, then we see that it expects a matrix of three bytes (values from zero to 255).
This is however not per se a problem: we can perform:
def rescale(arr):
arr_min = arr.min()
arr_max = arr.max()
return (arr - arr_min) / (arr_max - arr_min)
red_arr_b = 255.0 * rescale(red_arr)
green_arr_b = 255.0 * rescale(green_arr)
blue_arr_b = 255.0 * rescale(blue_arr)
arr[:,:,0] = red_arr_b
arr[:,:,1] = green_arr_b
arr[:,:,2] = blue_arr_b
img = Image.fromarray(arr.astype(int), 'RGB')
So first we rescale to a range 0 to 255, and then we feed that array to the PIL.
It is also possible that we want to scale red, green and blue the same way. In that case we can use:
def rescale(arr):
arr_min = arr.min()
arr_max = arr.max()
return (arr - arr_min) / (arr_max - arr_min)
arr[:,:,0] = red_arr
arr[:,:,1] = green_arr
arr[:,:,2] = blue_arr
arr = 255.0 * rescale(arr)
img = Image.fromarray(arr.astype(int), 'RGB')
Your np array should have data type as uint8:
arr = np.zeros((len(x), len(z), 3),dtype='uint8')
Essentially, PIL calls tobytes function on each strides of your arr and if they are of type int, extra bytes will be generated.
Here are the result of following piece of code with different data type.
import numpy as np
from PIL import Image
size=241
arr = np.zeros((size,size,3))
arr[:,:,0] = [[255]*size]*size
arr[:,:,1] = [[255]*size]*size
arr[:,:,2] = [[0]*size]*size
img = Image.fromarray(arr.astype(int), 'RGB')
import numpy as np
from PIL import Image
size=241
arr = np.zeros((size,size,3))
arr[:,:,0] = [[255]*size]*size
arr[:,:,1] = [[255]*size]*size
arr[:,:,2] = [[0]*size]*size
img = Image.fromarray(arr.astype('uint8'), 'RGB')
As suggested by others, if your original input are not in range (0,255), you will need to rescale them as well.