resize numpy array referencing another array - python

mypath='/Users/sachal/Desktop/data_raw/normal_1/images'
onlyfiles = [ f for f in listdir(mypath) if isfile(join(mypath,f)) ]
images = np.asarray(np.empty(len(onlyfiles), dtype=object))
for n in range(0, len(onlyfiles)):
images[n] = cv2.imread( join(mypath,onlyfiles[n]) )
#--------------------------------------------------------------------------------
resized = np.asarray(np.empty(len(onlyfiles), dtype=object))
img_f = np.asarray(np.empty(len(onlyfiles), dtype=object))
for n in range(0, len(onlyfiles)):
resized[n] = cv2.resize(images[n],(101,101))
img_f[n] = cv2.cvtColor(resized[n], cv2.COLOR_BGR2YUV)
train_img = np.asarray(img_f)
#--------------------------------------------------------------------------------
In the above code first I am loading images using opencv then I am resizing and changing their colour space in the second block.
My batch size is 6408 and dimensions of images are 101*101*3
When i do train_img.shape i get(6408,) and upon train_img[i].shape i get 101*101*3 and I am unable to train my neural network model because of this and the dimensions i want are 6408*101*101*3
I tried reshaping with this train_img.resize(6408,101,101,3) i got this ValueError: cannot resize an array that references or is referenced
by another array in this way. Use the resize function
and while fitting my model with i got this error Error when checking input: expected conv2d_3_input to have 4 dimensions, but got array with shape (6408, 1)
I want to know if i can change the dimensions of my input with the current method i am using to load my images.

You shouldn't use the dtype=object here. OpenCV creates ndarray images anyway.
Here is a corrected version of your code:
mypath='/Users/sachal/Desktop/data_raw/normal_1/images'
onlyfiles = [ f for f in os.listdir(mypath) if os.path.isfile(join(mypath,f)) ]
images = []
for file in onlyfiles:
img = cv2.imread(os.path.join(mypath,file))
resized_img = cv2.resize(img, (101, 101))
yuv_img = cv2.cvtColor(resized_img, cv2.COLOR_BGR2YUV)
images.append(yuv_img.reshape(1, 101, 101, 3))
train_img = np.concatenate(images, axis=0)
print(train_img.shape)
In the loop, you load each image, resize it, convert it to YUV then put it in a list. At the end of the loop, your list contains all your training images. You can pass it to np.concatenate to create an ndarray.

Related

Tensorflow how do I reshape array of images properly for model prediction input

