Rotating image and its key points label in tensorflow2.0 - tensorflow2.0

I am trying to add rotation to my dataset of images where the labels have some facial keypoints. tf.contrib is removed from tensorflow 2.0 and any other library like PIL does not work as I am using tf.data.Dataset.
I need angle rotated to be random while the same rotation needs to be applied to both an image and its keypoint labels as well. Is there a way to do this in tensorflow 2.0?
Below is the function I used:
def preprocess_data(image, angle):
image = tf.image.decode_jpeg(image, channels=3)
image = tf.image.resize(image, [input_size, input_size])
image = tf.image.rgb_to_grayscale(image)
image = Image.fromarray(np.array(tf.squeeze(image)))
rotated = Image.Image.rotate(image, angle)
image = tf.convert_to_tensor(np.array(rotated))
image = tf.expand_dims(image, -1)
return image
def load_and_preprocess_data(path):
image = tf.io.read_file(path)
rotation = tf.random.uniform([1,1], minval=-60, maxval=60, seed=0)
return preprocess_data(image, rotation)
Here I used PIL but it is not working when I try to map a tf.data.Dataset containing image paths to load_and_preprocess_data function.

Related

image preprocess function for image_dataset_from_directory

In the ImageDataGenerator, I've used the following function to preprocess images, through the keyword of 'preprocessing' in .flow_from_dataframe().
However, I am now trying to use the image_dataset_from_directory, which does not work with the preprocess function, as it does not allow embedding this function.
I've tried to apply the preprocess_image() function after the dataset is generated by image_dataset_from_directory, through .map() function, but it does not work either.
Please could anyone advise?
Many thanks,
Tony
train_Gen = dataGen.flow_from_dataframe(
df,
x_col='id_code',
y_col='diagnosis',
directory=os.path.join(data_dir, 'train_images'),
batch_size=BATCH_SIZE,
target_size=(IMG_WIDTH, IMG_HEIGHT),
subset='training',
seed=123,
class_mode='categorical',
**preprocessing=preprocess_image**,
)
def crop_image_from_gray(img, tol=7):
"""
Applies masks to the orignal image and
returns the a preprocessed image with
3 channels
:param img: A NumPy Array that will be cropped
:param tol: The tolerance used for masking
:return: A NumPy array containing the cropped image
"""
# If for some reason we only have two channels
if img.ndim == 2:
mask = img > tol
return img[np.ix_(mask.any(1),mask.any(0))]
# If we have a normal RGB images
elif img.ndim == 3:
gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
mask = gray_img > tol
check_shape = img[:,:,0][np.ix_(mask.any(1),mask.any(0))].shape[0]
if (check_shape == 0): # image is too dark so that we crop out everything,
return img # return original image
else:
img1=img[:,:,0][np.ix_(mask.any(1),mask.any(0))]
img2=img[:,:,1][np.ix_(mask.any(1),mask.any(0))]
img3=img[:,:,2][np.ix_(mask.any(1),mask.any(0))]
img = np.stack([img1,img2,img3],axis=-1)
return img
def preprocess_image(image, sigmaX=10):
"""
The whole preprocessing pipeline:
1. Read in image
2. Apply masks
3. Resize image to desired size
4. Add Gaussian noise to increase Robustness
:param img: A NumPy Array that will be cropped
:param sigmaX: Value used for add GaussianBlur to the image
:return: A NumPy array containing the preprocessed image
"""
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = crop_image_from_gray(image)
image = cv2.resize(image, (IMG_WIDTH, IMG_HEIGHT))
image = cv2.addWeighted (image,4, cv2.GaussianBlur(image, (0,0) ,sigmaX), -4, 128)
return image

Augmentation layers only for specific classes

For the classification task, I would like to apply Augmentation Layers (augmentation), only for specific classes.
The rationale: In case of an unbalanced dataset I would like to improve model performance for classes with a small number of images.
https://www.tensorflow.org/api_docs/python/tf/keras/layers/RandomFlip
One solution would be to use tf.data.Dataset() and a .map() function where you could verify the label in it, therefore performing augmentation only on that specific label.
def process_function(filepath):
label = retrieve_class_label(filepath=filepath)
image = tf.io.read_file(filename=filepath)
image = tf.image.decode_jpeg(image, channels=3)
image = tf.cast(image, tf.float32) / 255.0
image = tf.image.resize(image, [IMAGE_WIDTH, IMAGE_HEIGHT])
# Presume the label is of the form "root_folder/class_name"
label = tf.strings.split(filepath, '\\')[-1]
return image, label
def augment_function(image, label):
if tf.math.equal(class_underrepresented, label):
image = tf.image.random_flip_left_right(image)
return image, label

