image_utilities.py 11.5 KB
Newer Older
Aleksis's avatar
Aleksis committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
"""
 image_utilities.py (author: Anson Wong / git: ankonzoid)

 Image utilities class that helps with image data IO and processing.
"""
import os, glob, random, errno
import numpy as np
import scipy.misc
from multiprocessing import Pool


class ImageUtils(object):

    def __init__(self):
        # Run settings
        self.img_shape = None
        self.flatten_before_encode = False

        # Directories
        self.query_dir = None
        self.answer_dir = None

        self.img_train_raw_dir = None
        self.img_inventory_raw_dir = None
        self.img_train_dir = None
        self.img_inventory_dir = None


    ############################################################
    ###
    ###
    ### External functions
    ###
    ###
    ############################################################

    """
     Set configuration
    """
    def configure(self, info):
        # Run settings
        self.img_shape = info["img_shape"]
        self.flatten_before_encode = info["flatten_before_encode"]

        # Directories
        self.query_dir = info["query_dir"]
        self.answer_dir = info["answer_dir"]

        self.img_train_raw_dir = info["img_train_raw_dir"]
        self.img_inventory_raw_dir = info["img_inventory_raw_dir"]
        self.img_train_dir = info["img_train_dir"]
        self.img_inventory_dir = info["img_inventory_dir"]


    """
     Load raw images from a given directory, resize them, and save them
    """
    def raw2resized_load_save(self, raw_dir=None, processed_dir=None, img_shape=None):

        (ypixels_force, xpixels_force) = img_shape
        gray_scale = False

        # Extract filenames from dir
        raw_filenames_list, n_files = self.extract_filenames(raw_dir, 1)

        for i, raw_filename in enumerate(raw_filenames_list):

            # Read raw image
            img_raw = self.read_img(raw_filename, gray_scale=gray_scale)

            # Process image
            img_resized = self.force_resize_img(img_raw, ypixels_force, xpixels_force)

            # Save processed image
            name, tag = self.extract_name_tag(raw_filename)
            processed_shortname = name + "_resized." + tag
            processed_filename = os.path.join(processed_dir, processed_shortname)
            self.save_img(img_resized, processed_filename)

            # Print process progress
81
82
            # print("[{0}/{1}] Resized and saved to '{2}'...".format(
            #     i+1, n_files, processed_filename))
Aleksis's avatar
Aleksis committed
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

    """
     Read a raw directory of images, and load as numpy array to memory
    """
    def raw2resizednorm_load(self, raw_dir=None, img_shape=None):

        (ypixels_force, xpixels_force) = img_shape
        gray_scale = False

        # Extract filenames from dir
        raw_filenames_list, n_files = self.extract_filenames(raw_dir, 1)

        img_list = []
        for i, raw_filename in enumerate(raw_filenames_list):

            # Read raw image
            img_raw = self.read_img(raw_filename, gray_scale=gray_scale)

            # Resize image (if not of shape (ypixels_force, xpixels_force))
            img_resized = img_raw
            if img_raw.shape[:2] != img_shape:
                img_resized = self.force_resize_img(img_resized, ypixels_force, xpixels_force)

            # Normalize image
            img_resizednorm = self.normalize_img_data(img_resized)

            # Append processed image to image list
            img_list.append(img_resizednorm)

            # Print process progress
113
114
            # print("[{0}/{1}] Loaded and processed '{2}'...".format(
            #     i + 1, n_files, raw_filename))
