You need a properly sized numpy array, meaning a HxWx3 array with integers. I tested it with the following code and input, seems to work as expected.
import os.path
import numpy as np
from PIL import Image
def pil2numpy(img: Image = None) -> np.ndarray:
"""
Convert an HxW pixels RGB Image into an HxWx3 numpy ndarray
"""
if img is None:
img = Image.open('amsterdam_190x150.jpg'))
np_array = np.asarray(img)
return np_array
def numpy2pil(np_array: np.ndarray) -> Image:
"""
Convert an HxWx3 numpy array into an RGB Image
"""
assert_msg = 'Input shall be a HxWx3 ndarray'
assert isinstance(np_array, np.ndarray), assert_msg
assert len(np_array.shape) == 3, assert_msg
assert np_array.shape[2] == 3, assert_msg
img = Image.fromarray(np_array, 'RGB')
return img
if __name__ == '__main__':
data = pil2numpy()
img = numpy2pil(data)
img.show()

I am using:
- Python 3.6.3
- numpy 1.14.2
- Pillow 4.3.0
So I tried to convert a raw RGB array to an image with this simple code:
import numpy as np
from PIL import Image
Canvas = np.array([[255, 0, 0], [0, 255, 0], [0, 0, 0], [0, 0, 0]])
img = Image.fromarray(Canvas, 'RGB')
img = img.save("canvas.png")
I have no idea how to set the size of the image as a resolution of 2x2 because this code does not create the correct resolution
The first pixel in Canvas should be red, second pixel should be green, the third and fourth pixels should be black
All I want is a 2x2 resolution image where the top-left pixel is red and the top-right pixel is green, then both bottom pixels should be black, but my code is just producing the wrong image resolution with the wrong pixel locations. What is the issue?
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.
You don't need to convert NumPy array to Mat because OpenCV cv2 module can accept NumPyarray.
The only thing you need to care for is that {0,1} is mapped to {0,255} and any value bigger than 1 in NumPy array is equal to 255. So you should divide by 255 in your code, as shown below.
img = numpy.zeros([5,5,3])
img[:,:,0] = numpy.ones([5,5])*64/255.0
img[:,:,1] = numpy.ones([5,5])*128/255.0
img[:,:,2] = numpy.ones([5,5])*192/255.0
cv2.imwrite('color_img.jpg', img)
cv2.imshow("image", img)
cv2.waitKey()
You are looking for scipy.misc.toimage:
import scipy.misc
rgb = scipy.misc.toimage(np_array)
It seems to be also in scipy 1.0, but has a deprecation warning. Instead, you can use pillow and PIL.Image.fromarray
You can use newer OpenCV python interface (if I'm not mistaken it is available since OpenCV 2.2). It natively uses numpy arrays:
import cv2
im = cv2.imread("abc.tiff")
print(type(im))
result:
<type 'numpy.ndarray'>
PIL (Python Imaging Library) and Numpy work well together.
I use the following functions.
from PIL import Image
import numpy as np
def load_image( infilename ) :
img = Image.open( infilename )
img.load()
data = np.asarray( img, dtype="int32" )
return data
def save_image( npdata, outfilename ) :
img = Image.fromarray( np.asarray( np.clip(npdata,0,255), dtype="uint8"), "L" )
img.save( outfilename )
The 'Image.fromarray' is a little ugly because I clip incoming data to [0,255], convert to bytes, then create a grayscale image. I mostly work in gray.
An RGB image would be something like:
out_img = Image.fromarray( ycc_uint8, "RGB" )
out_img.save( "ycc.tif" )
rgb = np.dstack((r,g,b)) # stacks 3 h x w arrays -> h x w x 3
To also convert floats 0 .. 1 to uint8 s,
rgb_uint8 = (np.dstack((r,g,b)) * 255.999) .astype(np.uint8) # right, Janna, not 256
I don't really understand your question but here is an example of something similar I've done recently that seems like it might help:
# r, g, and b are 512x512 float arrays with values >= 0 and < 1.
from PIL import Image
import numpy as np
rgbArray = np.zeros((512,512,3), 'uint8')
rgbArray[..., 0] = r*256
rgbArray[..., 1] = g*256
rgbArray[..., 2] = b*256
img = Image.fromarray(rgbArray)
img.save('myimg.jpeg')
The fourth layer is the transparency value for image formats that support transparency, like PNG. If you remove the 4th value it'll be a correct RGB image without transparency.
EDIT:
Example:
>>> import PIL.Image
>>> image = PIL.Image.open('../test.png')
>>> import numpy as np
>>> image = np.array(image)
>>> image.shape
(381, 538, 4)
>>> image[...,:3].shape
(381, 538, 3)
As mentioned by other answers, some images are saved with a 4th channel.
To load image with just RGB channels without using numpy at all:
from PIL import Image
image = Image.open('../test.png').convert('RGB')
Quite a busy one-liner, but here it is:
- First ensure your NumPy array,
myarray, is normalised with the max value at1.0. - Apply the colormap directly to
myarray. - Rescale to the
0-255range. - Convert to integers, using
np.uint8(). - Use
Image.fromarray().
And you're done:
from PIL import Image
from matplotlib import cm
im = Image.fromarray(np.uint8(cm.gist_earth(myarray)*255))
with plt.savefig():

with im.save():

input = numpy_image
np.uint8 -> converts to integers
convert('RGB') -> converts to RGB
Image.fromarray -> returns an image object
from PIL import Image import numpy as np PIL_image = Image.fromarray(np.uint8(numpy_image)).convert('RGB') PIL_image = Image.fromarray(numpy_image.astype('uint8'), 'RGB')