Feeding tf.data Dataset with multidimensional output to Keras model

I want to feed a tf.data Dataset to a Keras model, but I get the following error:
AttributeError: 'DatasetV1Adapter' object has no attribute 'ndim'
This dataset will be used to solve a segmentation problem, so both input and output will be images (3D tensors)
The dataset is created with this code:
dataset = tf.data.Dataset.list_files(TRAIN_PATH + "*.png",shuffle=False)
def process_path(file_path):
img = tf.io.read_file(file_path)
img = tf.image.decode_png(img, channels=3)
train_image_path=tf.strings.regex_replace(file_path,"image","mask")
mask = tf.io.read_file(train_image_path)
mask = tf.image.decode_png(mask, channels=1)
mask = tf.squeeze(mask)
mask = tf.one_hot(tf.cast(mask, tf.int32), Num_Classes, axis = -1)
return img,mask
dataset = dataset.map(process_path)
dataset = dataset.batch(32,drop_remainder=True)
Taking an item from the dataset shows that I get a tuple containing an input tensor and an output tensor, whose dimensions are correct:
Input: (batch-size, image height, image width, 3 channels)
Output: (batch-size, image height, image width, 4 channels)
When fitting the model I get an error:
model.fit(dataset, epochs = 50)
I've solved the provem moving to Keras 2.4.3 and Tensorflow 2.2
Everything was right but apparently the previous release of Keras did not manage this tf.data correctly.
Here's a tutorial I've found very useful on this.

Read different size and format images to form a queue in Tensorflow

I meet a problem on for Tensorflow. I want to read some bmp and jpeg images to form the queue in Tensorflow. And these images have different size.
The input is image path list and label list.
Currently I use " tf.train.slice_input_producer" (generate queue), "tf.image.decode_image" (read different format image), "tf.image.resize_images" (resize image to same size).
However, here I have some problems. The "tf.image.resize_images" needs image shape but there is no shape from "tf.image.decode_image". If I set fixed image shape manually, there will be error to read some images with different size.
Is there any better way for this issue (read different size and format images in Tensorflow)?
images = tf.convert_to_tensor(image_list)
labels = tf.convert_to_tensor(label_list)
input_queue = tf.train.slice_input_producer([images, labels]) #Slice_input producer shuffles the data by default.
#Decode
image = tf.read_file(input_queue[0])
image = tf.image.decode_image(image, channels=3) # for different format
label = input_queue[1]
image.set_shape([640, 480, 3]) # if I dont set the shape, "tf.image.resize_images" cannot work, if I set it, it is fixed...
image = tf.image.resize_images(image, [160, 120])
image_batch, label_batch = tf.train.batch([image , label], batch_size=batch_size)
return image_batch, label_batch

How do I draw a resized image in TensorFlow?

It seems like images in TensorFlow get transformed to a different kind of image coordinate system after any transformation (e.g. resize) is applied. Drawing the image results in this:
%matplotlib inline
import tensorflow as tf
from matplotlib import pyplot as plt
with tf.device("/cpu:0"):
file_contents = tf.read_file('any_image.png')
image = tf.image.decode_png(file_contents)
image.set_shape([375, 1242, 3])
image = tf.image.resize_images(image, 448, 448)
with tf.Session() as sess:
sess.run(tf.initialize_all_variables())
image_val = sess.run([image])
plt.figure(figsize=(16, 8))
plt.imshow(image_val[0], interpolation='nearest')
plt.show()
plt.close()
If I remove the resize operation it draws the regular image. How do I get matplotlib to draw the resized image correctly or tell Tensorflow to return it to RGB?
Seems like there is no image transformation besides unsigned integer to float. Converting back to unsigned integer fixed the problem.
plt.imshow(image_val[0].astype(np.uint8), interpolation='nearest')