Confused during reshaping array of image - python

At the moment I'm trying to run a ConvNet. Each image, which later feeds the neural net, is stored as a list. But the list is at the moment created using three for-loops. Have a look:
im = Image.open(os.path.join(p_input_directory, item))
pix = im.load()
image_representation = []
# Get image into byte array
for color in range(0, 3):
for x in range(0, 32):
for y in range(0, 32):
image_representation.append(pix[x, y][color])
I'm pretty sure that this is not the nicest and most efficient way. Because I have to stick to the structure of the list created above, I thought about using numpy and providing an alternative way to get to the same structure.
from PIL import Image
import numpy as np
image = Image.open(os.path.join(p_input_directory, item))
image.load()
image = np.asarray(image, dtype="uint8")
image = np.reshape(image, 3072)
# Sth is missing here...
But I don't know how to reshape and concatenate the image for getting the same structure as above. Can someone help with that?

One approach would be to transpose the axes, which is essentially flattening in fortran mode i.e. reversed manner -
image = np.asarray(im, dtype="uint8")
image_representation = image.ravel('F').tolist()
For a closer look to the function have a look to the numpy.ravel documentation.

Related

How can I create an array of the grayscale color pixel values of a 28x28 matplotlib figure?

I am trying to code a neural network. I am in the very early stages and can't quite get past this problem. I have working code to extract an image from an MNIST database and form it into a matplotlib. In order to continue, I need to extract the grayscale value (between 0 and 255) of each individual pixel. I know it is possible, but I do not know how to access and iterate through each pixel on the figure. Here is an example:
matplot of handrawn figure
Here is my code thus far:
import numpy as np
import gzip
import matplotlib.pyplot as plt
import random
from PIL import Image
f = gzip.open('train-images-idx3-ubyte.gz','r')
image_size = 28
num_images = 10000
f.read(16)
buf = f.read(image_size * image_size * num_images)
data = np.frombuffer(buf, dtype=np.uint8).astype(np.float32)
data = data.reshape(num_images, image_size, image_size, 1)
x = random.randrange(0, 10000)
image = np.asarray(data[x]).squeeze()
plt.style.use('grayscale')
plt.imshow(image)
plt.show()
If you can help, thank you so much!
I tried to find out if there was a way to just call pixel values via (row, column) sort of thing, but I couldn't find anything. People have said that its impossible to do on matplot, but if you hover on a pixel you can clearly see the value, so there must be a way to access it. I want to be able to just iterate through the image pixels, but there is no keyword like that.
You have the gray-scale values already. They're in the raw data that you are loading. In the above code, the matrix of values appears to be stored in image.
Try adding this directly after you declare image.
for i in range(28):
for j in range(28):
val = img[i, j]
if val > 0:
print(i, j, f' {val}')
This will print all pixel values in the matrix-image that are above zero. Looking at the index numbers will show you that the non-0 values are all clustered together in the matrix, giving you an idea that there is an image there.

How do I generate a random colored image using Image.fromaray() in python?

I am trying to create a random image using NUMPY. First I am creating a random 3D array as it should be in the case of an image e.g. (177,284,3).
random_im = np.random.rand(177,284,3)
data = np.array(random_im)
print(data.shape)
Image.fromarray(data)
But when I am using Image.fromarray(random_array), this is throwing the following error.
Just to check if there is any issue with the shape of the array, I converted an image back to the array and converted it back after copying it to the other variable. And I got the output I was looking for.
img = np.array(Image.open('Sample_imgs/dog4.jpg'))
git = img.copy()
git.shape
Image.fromarray(git)
They both have the same shape, I don't understand where am I making the mistake.
When I am creating a 2D array and then converting it back it is giving me a black canvas of that size (even though the pixels should not be black).
random_im = np.random.randint(0,256,size=(231,177))
print(random_im)
# data = np.array(random_im)
print(data.shape)
Image.fromarray(random_im)
I was able to get this working with the solution detailed here:
import numpy as np
from PIL import Image
random_array = np.random.rand(177,284,3)
random_array = np.random.random_sample(random_array.shape) * 255
random_array = random_array.astype(np.uint8)
random_im = Image.fromarray(random_array)
random_im.show()
----EDIT
A more elegant way to get a random array of the correct type without conversions is like so:
import numpy as np
from PIL import Image
random_array = np.random.randint(low=0, high=255,size=(250,250),dtype=np.uint8)
random_im = Image.fromarray(random_array)
random_im.show()
Which is almost what you were doing in your solution, but you have to specify the dtype to be np.uint8:
random_im = np.random.randint(0,256,size=(231,177),dtype=np.uint8)

