Swapping array dimensions with NumPy - python

When I load an image with PIL and convert it into a NumPy array:
image = Image.open("myimage.png")
pixels = np.asarray(image)
The data is stored as [x][y][channel]. I.e., the value of pixels[3, 5, 0] will be the the (3, 5) pixel, and the red component of that pixel.
However, I am using a library which requires the image to be in the format [channel][x][y]. Therefore, I am wondering how I can do this conversion?
I know that NumPy has a reshape function, but this doesn't actually allow you to "swap" over the dimensions as I want.
Any help? Thanks!

In order to get the dimensions in the order that you want, you could use the transpose method as follows:
image = Image.open("myimage.png")
pixels = np.asarray(image).transpose(2,0,1)

Related

How to create an image with height as pixel values

I want to create a jpg image with size 343 by 389 (Height by Width) with height as pixel values. For example for the whole topmost pixels, I need to give it as value 1, the next row of pixels should have a value 2. and finally, the last pixel with value 343. then export that image in jpg format. How to do this? either in python or in Matlab?
In MATLAB
A solution in MATLAB using the meshgrid() function may work. An important part is to caste the array Image of type double into an unsigned 8-bit integer array, uint8 before exporting it as a .jpg using the imwrite() function.
[~,Image] = meshgrid((1:389),(1:343));
imwrite(uint8(Image),"Depth.jpg");
Did it
from PIL import Image
import numpy as np
a = np.empty(shape=(343, 389), dtype=int)
for i in range(343):
for j in range(389):
a[i,j]=i
im = Image.fromarray(a,'L')
im.save('depth.jpg')

Replace certain pixels by integers in numpy array

I have made myself a numpy array from a picture using
from PIL import Image
import numpy as np
image = Image.open(file)
np.array(image)
its shape is (6000, 6000, 4) and in that array I would like to replace pixel values by one number lets say this green pixel [99,214,104,255] will be 1.
I have only 4 such pixels I want to replace with a number and all other pixels will be 0. Is there a fast and efficient way to do so and what is the best way to minimize the size of the data. Is it better to save it as dict(), where keys will be x,y and values, will be integers? Or is it better to save the whole array as it is with the shape it has? I only need the color values the rest is not important for me.
I need to process such a picture as fast as possible because there is one picture every 5 minutes and lets say i would like to store 1 year of data. That is why I'd like to make it as efficient as possible time and space-wise.
If I understand the question correctly, you can use np.where for this:
>>> arr = np.array(image)
>>> COLOR = [99,214,104,255]
>>> np.where(np.all(arr == COLOR, axis=-1), 1, 0)
This will produce a 6000*6000 array with 1 if the pixel is the selected colour, or 0 if not.
How about just storing in a database: the position and value of the pixels you want to modify, the shape of the image, the dtype of the array and the extension (jpg, etc...). You can use that information to build a new image from an array filled with 0.

How to shift an image in Scipy?

I'm trying to translate an image using the following code.
im = io.imread("path/to/my/image.jpg")
shift_image = scipy.ndimage.shift(im, np.array([1, 2]))
I'm using skimage to read the image.
I get the following error
RuntimeError: sequence argument must have length equal to input rank
The name ndimage (with "n-dimensional" in it) suggests that the package is not going to assume that images are two dimensional, and that any other dimension means something else. After all, 3D images (MRI) are a thing. So in effect, it operates with an abstract n-dimensional array. For an two-dimensional RGB image, the shape is (height, width, 3) because of the three color channels. So the shift would be [1, 2, 0].

Reordering numpy array indices

I have a 2D array that I want to create an image from. I want to transform the image array of dimensions 140x120 to an array of 140x120x3 by stacking the same array 3 times (to get a grayscale image to use with skimage).
I tried the following:
image = np.uint8([image, image, image])
which results in a 3x120x140 image. How can I reorder the array to get 120x140x3 instead?
np.dstack([image, image, image]) (docs) will return an array of the desired shape, but whether this has the right semantics for your application depends on your image generation library.

Add two 3D numpy arrays with a 2D mask

I would like to add two 3D numpy arrays (RGB image arrays) with a 2D mask generated by some algorithms on a greyscale image. What is the best way to do this?
As an example of what I am trying to do:
from PIL import Image, ImageChops, ImageOps
import numpy as np
img1=Image.open('./foo.jpg')
img2=Image.open('./bar.jpg')
img1Grey=ImageOps.grayscale(img1)
img2Grey=ImageOps.grayscale(img2)
# Some processing for example:
diff=ImageChops.difference(img1Grey,img2Grey)
mask=np.ma.masked_array(img1,diff>1)
img1Array=np.asarray(im1)
img2Array=np.asarray(im2)
imgResult=img1Array+img2Array[mask]
I was thinking:
1) break up the RGB image and do each color separately
2) duplicate the mask into a 3D array
or is there a more pythonic way to do this?
Thanks in advance!
Wish I could add a comment instead of an answer. Anyhow:
masked_array is not for making masks. It's for including only the data outside the mask in calculations such as sum, mean, etc.. scientific statistical applications. It's comprised of an array and the mask for the array.
It's probably NOT what you want.
You probably just want a normal boolean mask, as in:
mask = diff>1
Then you'll need to modify the shape so numpy broadcasts in the correct dimension, then broadcast it into the 3rd dimension:
mask.shape = mask.shape + (1,)
mask = np.broadcast_arrays(img1Array, mask)[1]
After that, you can just add the pixels:
img1Array[mask] += img2Array[mask]
A further point of clarification:
imgResult=img1Array+img2Array[mask]
That could never work. You are saying 'add some of the pixels from img2Array to all of the pixels in img1Array' 6_9
If you want to apply a ufunc between two or more arrays, they must be either the same shape, or broadcastable to the same shape.

Categories