Point not mapping properly from numpy array to PIL Image - python

I am finding a point within a numpy array and then want to save this array as an image with a box around the located point.
Below is a simplified code representation showing the issue
from PIL import Image, ImageDraw
import numpy as np
np_img = np.zeros((259,339,3))
pt = (29,118)
np_img[pt] = [255,0,0]
print(np_img[pt])
final_img = Image.fromarray(np_img, 'RGB')
#final_draw = ImageDraw.Draw(final_img)
#final_draw.rectangle([(pt[1]-3, pt[0]+3), (pt[1]+3, pt[0]-3)], outline="blue")
new_np_img = np.asarray(final_img)
print(new_np_img[pt])
new_pt = np.where(new_np_img > 0)
print(new_pt)
final_img.show()
I would expect that if I read the generated PIL image back into a numpy array that the point that I set as [255,0,0] would still be that value but it is not. What is PIL doing to my data so that I can understand how I need to condition my numpy array so that it displays the correct position of my point in the PIL image?

The reason for undesired output is because you didn't explicitly defined the datatype of the numpy array as uint8. In your code, the first array (np_img) was stored as float64 datatype. And the array obtained from PIL (final_img) was of the datatype uint8. Which caused inconsistent results.
from PIL import Image
import numpy as np
np_img = np.zeros((259,339,3), np.uint8)
pt = (29,118)
np_img[pt] = [255,0,0]
print(np_img[pt])
final_img = Image.fromarray(np_img, 'RGB')
new_np_img = np.asarray(final_img)
print(new_np_img[pt])
final_img.show()
Output:-
[255 0 0]
[255 0 0]
Output Image:-

Related

How do I resize image but maintain features in the image? Python

I have an image that looks like this:
array.resize(20,20,3)
img = Image.fromarray(array, 'RGB')
img.save('my.png',quality=90)
img.show()
It is currently a 500x500x3 NumPy array. The underlying space is a 20x20 grid of cells and I want to resize the image so that each grid cell has entries in a 20x20x3 NumPy Array corresponding to it's RGB values instead of (500/20)*(500/20)*3 entries per cell.
The code above does not seem to work unfortunately as it seems to be giving more entries per cell than I expected although I am not 100% sure.
To resize image with pillow you can use Image.resize()
from PIL import Image
import urllib.request
import numpy as np
data = urllib.request.urlopen('https://i.stack.imgur.com/7bPlZ.png')
old_img = Image.open(data)
new_img = old_img.resize((20, 20))
new_img.save('my.png',quality=90)
new_img.show()
array = np.array(new_img)
print(array)
But resizing image you can create pixels with half-tones.
Maybe you should get values directly from numpy.array. You have solid colors so you could get single pixel from every cell - because every cell has size 25x25 so it could be:
new_array = old_array[::25,::25,:]
and then you don't have to convert to image.
And if you convert this array to image then it should be sharper than create with Image.resize.
from PIL import Image
import urllib.request
import numpy as np
data = urllib.request.urlopen('https://i.stack.imgur.com/7bPlZ.png')
old_img = Image.open(data)
old_array = np.array(old_img)
new_array = array[::25,::25,:]
print(new_array)
new_img = Image.fromarray(new_array)
new_img.save('my.png',quality=90)
new_img.show()
Try this
size = 20, 20
img = Image.fromarray(array, 'RGB')
img.thumbnail(size, Image.ANTIALIAS)
img.save('my.png',quality=90)
img.show()

I am trying to convert a numpy array to PIL.Image. But it is giving black images. The numpy array is returned by pyramid_gaussian method from skimage

