Just do
Image.fromarray(np.array(img).astype(np.uint8).transpose(1,2,0))
Answer from Maiia Bocharova on Stack OverflowSo 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?
python - Convert numpy array to rgb image - Stack Overflow
Combine 3 separate numpy arrays to an RGB image in Python - Stack Overflow
python - RGB array to PIL image - Stack Overflow
python - Convert a raw RGB array into a png image. - Stack Overflow
Note that this answer is outdated as of 2018; scipy has deprecated imread, and you should switch to imageio.imread. See this transition doc about differences between the two. The code below should work with no changes if you just import the new library in place of the old, but I haven’t tested it.
The simplest answer is to use the NumPy and SciPy wrappers around PIL. There's a great tutorial, but the basic idea is:
from scipy import misc
arr = misc.imread('lena.png') # 640x480x3 array
arr[20, 30] # 3-vector for a pixel
arr[20, 30, 1] # green value for a pixel
For a 640x480 RGB image, this will give you a 640x480x3 array of uint8.
Or you can just open the file with PIL (or, rather, Pillow; if you're still using PIL, this may not work, or may be very slow) and pass it straight to NumPy:
import numpy as np
from PIL import Image
img = Image.open('lena.png')
arr = np.array(img) # 640x480x4 array
arr[20, 30] # 4-vector, just like above
This will give you a 640x480x4 array of type uint8 (the 4th is alpha; PIL always loads PNG files as RGBA, even if they have no transparency; see img.getbands() if you're every unsure).
If you don't want to use NumPy at all, PIL's own PixelArray type is a more limited array:
arr = img.load()
arr[20, 30] # tuple of 4 ints
This gives you a 640x480 PixelAccess array of RGBA 4-tuples.
Or you can just call getpixel on the image:
img.getpixel(20, 30) # tuple of 4 ints
I have a feeling I'm not doing exactly what you wanted here, so please specify if this is totally off. You could open the image like this and get an array of pixels:
import Image
im = Image.open('Lenna.png')
pixels = list(im.getdata())
This will get you a flat list of RGB data that looks like
[(226, 137, 125), (226, 137, 125), (223, 137, 133), (223, 136, 128),
(226, 138, 120), (226, 129, 116), (228, 138, 123), (227, 134, 124),
(227, 140, 127), (225, 136, 119), (228, 135, 126), (225, 134, 121),...
Now this will be all pixels in a flat array, if you want a two dimensional array then some additional code would be needed for that. Not sure if there is a direct function for it in PIL.
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')
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.
imshow in the matplotlib library will do the job
what's critical is that your NumPy array has the correct shape:
height x width x 3
(or height x width x 4 for RGBA)
>>> import os
>>> # fetching a random png image from my home directory, which has size 258 x 384
>>> img_file = os.path.expanduser("test-1.png")
>>> from scipy import misc
>>> # read this image in as a NumPy array, using imread from scipy.misc
>>> M = misc.imread(img_file)
>>> M.shape # imread imports as RGBA, so the last dimension is the alpha channel
array([258, 384, 4])
>>> # now display the image from the raw NumPy array:
>>> from matplotlib import pyplot as PLT
>>> PLT.imshow(M)
>>> PLT.show()
Matplotlib's built in function imshow will let you do this.
import matplotlib.pyplot as plt
def displayImage(image):
plt.imshow(image)
plt.show()
Evidently imsave supports "file-like objects" of which io.BytesIO is the one I need:
buffer = BytesIO()
imsave(buffer, rgb)
encoded_png = buffer.getbuffer()
#and then my class derived from BaseHTTPRequestHandler can transmit it as the response to a GET
self.send_response(200)
self.send_header("Content-Type", "image/png")
self.end_headers()
self.wfile.write(encoded_png)
return
If you want to do a file upload (any type of picture) Send file using POST from a Python script
But if you want to send raw png data you can reread the file and encode it in base64. Your server just have to decode base64 and write the file.
import base64
from urllib.parse import urlencode
from urllib.request import Request, urlopen
array_encoded = ""
with open("/tmp/whatever.png") as f:
array_encoded = base64.encode(f)
url = 'https://URL.COM' # Set destination URL here
post_fields = {'image': array_encoded} # Set POST fields here
request = Request(url, urlencode(post_fields).encode())
responce = urlopen(request).read()
print(responce)
Code not tested!!!!!!!
I think this is solved here, remember if you want a RGB image you need 3 channels and that means a matrix with shape (NxMx3).
Convert 2d array to collored image in python
Cheers!
Edit:
This is an example of how you can stack your 2D arrays into a 3D one with the shape you need.
import numpy as np
#some random arrays i just created for test
r = np.array([3,3,3])
g = np.array([6,6,6])
b = np.array([9,9,9])
bl = np.array([12,12,12])
#create the stacked arrays
stacked = np.dstack((r,g,b,bl))
#check the shape
print(np.shape(stacked))
To make RGB images from ndarrays you have to: 1) separate each RGB channel as a different array by methods such as splitting maximum and minimum intensities into group of 3, normalize them (turning them into a range between 0-1) based on original or RGB minimums/maximums to represent pixel color intensity, then display/save them using plt.imshow/plt.imsave:
from matplotlib.colors import Normalize
from PIL import Image
import numpy as np
# example data
arr = np.array([4,3,2,1,-1,-2,-3,-4])
# producing RGB variants by slicing intensity of the data into 3 equal sections
R = np.percentile(arr,100 - 100/3)
B = np.percentile(arr,100/3)
arr_R = np.where(arr >= R, arr, 0)
arr_B = np.where(arr <= B, arr, 0)
arr_G = np.where((arr > B) & (arr < R), arr, 0)
# normalizing arr_RGB to have values between 0-255
def normRGB(a):
mynorm = Normalize(vmin=np.min(a), vmax=np.max(a))
return mynorm(a)
# #Run below if you prefer original array's minimum and maximum
# arr = normRGB(abs(arr)) # absolute values help acknowledging negative values' intensity, exclude them if you mean otherwise
# # otherwise run below if you prefer RGB channels' minimums and maximums
arr_R = normRGB(abs(arr_R)) # absolute values help acknowledging negative values' intensity, exclude them if you mean otherwise
arr_G = normRGB(abs(arr_G))
arr_B = normRGB(abs(arr_B))
# stacking RGB into one ndarray
arr_RGB = np.dstack((arr_R,arr_G,arr_B))
plt.imshow(arr_RGB)
plt.show()
print(arr_RGB)

Stacking resulted images into a higher dimension array (like an album book) is also possible by adding arr_RGB's together using the same np.dstack() function. for example:
N = 22 # if there are 22 images
album = np.zeros((N))
for n in range(N):
### Here should be written all above operation with an i index that updates new arr_RGB from dataset[i] during each iteration ###
if n == 0: # if it is the first iteration
album = np.copy(arr_RGB)
elif n > 0: # now that album has been created, it can be stacked on its previous records
album = np.dstack(album, arr_RGB)
print(np.shape(album))
Thanks to @jairoar answer upon explaining np.dstack