Aleksis's avatar
Aleksis committed
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
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
235
236
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
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340

        # Convert image list to numpy array
        img_list = np.array(img_list)

        # Make tests
        if img_list.shape[0] != n_files:
            raise Exception("Inconsistent number of loading images!")
        if img_list.shape[1] != ypixels_force:
            raise Exception("Inconsistent ypixels loading images!")
        if img_list.shape[2] != xpixels_force:
            raise Exception("Inconsistent xpixels loading images!")
        if img_list.shape[3] != 3:
            raise Exception("Inconsistent RGB loading images!")

        return img_list, raw_filenames_list

    """
     Split image data set to training and test set using a seeded psuedo 
     random number generator
    """
    def split_train_test(self, x_data, ratio_train_test, seed):

        # Find number of examples we have
        n = len(x_data)

        # Generate a list of random [0,1] numbers
        random.seed(a = seed)
        r_list = [random.random() for x in range(n)]

        # Perform splitting given our splitting ratio
        x_data_train = []; x_data_test = []
        index_train = []; index_test = []
        for i in range(n):

            # Assign to training if: r_list[i] < ratio_train_test
            # Assign to test data if: r_list[i] >= ratio_train_test
            if r_list[i] < ratio_train_test:
                x_data_train.append(x_data[i])
                index_train.append(i)
            else:
                x_data_test.append(x_data[i])
                index_test.append(i)

        # Convert to numpy arrays
        x_data_train = np.array(x_data_train, dtype=float)
        x_data_test = np.array(x_data_test, dtype=float)
        index_train = np.array(index_train, dtype=int)
        index_test = np.array(index_test, dtype=int)

        # Make checks that the sets are not empty
        if len(x_data_train) == 0:
            raise Exception("Split train set is empty!")
        if len(x_data_test) == 0:
            raise Exception("Split test set is empty!")

        return x_data_train, x_data_test, index_train, index_test

    ############################################################
    ###
    ###
    ### Internal functions
    ###
    ###
    ############################################################


    ### =============================================
    ### Load image IO
    ### =============================================

    """
     Read image (grayscale/RGB)
    """
    def read_img(self, img_filename, gray_scale=False):
        if gray_scale:
            img = np.array(scipy.misc.imread(img_filename, flatten=gray_scale))
        else:
            img = np.array(scipy.misc.imread(img_filename, mode='RGB'))
        return img

    """
     This function is to be paired with Pool
    """
    def _read_img_parallel(self, zipped_enumerated_filenames_list):
        filenames_list, gray_scale = zipped_enumerated_filenames_list
        print("Reading {0} (gray_scale={1})".format(filenames_list, gray_scale))
        img = self.read_img(filenames_list, gray_scale=gray_scale)  # greyscale image (img.shape[0]=y, img.shape[1]=x)
        return img

    """
     Load images from directory (parallelized to cores)
    """
    def load_images_parallel(self, dir, ratio_training_test, seed, n_cores):
        frac_training_use = 1
        gray_scale = False
        index_train = []; index_test = []
        x_train = []; x_test = []
        filenames_list, n_files = self.extract_filenames(dir, frac_training_use)

        # Set up seed, and create a list of pre-determined random numbers (between [0,1]) following this seed
        random.seed(a = seed)
        r_list = [random.random() for x in range(n_files)]  # list of pseudo random [0,1]'s

        # Read images in parallel
        gray_scale_vec = [gray_scale] * n_files
        pool = Pool(n_cores)
        img_list = pool.map(self._read_img_parallel, zip(filenames_list, gray_scale_vec))  # pool.map(f, input_f)
        pool.close()  # close the pool
        pool.join()  # join the pool
        img_mat = np.array(img_list)
        ypixels_data = img_mat.shape[1]
        xpixels_data = img_mat.shape[2]

        # Append each sample to the training or test set
        for i in range(len(img_mat)):
            if r_list[i] < ratio_training_test:
                x_train.append(img_mat[i])
                index_train.append(i)
            else:
                x_test.append(img_mat[i])
                index_test.append(i)

        # Depending on gray_scale, we reshape to 3 or 4 dimensional array
        if gray_scale:
            x_train = np.array(x_train).reshape((-1, ypixels_data, xpixels_data))  # convert to 3-dim numpy
            x_test = np.array(x_test).reshape((-1, ypixels_data, xpixels_data))  # convert to 3-dim numpy
        else:
            x_train = np.array(x_train).reshape((-1, ypixels_data, xpixels_data, 3))  # convert to 4-dim numpy
            x_test = np.array(x_test).reshape((-1, ypixels_data, xpixels_data, 3))  # convert to 4-dim numpy

        index_train = np.array(index_train, dtype=int)
        index_test = np.array(index_test, dtype=int)
        return x_train, x_test, index_train, index_test, filenames_list


    ### =============================================
    ### Save image IO
    ### =============================================

    """
     Save image to a directory
      - If img.shape = (ypixels, xpixels), outputs greyscaled image
      - If img.shape = (ypixels, xpixels, 3), outputs RGB image
    """
    def save_img(self, img, save_filename):
        scipy.misc.imsave(save_filename, img)
        return

    ### =============================================
    ### Image processing
    ### =============================================

    """
     Flatten image data and flatten pixel dimensions
    """
    def flatten_img_data(self, x_data):
        n_data = x_data.shape[0]
        flatten_dim = np.prod(x_data.shape[1:])
        x_data_flatten = x_data.reshape((n_data, flatten_dim))
        return x_data_flatten

    """
     Normalize image data (no reshaping)
    """
    def normalize_img_data(self, x_data):
        x_data_norm = x_data.astype('float32') / 255.  # normalize values [0,1]
        return x_data_norm

    """
     Force resize image data to given (ypixels, xpixels)
    """
    def force_resize_img(self, img, ypixels_force, xpixels_force):
        img_resized = np.array(scipy.misc.imresize(img, (ypixels_force, xpixels_force)))
        return img_resized


    ### =============================================
    ### Filename IO
    ### =============================================

    """
     Extract name and tag from a filename
    """
    def extract_name_tag(self, full_filename):
        shortname = full_filename[full_filename.rfind("/") + 1:]  # filename (within its last directory)
        shortname_split = shortname.split('.')
        name = ''
        n_splits = len(shortname_split)
        for i, x in enumerate(shortname_split):
            if i == 0:
                name = name + x
            elif i == n_splits - 1:
                break
            else:
                name = name + '.' + x
        tag = shortname_split[-1]
        return name, tag

    """
     Extract all filenames inside a given directory (with fraction option):
      - list of filenames
    """
    def extract_filenames(self, dir, frac_take):
        filenames_list = glob.glob(dir + "/*")
        n_files = len(filenames_list)
        if n_files == 0:
            raise Exception("There are no files in {0}!".format(dir))
        if frac_take != 1:
            n_files = int(frac_take * n_files)
            filenames_list = filenames_list[:n_files]
        return filenames_list, n_files

    ### =============================================
    ### Directory IO
    ### =============================================

    """
     Force make directory
    """
    def make_dir(self, dir):
        try:
            os.makedirs(dir)
        except OSError as exception:
            if exception.errno != errno.EEXIST:
                raise Exception("Unexpected error in making directory!")