How to shuffle pixels in an image using Python Pillow?

My goal is to shuffle all pixels in a 512x512 Python Pillow image. Also, I need the time performance to be relatively good. What I've tried:
from PIL import Image
import numpy as np
orig = Image.open('img/input2.jpg')
orig_px = orig.getdata()
np_px = np.asarray(orig_px)
np.random.shuffle(np_px)
res = Image.fromarray(np_px.astype('uint8')).convert('RGB')
res.show()
The Preview app gives me the following error:
The file “tmp11g28d6z.PNG” could not be opened.
It may be damaged or use a file format that Preview doesn’t recognise.
I cannot figure out, what went wrong. I would be grateful for any suggestions about fixing this code or trying a different approach to solving this problem.
Main problem that getdata provide you 1d array, and fromarray requires 2d or 3d array. see corrected code. You maybe notice two reshapes. So first reshape make array of pixels. Each pixel has 3 values. Than shuffle them, than reshape in image. If you comment np.random.shuffle(orig_px) you will get original image as is.
from PIL import Image
import numpy as np
orig = Image.open('test.jpg')
orig_px = orig.getdata()
orig_px = np.reshape(orig_px, (orig.height * orig.width, 3))
np.random.shuffle(orig_px)
orig_px = np.reshape(orig_px, (orig.height, orig.width, 3))
res = Image.fromarray(orig_px.astype('uint8'))
res.save('out.jpg')

How to get a matrix consisting of arrays of pixels and RGB?

I tried using the PIL library to get a matrix consisting of arrays of pixels and RGB, however, I only get a one-dimensional array and I don’t understand how to form a matrix of them
img = Image.open("E:\\1f9114.png").convert('RGB')
obj = img.load()
width, height = img.size
for j in range(height):
for i in range(width):
matrix1=[i,j,obj[i,j]]
print(matrix1)
print()
I know that the matrix can turn out huge, and the usual sheet does not cope .I hope somebody will help, as it is important for me.
There are several issues with this code snippet:
matrix1 is always overridden. If you want to add pixels to an existing list, use list.append().
im.getdata() should be used to obtain a one-dimensional raw pixel list from the image.
Here is an example (adapted from here) to load pixels into a two-dimensional array that contains (r,g,b) tuples built using list comprehensions and slices.
pixels = list(img.getdata())
matrix1 = [pixels[i*width:(i+1)*width] for i in range(height)]

Is it possible to generate a gif animation using pillow library only?

I want to be able to transform numpy arrays into images. First, I have learned how to transform a 3D (hight x width x color) array into an image. After some research it looks to me that PIL (or Pillow) is the most natural way to do it. This is how I do it at the moment (and it works fine):
from PIL import Image
import numpy as np
if __name__ == '__main__':
h = 4
w = 8
arr = np.zeros((h,w,3), dtype=np.uint8)
arr[0, 0, :] = [255,255,0]
arr[3, 7, :] = [0,255,0]
img = Image.fromarray(arr, 'RGB')
img.save('viz.png')
As a next step, I want to be able to take a list of 3D array (or a 4D array, where time is the additional dimension) and generate the corresponding animation. So, far I did not find how to do it.
It looks like Pillow is able to read gif-animation. Using ImageSequence we can access its frames. However, I cannot find out how one can put a sequence of images into animation.
I saw some solutions that use ìmages2gif but I would like to stay withing a single library.
ADDED
The answers here do not answer my question. They use gifmaker library that I cannot even install by pip.
So, the main objection of the question was to generate a gif animation represented by a list of 3D arrays (frames) or by a 4D matrix (with width, height, color and time as dimension) without a use of tools that are "external" to Python.
It looks like PIL library cannot do that. At least not in a simple way without hacks or workarounds. However, the goal can be achieved by using the moviepy library. Here is the elegant solution provided by this library:
import numpy as np
import moviepy.editor as mpy
def make_frame(t):
h = 100
w = 100
ar = np.zeros((h, w, 3))
for hi in range(h):
for wi in range(w):
for ci in range(3):
ar[hi, wi, ci] = 255.0*t/15.0
return ar
if __name__ == '__main__':
clip = mpy.VideoClip(make_frame, duration=15.0)
clip.write_gif('ani.gif', fps=15)

Categories