I have trained model and I am trying to test it
import tensorflow as tf
import os
import cv2
import matplotlib.pyplot as plt
import numpy as np
# Some paths
paths = {
"cats": "data\\images\\cats",
"dogs": "data\\images\\dogs",
"img": "data\\images"
}
label_to_index = {
"cat": 0,
"dog": 1
}
index_to_label = {
0: "cat",
1: "dog"
}
animals = {
"cats_labels": [label_to_index["cat"] for _ in range(len(paths["cats"]))],
"dogs_labels": [label_to_index["dog"] for _ in range(len(paths["dogs"]))],
"cats": [os.path.join(paths["cats"], img) for img in os.listdir(paths["cats"])],
"dogs": [os.path.join(paths["dogs"], img) for img in os.listdir(paths["dogs"])],
}
# Load model
model = tf.keras.models.load_model('models/cats_dogs_model_1.h5')
# Load one image for test
img = cv2.imread(animals['cats'][0])
# Predictions input needs to be an array
test_img = [img]
# (1) mobilenetv2_1.00_192_input expected to have 4 dimensions, image now has 3 dims ->
# -> add new dim
test_img = [np.expand_dims(img, axis=0) for img in test_img]
print("Shape is ", test_img[0].shape) # New Shape is (1, 375, 500, 3) , was (375, 500, 3)
print("Number if dimentions is ", test_img[0].ndim) # New Number if dimentions is 4 , was 3
# (2) ValueError: Error when checking input: expected mobilenetv2_1.00_192_input
# to have shape (192, 192, 3) but got array with shape (375, 500, 3)
# in the next line I am trying to reshape image for necessary sizes:
# test_img = [np.reshape(img, (192, 192)) for img in test_img]
# but if I uncomment it new error will be raised:
# ValueError: cannot reshape array of size 562500 into shape (192,192)
predictions = model.predict(test_img) # !!! error raises here
plt.imshow(test_img[0])
label = np.argmax(predictions)
plt.title(label)
plt.show()
But I encounter errors all the time I am trying to make image shape and dims valid for model.predict input, so I am stuck at this moment without understanding how to reshape my image properly. I hope anybody could explain me what is wrong with my image transormation, because this part is a black box for me now.
Errors I encounter:
(1) Error about dimentions - I added fourth dim, and everything is ok for now, then
(2) Error about invalid input image shape
Reshape is not you are looking for, reshape only rearranges the dimensions and changes values across dimensions, but never generates new values to fit a required size. What you want to resize the images. TensorFlow has a convenient function to resize a batch of images:
import tensorflow as tf
# ...
model = tf.keras.models.load_model('models/cats_dogs_model_1.h5')
img = cv2.imread(animals['cats'][0])
test_img = [img]
test_img = [np.expand_dims(img, axis=0) for img in test_img]
# It is better to have a single tensor instead of a list of tensors, therefore,
# before resizing the images concatenate all them in a tensor
test_img = tf.concat(test_img, axis=0)
test_img = tf.image.resize(test_img, [192, 192])
np.reshape cannot resize an image. It's used to, you guessed it, reshape an array to another shape without changing the number of elements it contains. For instance, you can reshape a (20, 50) array into a (20, 5, 10) array because 20x50=20x5x10, but you can't reshape a (375, 500, 3) image into a (192, 192, 3) image.
Instead, you should use the resize method from PIL.Image (https://www.google.com/amp/s/www.geeksforgeeks.org/python-pil-image-resize-method/amp/)

How to get only possible non overlapping blocks from images of any given size and show them in Python

I have images of varying resolutions, and I would like to extract non-overlapping blocks from these images.
However, because the images have not fixed size and my block size is big (64x64), I would like to get only non-overlapping blocks that could be found in an image. If the block exceeds the image borders, I don't want to get them.
I tried the view_as_blocks function from scikit-image as below:
from skimage.util import view_as_blocks
for elem in listOfFiles:
# Reading image
print("Reading image "+elem)
img = cv2.imread(elem)
print(img.shape) #for example, one image is (2059, 2059, 3)
Blocks = view_as_blocks(img, block_shape=(64, 64, 3))
The code returns the following error:
ValueError: 'block_shape' is not compatible with 'arr_in'
I also tried the Patch Extractor from scikit-learn, as follows:
from sklearn.feature_extraction import image
import cv2
import numpy
for elem in listOfFiles:
# Reading image
print("Reading image "+elem)
img = cv2.imread(elem)
print(img.shape)
pe = image.PatchExtractor(patch_size=(64,64))
pe_fit = pe.fit(img)
pe_trans = pe.transform(img)
print('Patches shape: {}'.format(pe_trans.shape))
The error that returns to me is the following:
ValueError: negative dimensions are not allowed
the function image.extract_patches_2d from sklearns runs perfectly, but unfortunatelly it works only for overlapping blocks as you can see here.
These functions also don't help me because I also want to show the image with these blocks selected, so I also need another matrix with coordinates of such blocks and show the selected blocks.
Is that possible to that in Python?
Since you don't care about the incomplete blocks at the edges, you can manually check the number of blocks along each dimension, and crop your image to that shape:
from skimage.util import view_as_blocks
for elem in listOfFiles:
# Reading image
print("Reading image "+elem)
img = cv2.imread(elem)
print(img.shape) #for example, one image is (2059, 2059, 3)
block_shape = np.array((64, 64, 3))
nblocks = np.array(img.shape) // block_shape # integer division
crop_r, crop_c, crop_ch = nblocks * block_shape
cropped_img = img[:crop_r, :crop_c, :crop_ch]
Blocks = view_as_blocks(cropped_img, block_shape=(64, 64, 3))

Add 2d array to make 3d in python

I have a requirement to read image files( 28*28) from a folder and stack them together to make a single array for analysis.
I have the following code:
for fname in os.listdir(dirname):
im = Image.open(os.path.join(dirname, fname))
imarray = np.array(im)
final = np.stack((final,imarray ), axis = 0)
am getting the following error:
ValueError: all input arrays must have the same shape
imarray is (28,28) and i have 60K images in that folder so i want to make a array of size (60000,28,28)
Thanks for the help
NK
Build a list of all components and stack them once:
alist = []
for fname in os.listdir(dirname):
im = Image.open(os.path.join(dirname, fname))
imarray = np.array(im)
alist.append(imarray)
final = np.stack(alist) # axis=0 is the default
This will join them on a new initial axis.

Store several images as ndarrays into one 4 dimensional ndarray

I have a loop, where I read images and resize them to 32x32x3
for i, filename in enumerate(os.listdir(path)):
img = plt.imread(path+filename)
out = imresize(img, [32,32])
I tried to store it in a list and convert it to an numpy array
for i, filename in enumerate(os.listdir(path)):
img = plt.imread(path+filename)
out = imresize(img, [32,32])
inet_signs.append(out)
a = np.array(inet_signs)
But this only resulted in the error:
ValueError: could not broadcast input array from shape (32,32,3) into
shape (32,32)

on modifying the shape of numpy array resulting from input image

I am trying to customize an existing code to suit my own need. Originally, the code use imgs = np.ndarray((total, 1, image_rows, image_cols), dtype=np.uint8) to store a list of image files in an numpy array format. Iterating the folder, each image file is read as follows img = skimage.io.imread(os.path.join(train_data_path, image_name)) It works just fine.
The code is as follows:
image_rows = 420
image_cols = 580
imgs = np.ndarray((total, 1, image_rows, image_cols), dtype=np.uint8)
i=0
for image_name in images:
img = skimage.io.imread(os.path.join(train_data_path, image_name))
img = np.array([img])
imgs[i]=img
i+=1
In order to suit my own need, I tend to have image file array with the shape [total, image_rows,image_cols,1]. In other words, I modified it as imgs = np.ndarray((total,image_rows, image_cols,1), dtype=np.uint8) However, running the code causes the following error
imgs[i] = img
ValueError: could not broadcast input array from shape (1,420,580) into shape
(420,580,1)
Are there any way to change the shape of img, which originally has shape of [1,420,580] after reading from file. How can I change it to [420,580,1] without affecting the corresponding pixel values in the image.
You want to transpose the dimensions. It can be done using the transpose method:
img = img.transpose(1,2,0)
(for your case)

Categories