import tensorflow as tf
import numpy
import os
import bob.io.base
DEFAULT_FEATURE = {
"data": tf.FixedLenFeature([], tf.string),
"label": tf.FixedLenFeature([], tf.int64),
"key": tf.FixedLenFeature([], tf.string),
}
[docs]def from_hdf5file_to_tensor(filename):
import bob.io.image
data = bob.io.image.to_matplotlib(bob.io.base.load(filename))
# reshaping to ndim == 3
if data.ndim == 2:
data = numpy.reshape(data, (data.shape[0], data.shape[1], 1))
data = data.astype("float32")
return data
[docs]def from_filename_to_tensor(filename, extension=None):
"""
Read a file and it convert it to tensor.
If the file extension is something that tensorflow understands (.jpg, .bmp, .tif,...),
it uses the `tf.image.decode_image` otherwise it uses `bob.io.base.load`
"""
if extension == "hdf5":
return tf.py_func(from_hdf5file_to_tensor, [filename], [tf.float32])
else:
return tf.cast(tf.image.decode_image(tf.read_file(filename)), tf.float32)
[docs]def append_image_augmentation(
image,
gray_scale=False,
output_shape=None,
random_flip=False,
random_brightness=False,
random_contrast=False,
random_saturation=False,
random_rotate=False,
per_image_normalization=True,
random_gamma=False,
random_crop=False,
):
"""
Append to the current tensor some random image augmentation operation
**Parameters**
gray_scale:
Convert to gray scale?
output_shape:
If set, will randomly crop the image given the output shape
random_flip:
Randomly flip an image horizontally (https://www.tensorflow.org/api_docs/python/tf/image/random_flip_left_right)
random_brightness:
Adjust the brightness of an RGB image by a random factor (https://www.tensorflow.org/api_docs/python/tf/image/random_brightness)
random_contrast:
Adjust the contrast of an RGB image by a random factor (https://www.tensorflow.org/api_docs/python/tf/image/random_contrast)
random_saturation:
Adjust the saturation of an RGB image by a random factor (https://www.tensorflow.org/api_docs/python/tf/image/random_saturation)
random_rotate:
Randomly rotate face images between -5 and 5 degrees
per_image_normalization:
Linearly scales image to have zero mean and unit norm.
"""
# Changing the range from 0-255 to 0-1
image = tf.cast(image, tf.float32) / 255
# FORCING A SEED FOR THE RANDOM OPERATIONS
tf.set_random_seed(0)
if output_shape is not None:
if random_crop:
image = tf.random_crop(image, size=list(output_shape) + [3])
else:
assert len(output_shape) == 2
image = tf.image.resize_image_with_crop_or_pad(
image, output_shape[0], output_shape[1]
)
if random_flip:
image = tf.image.random_flip_left_right(image)
if random_brightness:
image = tf.image.random_brightness(image, max_delta=0.15)
image = tf.clip_by_value(image, 0, 1)
if random_contrast:
image = tf.image.random_contrast(image, lower=0.85, upper=1.15)
image = tf.clip_by_value(image, 0, 1)
if random_saturation:
image = tf.image.random_saturation(image, lower=0.85, upper=1.15)
image = tf.clip_by_value(image, 0, 1)
if random_gamma:
image = tf.image.adjust_gamma(
image, gamma=tf.random.uniform(shape=[], minval=0.85, maxval=1.15)
)
image = tf.clip_by_value(image, 0, 1)
if gray_scale:
image = tf.image.rgb_to_grayscale(image, name="rgb_to_gray")
# normalizing data
if per_image_normalization:
image = tf.image.per_image_standardization(image)
return image
[docs]def arrange_indexes_by_label(input_labels, possible_labels):
# Shuffling all the indexes
indexes_per_labels = dict()
for l in possible_labels:
indexes_per_labels[l] = numpy.where(input_labels == l)[0]
numpy.random.shuffle(indexes_per_labels[l])
return indexes_per_labels
[docs]def triplets_random_generator(input_data, input_labels):
"""
Giving a list of samples and a list of labels, it dumps a series of
triplets for triple nets.
**Parameters**
input_data: List of whatever representing the data samples
input_labels: List of the labels (needs to be in EXACT same order as input_data)
"""
anchor = []
positive = []
negative = []
def append(anchor_sample, positive_sample, negative_sample):
"""
Just appending one element in each list
"""
anchor.append(anchor_sample)
positive.append(positive_sample)
negative.append(negative_sample)
possible_labels = list(set(input_labels))
input_data = numpy.array(input_data)
input_labels = numpy.array(input_labels)
total_samples = input_data.shape[0]
indexes_per_labels = arrange_indexes_by_label(input_labels, possible_labels)
# searching for random triplets
offset_class = 0
for i in range(total_samples):
anchor_sample = input_data[
indexes_per_labels[possible_labels[offset_class]][
numpy.random.randint(
len(indexes_per_labels[possible_labels[offset_class]])
)
],
...,
]
positive_sample = input_data[
indexes_per_labels[possible_labels[offset_class]][
numpy.random.randint(
len(indexes_per_labels[possible_labels[offset_class]])
)
],
...,
]
# Changing the class
offset_class += 1
if offset_class == len(possible_labels):
offset_class = 0
negative_sample = input_data[
indexes_per_labels[possible_labels[offset_class]][
numpy.random.randint(
len(indexes_per_labels[possible_labels[offset_class]])
)
],
...,
]
append(str(anchor_sample), str(positive_sample), str(negative_sample))
# yield anchor, positive, negative
return anchor, positive, negative
[docs]def siamease_pairs_generator(input_data, input_labels):
"""
Giving a list of samples and a list of labels, it dumps a series of
pairs for siamese nets.
**Parameters**
input_data: List of whatever representing the data samples
input_labels: List of the labels (needs to be in EXACT same order as input_data)
"""
# Lists that will be returned
left_data = []
right_data = []
labels = []
def append(left, right, label):
"""
Just appending one element in each list
"""
left_data.append(left)
right_data.append(right)
labels.append(label)
possible_labels = list(set(input_labels))
input_data = numpy.array(input_data)
input_labels = numpy.array(input_labels)
total_samples = input_data.shape[0]
# Filtering the samples by label and shuffling all the indexes
# indexes_per_labels = dict()
# for l in possible_labels:
# indexes_per_labels[l] = numpy.where(input_labels == l)[0]
# numpy.random.shuffle(indexes_per_labels[l])
indexes_per_labels = arrange_indexes_by_label(input_labels, possible_labels)
left_possible_indexes = numpy.random.choice(
possible_labels, total_samples, replace=True
)
right_possible_indexes = numpy.random.choice(
possible_labels, total_samples, replace=True
)
genuine = True
for i in range(total_samples):
if genuine:
# Selecting the class
class_index = left_possible_indexes[i]
# Now selecting the samples for the pair
left = input_data[
indexes_per_labels[class_index][
numpy.random.randint(len(indexes_per_labels[class_index]))
]
]
right = input_data[
indexes_per_labels[class_index][
numpy.random.randint(len(indexes_per_labels[class_index]))
]
]
append(left, right, 0)
# yield left, right, 0
else:
# Selecting the 2 classes
class_index = list()
class_index.append(left_possible_indexes[i])
# Finding the right pair
j = i
# TODO: Lame solution. Fix this
while (
j < total_samples
): # Here is an unidiretinal search for the negative pair
if left_possible_indexes[i] != right_possible_indexes[j]:
class_index.append(right_possible_indexes[j])
break
j += 1
if j < total_samples:
# Now selecting the samples for the pair
left = input_data[
indexes_per_labels[class_index[0]][
numpy.random.randint(len(indexes_per_labels[class_index[0]]))
]
]
right = input_data[
indexes_per_labels[class_index[1]][
numpy.random.randint(len(indexes_per_labels[class_index[1]]))
]
]
append(left, right, 1)
genuine = not genuine
return left_data, right_data, labels
[docs]def blocks_tensorflow(images, block_size):
"""Return all non-overlapping blocks of an image using tensorflow
operations.
Parameters
----------
images : `tf.Tensor`
The input color images. It is assumed that the image has a shape of
[?, H, W, C].
block_size : (int, int)
A tuple of two integers indicating the block size.
Returns
-------
blocks : `tf.Tensor`
All the blocks in the batch dimension. The output will be of
size [?, block_size[0], block_size[1], C].
n_blocks : int
The number of blocks that was obtained per image.
"""
# normalize block_size
block_size = [1] + list(block_size) + [1]
output_size = list(block_size)
output_size[0] = -1
# extract image patches for each color space:
output = []
for i in range(3):
blocks = tf.extract_image_patches(
images[:, :, :, i : i + 1], block_size, block_size, [1, 1, 1, 1], "VALID"
)
if i == 0:
n_blocks = int(numpy.prod(blocks.shape[1:3]))
blocks = tf.reshape(blocks, output_size)
output.append(blocks)
# concatenate the colors back
output = tf.concat(output, axis=3)
return output, n_blocks
[docs]def tf_repeat(tensor, repeats):
"""
Parameters
----------
tensor
A Tensor. 1-D or higher.
repeats
A list. Number of repeat for each dimension, length must be the same as
the number of dimensions in input
Returns
-------
A Tensor. Has the same type as input. Has the shape of tensor.shape *
repeats
"""
with tf.variable_scope("repeat"):
expanded_tensor = tf.expand_dims(tensor, -1)
multiples = [1] + repeats
tiled_tensor = tf.tile(expanded_tensor, multiples=multiples)
repeated_tesnor = tf.reshape(tiled_tensor, tf.shape(tensor) * repeats)
return repeated_tesnor
[docs]def all_patches(image, label, key, size):
"""Extracts all patches of an image
Parameters
----------
image:
The image should be channels_last format and already batched.
label:
The label for the image
key:
The key for the image
size: (int, int)
The height and width of the blocks.
Returns
-------
blocks:
The non-overlapping blocks of size from image and labels and keys are
repeated.
label:
key:
"""
blocks, n_blocks = blocks_tensorflow(image, size)
# duplicate label and key as n_blocks
def repeats(shape):
r = shape.as_list()
for i in range(len(r)):
if i == 0:
r[i] = n_blocks
else:
r[i] = 1
return r
label = tf_repeat(label, repeats(label.shape))
key = tf_repeat(key, repeats(key.shape))
return blocks, label, key