Converting from numpy arrays to a RGB image

2020-07-26 10:51发布

问题:

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:

回答1:

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')


回答2:

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.