Using skimage.transform.rescale twice on an image creates additional channels - python

In a coursera guided project that I was doing, the instructor used
from skimage.transform import rescale
image_rescaled = rescale(rescale(image,0.5),2.0)
to distort the image.
The error that is occurring on my own device (and that didn't arise on the jupyter notebook of the project, probably due to difference in versions of modules and python) was that image_rescaled's number of channel's are increasing by 1.
eg => images_normal.shape = (256,256,256,3) and images_with_twice_reshape.shape=(256,256,256,4)
This issue doesn't come up if I use rescaled(rescale(image,2.0),0.5).
Is this intended in a newer version of python/skimage or am I doing something wrong?
For additional references(didn't delete anything from source code but highlighted important parts with #s):
import os
import re
from scipy import ndimage, misc
from skimage.transform import resize, rescale
from matplotlib import pyplot
import numpy as np
def train_batches(just_load_dataset=False):
batches = 256 # Number of images to have at the same time in a batch
batch = 0 # Number if images in the current batch (grows over time and then resets for each batch)
batch_nb = 0 # Batch current index
ep = 4 # Number of epochs
images = []
x_train_n = []
x_train_down = []
x_train_n2 = [] # Resulting high res dataset
x_train_down2 = [] # Resulting low res dataset
for root, dirnames, filenames in os.walk("data/cars_train.nosync"):
for filename in filenames:
if re.search("\.(jpg|jpeg|JPEG|png|bmp|tiff)$", filename):
filepath = os.path.join(root, filename)
image = pyplot.imread(filepath)
if len(image.shape) > 2:
image_resized = resize(image, (256, 256)) # Resize the image so that every image is the same size
#########################
x_train_n.append(image_resized) # Add this image to the high res dataset
x_train_down.append(rescale(rescale(image_resized, 0.5), 2.0)) # Rescale it 0.5x and 2x so that it is a low res image but still has 256x256 resolution
########################
# >>>> x_train_down.append(rescale(rescale(image_resized, 2.0), 0.5)), this one works and gives the same shape of x_train_down and x_train_n.
########################
batch += 1
if batch == batches:
batch_nb += 1
x_train_n2 = np.array(x_train_n)
x_train_down2 = np.array(x_train_down)
if just_load_dataset:
return x_train_n2, x_train_down2
print('Training batch', batch_nb, '(', batches, ')')
autoencoder.fit(x_train_down2, x_train_n2,
epochs=ep,
batch_size=10,
shuffle=True,
validation_split=0.15)
x_train_n = []
x_train_down = []
batch = 0
return x_train_n2, x_train_down2
And with the above code, I get x_train_n2.shape = (256,256,256,3) and x_train_down2.shape=(256,256,256,4).

I was able to reproduce your issue as follows:
import numpy as np
from skimage.transform import resize, rescale
image = np.random.random((512, 512, 3))
resized = resize(image, (256, 256))
rescaled2x = rescale(
rescale(resized, 0.5),
2,
)
print(rescaled2x.shape)
# prints (256, 256, 4)
The problem is that resize can infer that your final dimension is channels/RGB, because you give it a 2D shape. rescale, on the other hand, treats your array as a 3D image of shape (256, 256, 3), which goes down to (128, 128, 2), interpolating along the colors as well, as if they were another spatial dimension, and then upsampling to (256, 256, 4).
If you look at the rescale documentation, you'll find the "multichannel" parameter, described as:
Whether the last axis of the image is to be interpreted as multiple channels or another spatial dimension.
So, updating my code:
rescaled2x = rescale(
rescale(resized, 0.5, multichannel=True),
2,
multichannel=True,
)
print(rescaled2x.shape)
# prints (256, 256, 3)

Related

How to resize an image now that scipy.misc.imresize has been removed from scipy?

I want to use an old script which uses scipy.misc.imresize.
But unfortunately it is removed entirely from scipy.
I do not understand what it does so what code will perform the same action as the above line.
I tried using skimage.transform.resize(image, (num_px*num_px*3, 1), order = 3)
But get the error - ValueError: cannot reshape array of size 12288 into shape (1200,1)
Edit: More Information
It's classifying pictures as belonging to one of two sets.
my_image = "anyimage.jpg" #any image form the internet
#Preprocessing the image
fname = "images/" + my_image
image = np.array(ndimage.imread(fname, flatten=False))
image = image/255.
my_image = scipy.misc.imresize(image, size=(num_px,num_px)).reshape((1, num_px*num_px*3)).T #The original code which worked perfectly
my_predicted_image = predict(d["w"], d["b"], my_image) #predict function uses
#linear regression where the third parameter must be data of
#size (num_px * num_px * 3, number of examples)
Instead of using the scipy image routines imread() and imresize() which have been deprecated and removed, you can do the same thing using pillow, which you should already have since it is required for the scipy functions to work.
from PIL import Image
import numpy as np
my_image = "anyimage.jpg" #any image form the internet
fname = "images/" + my_image
num_px = 20 # a guess based on the shape of (1200, 1) in your error message
#Preprocessing the image
image = Image.open(fname).resize(size=(num_px, num_px)) # use PIL to open and reshape image
my_image = np.array(image, dtype=float) / 255 # convert to numpy array and scale values
my_image = my_image.reshape((1, num_px*num_px*3)).T # reshape and transpose
my_predicted_image = predict(d["w"], d["b"], my_image) #predict function uses
#linear regression where the third parameter must be data of
#size (num_px * num_px * 3, number of examples)
from PIL import Image
import numpy as np
my_image = "anyimage.jpg" #any image form the internet
fname = "images/" + my_image
#Preprocessing the image
image = Image.open(fname).resize(size=(num_px, num_px)) # use PIL to open and reshape image
my_image = np.array(image, dtype=float) / 255 # convert to numpy array and scale values
my_image = my_image.reshape((1, num_px*num_px*3)).T # reshape and transpose
my_predicted_image = predict(d["w"], d["b"], my_image)

Cannot feed image data of DICOM into image data generator

So i have preprocessed some dicom images to feed a neural network, and in image augmentation step, the image data generator expects a 4d input while my data is 3d (200, 420, 420)
i tried reshaping the array and expanding dimensions, but in both cases i cannot plot the individual images in the array (expects image with shape 420, 420 and instead my new images have shape 420, 420, 1)
and here are my codes;
I have three functions to convert DICOM images into images with good contrast;
This one takes housefield units
def transform_to_hu(medical_image, image):
intercept = medical_image.RescaleIntercept
slope = medical_image.RescaleSlope
hu_image = image * slope + intercept
return hu_image
This one sets window image values;
def window_image(image, window_center, window_width):
img_min = window_center - window_width // 2
img_max = window_center + window_width // 2
window_image = image.copy()
window_image[window_image < img_min] = img_min
window_image[window_image > img_max] = img_max
return window_image
And this function loads the image:
def load_image(file_path):
medical_image = dicom.read_file(file_path)
image = medical_image.pixel_array
hu_image = transform_to_hu(medical_image, image)
brain_image = window_image(hu_image, 40, 80)
return brain_image
Then i load my images:
files = sorted(glob.glob('F:\CT_Data_Classifier\*.dcm'))
images = np.array([load_image(path) for path in files])
images.shape returns (200, 512, 512)
and everything is fine about the data, for example i can plot 100th image by
plt.imshow(images[100]) and it plots an image
i then feed the data into image data generator
train_image_data = ImageDataGenerator(
rescale=1./255,
shear_range=0.,
zoom_range=0.05,
rotation_range=180,
width_shift_range=0.05,
height_shift_range=0.05,
horizontal_flip=True,
vertical_flip=True,
fill_mode='constant',
cval=0
but then, when i try to plot, with this code:
plt.figure(figsize=(12, 12))
for X_batch, y_batch in train_image_data.flow(trainX, trainY, batch_size=9):
for i in range(0, 9):
plt.subplot(330 + 1 + i)
plt.imshow(X_batch[i])
plt.show()
break
it returns
(ValueError: ('Input data in "NumpyArrayIterator" should have rank 4. You passed an array with shape', (162, 420, 420)))
i tried expand_dims and reshape to add an extra dimension at the end of the array to represent channels
but then it returns
TypeError: Invalid shape (420, 420, 1) for image data
in the plt.imshow stage
im a doctor and not an experienced programmer, so i would really appreciate your help. cheers.
You are correct in adding an extra dimension to represent channels. That part seems fine. The problem is with plotting. For that, you can use:
plt.matshow(x[..., 0]).
where x is the 3D array. The syntax x[..., 0] means take index 0 of the last dimension of array x. The ellipsis (...) is shorthand to fill in the dimensions. For a 3D array, the equivalent call would be x[:, :, 0].

How to obtain same augmented images using ImageDataGenerator in keras or tensorflow?

I am working with grayscale images of size 75 by 75 and want to perform some augmentation techniques using ImageDataGenerator.
But wondering if we can repeat the output consistently if we run multiple times. I am not talking about epochs but like running the whole code to mimic the exact same augmented images to get same results.
I am attaching sample grayscale image:
import matplotlib.pyplot as plt
import numpy as np
from scipy import misc, ndimage
from keras.preprocessing.image import ImageDataGenerator
gen = ImageDataGenerator(rotation_range=10, width_shift_range=0.1,
height_shift_range=0.1, zoom_range=0.1, # shear_range=0.15,
channel_shift_range=10., horizontal_flip=True, vertical_flip = True,
rescale = 0.2, fill_mode = 'wrap')
image_path = '/trial_img.png' # grayscale image
# Obtain image
# data_format = [#num_images,height,width,#num_of_channels]
# where, #num_images = 1 and #num_of_channels = 1, height = width = 75
image = np.expand_dims(ndimage.imread(image_path),0) # add num_images dimension
image = np.expand_dims(image, axis=3) # add num_of_channels dimension
plt.imshow(image.reshape(75,75), cmap = 'gray')
# Trial #1
# Generate batches of augmented images from this image
aug_iter = gen.flow(image)
# Get 10 samples of augmented images
aug_images1 = [next(aug_iter)[0].reshape(75,75).astype(np.uint8) for i in range(10)]
# Trial #2
aug_iter = gen.flow(image)
aug_images2 = [next(aug_iter)[0].reshape(75,75).astype(np.uint8) for i in range(10)]
# check if equal
truth = []
for val in range(10):
truth.append((aug_images1[val] == aug_images2[val]).all()) # check images
np.asarray(truth).all() # check if all images are same
How to repeat the augmented outputs consistently in above code?
I know this code is written very badly, any suggestions on code optimization are also greatly appreciated.
Thanks,
Gopi
You can set a seed to the flow method:
aug_iter = gen.flow(image, seed = 0)
By setting this parameter to a specific integer, you will always get the same sequence of random shuffling/transformations.
You could run the generator and save the images, then simply load the images:
# Trial #1
# Generate batches of augmented images from this image
aug_iter = gen.flow(image)
# Get 10 samples of augmented images
aug_images1 = [next(aug_iter)[0].reshape(75,75).astype(np.uint8) for i in range(10)]
If memory is not a problem, you can save this with numpy:
aug_images1 = np.array(aug_images1)
np.save(filename, aug_images1)
Then load it:
aug_images1 = np.load(filename)
If you prefer, you can save each image as proper image files (less memory occupied) using an image library such as Pillow:
from PIL import Image
for (im,filename in zip(aug_images1,list_of_names)):
im = Image.fromarray(im) #make sure you have a uint8 from 0 to 255 array.
im.save(filename)
Later, load the files:
aug_images1 = [np.array(image.open(filename)) for filename in list_of_names]
aug_images1 = np.array(aug_images1)
Using ImageDataGenerator for loading files
In case you don't want to load all images at once in memory, with saved images, you can create a new ImageDataGenerator, but without any kind of augmentation, just a pure image loader.
Then use gen.flow_from_directory() to get images from a directory.
Read more in the documentation: https://keras.io/preprocessing/image/

tensorflow dataset api create 100 images from 1

what is the most efficient way to load an image with tensorflow and crop 100 images from that one image.
what I tried is:
import numpy as np
import tensorflow as tf
import cv2
filenames_train = ['image1.jpg', 'image2.jpg', 'image3.jpg']
def _opencv_operation(image,label):
# operation with image without tensorflow
kernel = np.ones((5, 5), np.float32) / 25
image = cv2.filter2D(image, -1, kernel)
return image, int(label)
def _read_images_and_crop(image_path):
image = tf.read_file(image_path)
image = tf.image.decode_jpeg(image)
print image.shape
image.set_shape([None, None, None])
image = tf.cast(image, tf.float32)
image = tf.scalar_mul(2./255.,image)-1.
image = tf.image.resize_images(image, [299, 299])
image = tf.reshape(image,(299, 299,3))
label = 1
#r_values1 = #random values#
#image1 = tf.image.crop_and_resize(image, r_values1)
# ...
#r_values100 = # random values#
#image100 = tf.image.crop_and_resize(image, r_values100)
#label = r_values1 ... r_values100
return image, label
# but what i actually want to return is: return [image1, image2,..image100], [label1, label2,.. label100]
# Training dataset
dataset_train = tf.data.Dataset.from_tensor_slices((filenames_train))
dataset_train = dataset_train.map(_read_images_and_crop)
dataset_train = dataset_train.map(
lambda filename, label: tuple(tf.py_func(
_opencv_operation, [filename, label], [tf.float32, tf.int64])))
dataset_train = dataset_train.batch(5)
iterator = tf.data.Iterator.from_structure(dataset_train.output_types,
dataset_train.output_shapes)
(next_images,next_labels) = iterator.get_next()
training_init_op = iterator.make_initializer(dataset_train)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for i_epoch in xrange(5):
sess.run(training_init_op)
curr_images, curr_labels = sess.run([next_images, next_labels])
so, what my script does, is reading one image from a file and resizing it.
and gives this image as an output.
what I need is to crop that image afterwords with 100 different crop parameters, so i have 100 images as an output and 100 labels.
but at the and I want bust as many outputs as big like the batch size.
Is it possible with the dataset api or is it just possible to load one image from file and process that image till its the output of the dataset_train.
I dont want to load an image 100 times and process it 100 times.
I want to load it one time and process it 100 times(e.g.crop, blur with different parameters and so on..)

Image transformation with Keras and Numpy

I want to feed a network with images using Keras. I am downloading images from internet and storing them into a numpy array. When I plot a single image then it is shown correctly.
As a next step I am creating a new numpy array in which I store the single image. However, at that step the image is only displayed as a black images. I wondering why this happens?
Here is my code:
import numpy as np
import urllib.request
import cv2
from matplotlib import pyplot as plt
from keras import backend as K
%matplotlib inline
file = "http://farm2.static.flickr.com/1353/1230897342_2bd7c7569f.jpg"
# Read web file
images_or = np.ndarray((1,128, 128,3), dtype=np.uint8)
req = urllib.request.urlopen(file)
arr = np.asarray(bytearray(req.read()), dtype=np.uint8)
img = cv2.imdecode(arr,-1) # 'load it as it is'
images_or[0] = cv2.resize(img,(128,128))
# Display image
plt.imshow(images_or[0])
plt.show()
# Format image
images_or = images_or.astype(K.floatx())
images_or *= 0.96/255
images_or += 0.02
# Display image
plt.imshow(images_or[0])
plt.show()
# Reshape image
images_or = images_or.reshape(images_or.shape[0], 3, 128, 128)
# Copy image in another np.array
A_train_test = np.ndarray((1, 3, 128, 128), dtype=np.uint8)
A_train_test[0] = images_or[0]
# Format image
A_train_test = A_train_test.astype(K.floatx())
A_train_test *= 0.96/255
A_train_test += 0.02
# Reshape image
A_train_test = A_train_test.reshape(A_train_test.shape[0], 128, 128, 3)
image_xxx = A_train_test[0]
plt.imshow(image_xxx)
plt.show()
Thank you very much in advance,
Andi
I needed to change the order of commands:
# Copy image in another np.array
A_train_test = np.ndarray((1, 3, 128, 128), dtype=np.uint8)
A_train_test = A_train_test.astype(K.floatx())
A_train_test[0][:] = images_or[0][:]
Issues is solved.

Categories

Resources