Here is my code
import numpy as np
from PIL import Image
from skimage.transform import pyramid_gaussian
image = Image.open('/home/sumith/Downloads/AFW/testimages/3854178896.jpg')
rows, cols, dim = np.asarray(image).shape
pyramid = tuple(pyramid_gaussian(image, downscale=2,))
count = 0
for pyr in pyramid[0:8]:
row, col, dim = (np.asarray(pyr).shape)
count += 1
#io.imsave('/home/sumith/imagepyramids/'+count.__str__()+".jpg", pyr)
print(type(pyr))
image = Image.fromarray(pyr.astype('uint8'), 'RGB')
image.save('/home/sumith/imagepyramids/'+count.__str__()+".jpg")
when I print the type(pyr) it is showing as but when I try to convert and save it from PIL image all the images in the pyramid will be black. but if i save it using io.imsave it is working fine .I need the image pyramid's image to be fed into a neural network so if i can feed it as PIL.Image then it will be very helpful.
Thanks in advance!! The black image looks like this black-image
Check the values in pyr. Maybe they are values between 0 and `, while your RGB image is expected to be with values between 0 and 255.

Converting 2D Numpy array of grayscale values to a PIL image

Say I have a 2D Numpy array of values on the range 0 to 1, which represents a grayscale image. How do I then convert this into a PIL Image object? All attempts so far have yielded extremely strange scattered pixels or black images.
for x in range(image.shape[0]):
for y in range(image.shape[1]):
image[y][x] = numpy.uint8(255 * (image[x][y] - min) / (max - min))
#Create a PIL image.
img = Image.fromarray(image, 'L')
In the code above, the numpy array image is normalized by (image[x][y] - min) / (max - min) so every value is on the range 0 to 1. Then it is multiplied by 255 and cast to an 8 bit integer. This should, in theory, process through Image.fromarray with mode L into a grayscale image - but the result is a set of scattered white pixels.
I think the answer is wrong. The Image.fromarray( ____ , 'L') function seems to only work properly with an array of integers between 0 and 255. I use the np.uint8 function for this.
You can see this demonstrated if you try to make a gradient.
import numpy as np
from PIL import Image
# gradient between 0 and 1 for 256*256
array = np.linspace(0,1,256*256)
# reshape to 2d
mat = np.reshape(array,(256,256))
# Creates PIL image
img = Image.fromarray(np.uint8(mat * 255) , 'L')
img.show()
Makes a clean gradient
vs
import numpy as np
from PIL import Image
# gradient between 0 and 1 for 256*256
array = np.linspace(0,1,256*256)
# reshape to 2d
mat = np.reshape(array,(256,256))
# Creates PIL image
img = Image.fromarray( mat , 'L')
img.show()
Has the same kind of artifacting.
If I understood you question, you want to get a grayscale image using PIL.
If this is the case, you do not need to multiply each pixels by 255.
The following worked for me
import numpy as np
from PIL import Image
# Creates a random image 100*100 pixels
mat = np.random.random((100,100))
# Creates PIL image
img = Image.fromarray(mat, 'L')
img.show()
im = Image.fromarray(np.uint8(mat), 'L')
or
im = Image.fromarray(np.uint8(mat))
Apparently it accepts type np.uint8(insert array here), also may be able to remove 'L' for conciseness.

Convert Image ( png ) To Matrix And Then To 1D Array

I have 5 pictures and i want to convert each image to 1d array and put it in a matrix as vector. I want to be able to convert each vector to image again.
img = Image.open('orig.png').convert('RGBA')
a = np.array(img)
I'm not familiar with all the features of numpy and wondered if there other tools I can use.
Thanks.
import numpy as np
from PIL import Image
img = Image.open('orig.png').convert('RGBA')
arr = np.array(img)
# record the original shape
shape = arr.shape
# make a 1-dimensional view of arr
flat_arr = arr.ravel()
# convert it to a matrix
vector = np.matrix(flat_arr)
# do something to the vector
vector[:,::10] = 128
# reform a numpy array of the original shape
arr2 = np.asarray(vector).reshape(shape)
# make a PIL image
img2 = Image.fromarray(arr2, 'RGBA')
img2.show()
import matplotlib.pyplot as plt
img = plt.imread('orig.png')
rows,cols,colors = img.shape # gives dimensions for RGB array
img_size = rows*cols*colors
img_1D_vector = img.reshape(img_size)
# you can recover the orginal image with:
img2 = img_1D_vector.reshape(rows,cols,colors)
Note that img.shape returns a tuple, and multiple assignment to rows,cols,colors as above lets us compute the number of elements needed to convert to and from a 1D vector.
You can show img and img2 to see they are the same with:
plt.imshow(img) # followed by
plt.show() # to show the first image, then
plt.imshow(img2) # followed by
plt.show() # to show you the second image.
Keep in mind in the python terminal you have to close the plt.show() window to come back to the terminal to show the next image.
For me it makes sense and only relies on matplotlib.pyplot. It also works for jpg and tif images, etc. The png I tried it on has float32 dtype and the jpg and tif I tried it on have uint8 dtype (dtype = data type); each seems to work.
I hope this is helpful.
I used to convert 2D to 1D image-array using this code:
import numpy as np
from scipy import misc
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
face = misc.imread('face1.jpg');
f=misc.face(gray=True)
[width1,height1]=[f.shape[0],f.shape[1]]
f2=f.reshape(width1*height1);
but I don't know yet how to change it back to 2D later in code, Also note that not all the imported libraries are necessary, I hope it helps

How to create a white image in Python?

Upon doing my homework, I stumbled across a problem concerning Python and image manipulation. I must say, using the Image lib is not an option. So here it is
from scipy.misc import imread,imsave
from numpy import zeros
imga = zeros([100,100,3])
h = len(imga)
w = len(imga[0])
for y in range(h):
for x in range(w):
imga[y,x] = [255,255,255]
imsave("Result.jpg",imga)
I would assume it makes my picture white, but it turns it black, and I have no idea why
It's not about the code (and I know it looks very ugly). Its just about the fact, that it is a black image.
Every color in an image is represented by one byte. So to create an image array, you should set it's dtype to uint8.
And, you don't need for-loop to set every elements to 255, you can use fill() method or slice index:
import numpy as np
img = np.zeros([100,100,3],dtype=np.uint8)
img.fill(255) # or img[:] = 255
Easy!
Check the below Code:
whiteFrame = 255 * np.ones((1000,1000,3), np.uint8)
255 is the color for filling the bytes.
1000, 1000 is the size of the image.
3 is the color channel for the image.
And unit8 is the type
Goodluck
Here's a simple way to create a white image with a python one liner.
$ python3 -c "from PIL import Image;Image.new('RGB', (1900, 1080), color = (255,255,255)).save('Img.jpg')"
This will create a white image with a width of 1900 and hight of 1080.
When creating imga, you need to set the unit type. Specifically, change the following line of code:
imga = zeros([100,100,3], dtype=np.uint8)
And, add the following to your imports:
import numpy as np
That gives a white image on my machine.
The headline is too broad and shows up at Google first. I needed a white image and used PIL and numpy. PILlow actually works well with numpy
import numpy as np
from PIL import Image
img = np.zeros([100,100,3],dtype=np.uint8)
img.fill(255) # numpy array!
im = Image.fromarray(img) #convert numpy array to image
im.save('whh.jpg')
Just regarding the headline of this question, I did need a white image as well as a pillow input. And the solutions presented here did not work for me.
Therefore here a different way to generate white images for other purposes:
from PIL import Image
img = Image.new('RGB', (200, 50), color = (255,255,255))
Size and color may be changed in the 2nd and 3rd parameter of the Image.new()-function.
And if you want to write something on this image or save it, this would be example code for this.
from PIL import ImageFont, ImageDraw
fnt = ImageFont.truetype("Pillow/Tests/fonts/FreeMono.ttf", 30)
ImageDraw.Draw(img).text((0,0), "hello world", font=fnt, fill=(0,0,0))
img.save('test.jpg')
# Create an array with a required colours
# The colours are given in BGR [B, G, R]
# The array is created with values of ones, the size is (H, W, Channels)
# The format of the array is uint8
# This array needs to be converted to an image of type uint8
selectedColor = [75, 19, 77] * np.ones((640, 480, 3), np.uint8)
imgSelectedColor = np.uint8(np.absolute(selectedColor))

Categories