__init__.py 9.95 KB
Newer Older
1
import tensorflow as tf
2
import numpy
3
4
import os
import bob.io.base
5

6
7
8
DEFAULT_FEATURE = {'data': tf.FixedLenFeature([], tf.string),
                   'label': tf.FixedLenFeature([], tf.int64),
                   'key': tf.FixedLenFeature([], tf.string)}
9
10


11
def from_hdf5file_to_tensor(filename):
Tiago de Freitas Pereira's avatar
Tiago de Freitas Pereira committed
12
    import bob.io.image
13
14
    data = bob.io.image.to_matplotlib(bob.io.base.load(filename))
    
Tiago de Freitas Pereira's avatar
Tiago de Freitas Pereira committed
15
    #reshaping to ndim == 3    
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    if data.ndim == 2:
        data = numpy.reshape(data, (data.shape[0], data.shape[1], 1))
    data = data.astype("float32")
    
    return data


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)


37
def append_image_augmentation(image, gray_scale=False,
38
39
40
41
42
43
44
45
                              output_shape=None,
                              random_flip=False,
                              random_brightness=False,
                              random_contrast=False,
                              random_saturation=False,
                              per_image_normalization=True):
    """
    Append to the current tensor some random image augmentation operation
46

47
48
49
    **Parameters**
       gray_scale:
          Convert to gray scale?
50

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
       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)

       per_image_normalization:
           Linearly scales image to have zero mean and unit norm.
68

69
70
71
72
73
74
    """

    # Casting to float32
    image = tf.cast(image, tf.float32)

    if output_shape is not None:
75
        assert len(output_shape) == 2
76
        image = tf.image.resize_image_with_crop_or_pad(image, output_shape[0], output_shape[1])
77

78
79
80
81
    if random_flip:
        image = tf.image.random_flip_left_right(image)

    if random_brightness:
82
        image = tf.image.random_brightness(image, max_delta=0.5)
83
84

    if random_contrast:
85
        image = tf.image.random_contrast(image, lower=0, upper=0.5)
86
87

    if random_saturation:
88
        image = tf.image.random_saturation(image, lower=0, upper=0.5)
89
90
91
92
93
94
95
96
97
98

    if gray_scale:
        image = tf.image.rgb_to_grayscale(image, name="rgb_to_gray")
        #self.output_shape[3] = 1

    # normalizing data
    if per_image_normalization:
        image = tf.image.per_image_standardization(image)

    return image
99
100


101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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


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


162
163
164
165
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.
166

167
168
169
    **Parameters**

      input_data: List of whatever representing the data samples
170

171
172
173
174
175
176
177
      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 = []
178

179
180
181
182
183
184
185
186
187
188
    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)
189
190
    input_labels = numpy.array(input_labels)
    total_samples = input_data.shape[0]
191
192

    # Filtering the samples by label and shuffling all the indexes
193
194
195
196
197
    #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)
198
199

    left_possible_indexes = numpy.random.choice(possible_labels, total_samples, replace=True)
200
    right_possible_indexes = numpy.random.choice(possible_labels, total_samples, replace=True)
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234

    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)


235
        genuine = not genuine
236
    return left_data, right_data, labels
237

238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298

def blocks_tensorflow(images, block_size):
    """Return all non-overlapping blocks of an image using tensorflow
    operations.

    Parameters
    ----------
    images : :any:`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 : :any:`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


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