I am trying to downscale the image using "scikit-image". However I cannot show the downscaled picture through matplotlib.imshow function because of the dimension. Is there a way to prevent such dimension reduction? I put the script as well.
import os, cv2, glob
import numpy as np
import matplotlib.pyplot as plt
from skimage import io
from skimage.transform import pyramid_reduce,
plt.style.use('dark_background')
img_path = os.path.join(img_base_path, value[0])
img = io.imread(img_path)
resized = pyramid_reduce(img, downscale=4)
print(resized.shape)
img.shape is (240, 240, 3). So what I expect for an output is (60, 60, 3). However what I get is (60, 60, 1).
When I read the documentation of the pyramid_reduce function, I notice the parameter multichannel:
multichannel: bool,optional
Whether the last axis of the image is to be
interpreted as multiple channels or another spatial dimension.
So I would suggest you to set that to True, otherwise he is treating your 2D color images as a 3D BW image:
resized = pyramid_reduce(img, downscale=4, multichannel=True)
Related
I have an image of size 72x96. Windows says its size is 72x96. PIL Image also says it is 72x96:
from PIL import Image, ImageOps
with Image.open(<path>) as img:
print(img.size) # (72, 96)
print(ImageOps.exif_transpose(img).size) # (72, 96)
But when I read the image with cv2.imread or skimage.io.imread it says, that the shape of the image is (96, 72, 3):
from skimage.io import imread
im0 = imread(<path>)
print(im0.shape) # (96, 72, 3)
What is wrong here? Even if I do something like that:
import matplotlib.pyplot as plt
plt.imshow(im0)
It shows the image with the correct size, but the written size looks to be transposed.
This is expected behavior.
PIL returns the size of an image as (width, height) (PIL documentation), whereas numpy returns the shape of an array as the lengths of the first and then second dimension (in the case of a 2d array), so (height, width) (Numpy documentation).
I have an array of image pixel values that I would like to upscale for input into my neural network. It is an array of shape (28000, 48, 48, 1). These are normalized image pixel values and would like to upscale these to a higher resolution for input into my CNN. The arrays look like this...
array([[[[-0.6098866 ],
[-0.4592209 ],
[-0.40325198],
...,
[-0.7694696 ],
[-0.90518403],
[-0.95160526]],
[[-0.66049284],
[-0.68162924],
[-0.694159 ],
Both my X_train and y_train image arrays have shape of (28000,48,48,1). I would like to upscale or resize these 28000 image arrays to size 75x75. Please help. Should I convert arrays back to non-normalized arrays or images and then maybe use cv2 to upscale? How would I do this?
One easy way to resize images is using the Python module PIL (Python Image Library), which you can install with pip install pillow. Example below to demonstrate resizing a single image:
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
# Open image
panda_pil = Image.open("panda.jpg")
print(np.array(panda_pil).shape)
# (613, 696, 3)
panda_pil_resized = panda_pil.resize((75, 75))
print(np.array(panda_pil_resized).shape)
# (75, 75, 3)
plt.imshow(np.array(panda_pil_resized))
plt.show()
You can download the panda image as follows:
import urllib.request
panda_fname = "panda.jpg"
panda_url = "https://upload.wikimedia.org/wikipedia/commons/f/fe/Giant_Panda_in_Beijing_Zoo_1.JPG"
urllib.request.urlretrieve(panda_url, panda_fname)
To resize all 28000 images, one approach would be to do this as a preprocessing step in a for-loop, and save the images to a numpy array.
Edit: You can loop through your original 28000x2304 image array and upscale each image individually in a for-loop. To get the PIL.Image object from a np.ndarray object, you can use Pil.Image.from_array, as shown below (I have just generated a random array of Gaussian noise but it should work the same with your images):
import numpy as np
from PIL import Image
from time import perf_counter
old_width, old_height = 48, 48
new_width, new_height = 75, 75
num_images = 28000
old_image_array = np.random.normal(size=[num_images, old_width*old_height])
new_image_array = np.empty(shape=[num_images, new_width*new_height])
print("Starting conversion...")
t0 = perf_counter()
# Loop over each image individually
for i in range(num_images):
# Get the ith image and reshape
old_image = old_image_array[i].reshape(old_width, old_height)
# Convert to PIL.Image
old_image_pil = Image.fromarray(old_image)
# Upscale resolution
new_image_pil = old_image_pil.resize((new_width, new_height))
# Convert to numpy array
new_image = np.array(new_image_pil)
# Reshape and store in new image array
new_image_array[i] = new_image.reshape(new_width*new_height)
t1 = perf_counter()
print("Time taken = {:.3f} s".format(t1 - t0))
print(old_image_array.shape, new_image_array.shape)
Console output:
Starting conversion...
Time taken = 2.771 s
(28000, 2304) (28000, 5625)
There may well be a more efficient way of doing this, but this method is simple, and uses tools which are useful to know about if you don't know about them already (PIL is a good module for manipulating images, see this blog post if you want to learn more about PIL).
I've loaded an image using:
import numpy as np
from PIL import Image
imag = Image.open("image.png")
I = np.asarray(imag)
Where the shape of I is (951, 1200, 3)
But I would like to average each pixel roughly to it's luma values ((r*g*b)/3) to make the shape (951, 1200, 1).
What is the proper numpy operator to do this?
I think the easiest thing is to use Pillow's built-in conversion to Luminance as follows:
import numpy as np
from PIL import Image
# Load image and convert to luminance, and thence to Numpy array
imag = Image.open("image.png").convert('L')
I = np.asarray(imag)
I have pixel data that I want to use to create a new .tif image that has multiple frames. How would I go about doing this? I have tried python PIL however I have only found it supports multiple frame reading not writing. See below for my attempt that didn't work.
new_Image = Image.new("I;16", (num_pixels,num_rows))
for frame in range((len(final_rows)/num_rows)):
pixels = new_Image.load()
for row in range(num_rows):
row_pixel = final_rows[row].getPixels()
for pixel in range(num_pixels):
pixels[pixel,row] = row_pixel[pixel]
print frame
new_Image.seek(frame)
For example, using numpy and scikit-image with FreeImage plugin:
import numpy as np
from skimage.io._plugins import freeimage_plugin as fi
image = np.zeros((32, 256, 256), 'uint16')
fi.write_multipage(image, 'multipage.tif')
Or save it uncompressed using numpy and tifffile.py:
import numpy as np
from tifffile import imsave
image = np.zeros((32, 256, 256), 'uint16')
imsave('multipage.tif', image)
This assumes that all pages have the same data shape and type and no additional tags need to be written.
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