From 36ecbed1e0df77b4b640c91bd2a6d82dbddbe80c Mon Sep 17 00:00:00 2001 From: Zaccharie Ramzi Date: Mon, 7 Oct 2019 18:34:17 +0200 Subject: [PATCH 1/8] added plan of what to do --- keras_preprocessing/image/iterator.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/keras_preprocessing/image/iterator.py b/keras_preprocessing/image/iterator.py index f5a9b6cb..adcf1033 100644 --- a/keras_preprocessing/image/iterator.py +++ b/keras_preprocessing/image/iterator.py @@ -226,9 +226,12 @@ def _get_batches_of_transformed_samples(self, index_array): for i, j in enumerate(index_array): img = load_img(filepaths[j], color_mode=self.color_mode, + # TODO: here use None when resizing function is not None target_size=self.target_size, interpolation=self.interpolation) x = img_to_array(img, data_format=self.data_format) + # TODO: here use the custom provided resizing function if not None + # and check that the size corresponds to the target size. # Pillow images should be closed after `load_img`, # but not PIL images. if hasattr(img, 'close'): From 390ef761790b41246853ad92ca100ed915ec2a7d Mon Sep 17 00:00:00 2001 From: Zaccharie Ramzi Date: Tue, 8 Oct 2019 13:54:56 +0200 Subject: [PATCH 2/8] added resizing function to the directory iterator + docs --- keras_preprocessing/image/directory_iterator.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/keras_preprocessing/image/directory_iterator.py b/keras_preprocessing/image/directory_iterator.py index 3f75d835..e03cf31d 100644 --- a/keras_preprocessing/image/directory_iterator.py +++ b/keras_preprocessing/image/directory_iterator.py @@ -60,6 +60,11 @@ class DirectoryIterator(BatchFromFilesMixin, Iterator): If PIL version 1.1.3 or newer is installed, "lanczos" is also supported. If PIL version 3.4.0 or newer is installed, "box" and "hamming" are also supported. By default, "nearest" is used. + resizing_function: function, used to resize the loaded images to the + target size. this will overrule interpolation. If None, then + interpolation will happen. The input is an image in the specified + data format, and the output has to be an image in the specified + data format with the target size. dtype: Dtype to use for generated arrays. """ allowed_class_modes = {'categorical', 'binary', 'sparse', 'input', None} @@ -81,6 +86,7 @@ def __init__(self, follow_links=False, subset=None, interpolation='nearest', + resizing_function=None, dtype='float32'): super(DirectoryIterator, self).set_processing_attrs(image_data_generator, target_size, @@ -90,7 +96,8 @@ def __init__(self, save_prefix, save_format, subset, - interpolation) + interpolation, + resizing_function) self.directory = directory self.classes = classes if class_mode not in self.allowed_class_modes: From adc8f4a404a57ef467020a447d7722bfff978bdd Mon Sep 17 00:00:00 2001 From: Zaccharie Ramzi Date: Tue, 8 Oct 2019 13:55:24 +0200 Subject: [PATCH 3/8] implemented the custom resizing possibility in the iterator, that happens after loading, and added docs --- keras_preprocessing/image/iterator.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/keras_preprocessing/image/iterator.py b/keras_preprocessing/image/iterator.py index adcf1033..eefbcf57 100644 --- a/keras_preprocessing/image/iterator.py +++ b/keras_preprocessing/image/iterator.py @@ -142,7 +142,8 @@ def set_processing_attrs(self, save_prefix, save_format, subset, - interpolation): + interpolation, + resizing_function): """Sets attributes to use later for processing files into a batch. # Arguments @@ -168,6 +169,11 @@ def set_processing_attrs(self, If PIL version 1.1.3 or newer is installed, "lanczos" is also supported. If PIL version 3.4.0 or newer is installed, "box" and "hamming" are also supported. By default, "nearest" is used. + resizing_function: function, used to resize the loaded images to the + target size. this will overrule interpolation. If None, then + interpolation will happen. The input is an image in the specified + data format, and the output has to be an image in the specified + data format with the target size. """ self.image_data_generator = image_data_generator self.target_size = tuple(target_size) @@ -195,6 +201,7 @@ def set_processing_attrs(self, self.save_prefix = save_prefix self.save_format = save_format self.interpolation = interpolation + self.resizing_function = resizing_function if subset is not None: validation_split = self.image_data_generator._validation_split if subset == 'validation': @@ -223,15 +230,21 @@ def _get_batches_of_transformed_samples(self, index_array): # build batch of image data # self.filepaths is dynamic, is better to call it once outside the loop filepaths = self.filepaths + load_target_size = self.target_size + if self.resizing_function is not None: + load_target_size = None for i, j in enumerate(index_array): img = load_img(filepaths[j], color_mode=self.color_mode, - # TODO: here use None when resizing function is not None - target_size=self.target_size, + target_size=load_target_size, interpolation=self.interpolation) x = img_to_array(img, data_format=self.data_format) - # TODO: here use the custom provided resizing function if not None - # and check that the size corresponds to the target size. + x = self.resizing_function(x) + if x.shape[:-1] != self.target_size: + raise ValueError( + 'The loaded image size %s (at %s) does not correspond to' + 'the target size %s' % + (str(x.shape[:-1]), filepaths[j], str(self.target_size))) # Pillow images should be closed after `load_img`, # but not PIL images. if hasattr(img, 'close'): From 78871148683f44b8f04cc31383a282856b306578 Mon Sep 17 00:00:00 2001 From: Zaccharie Ramzi Date: Tue, 8 Oct 2019 14:06:46 +0200 Subject: [PATCH 4/8] added note on kwargs for resizing --- keras_preprocessing/image/iterator.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/keras_preprocessing/image/iterator.py b/keras_preprocessing/image/iterator.py index eefbcf57..9e01947d 100644 --- a/keras_preprocessing/image/iterator.py +++ b/keras_preprocessing/image/iterator.py @@ -239,6 +239,8 @@ def _get_batches_of_transformed_samples(self, index_array): target_size=load_target_size, interpolation=self.interpolation) x = img_to_array(img, data_format=self.data_format) + # NOTE: we could potentially have keyword arguments for the + # resizing function x = self.resizing_function(x) if x.shape[:-1] != self.target_size: raise ValueError( From dad4ade3a1fc640e7d55c7f74406542fefeb4bcf Mon Sep 17 00:00:00 2001 From: Zaccharie Ramzi Date: Tue, 8 Oct 2019 14:36:24 +0200 Subject: [PATCH 5/8] changed the flow from directory interface to expose resizing function --- keras_preprocessing/image/image_data_generator.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/keras_preprocessing/image/image_data_generator.py b/keras_preprocessing/image/image_data_generator.py index 0d3d92a7..eab56407 100644 --- a/keras_preprocessing/image/image_data_generator.py +++ b/keras_preprocessing/image/image_data_generator.py @@ -447,7 +447,8 @@ def flow_from_directory(self, save_format='png', follow_links=False, subset=None, - interpolation='nearest'): + interpolation='nearest', + resizing_function=None): """Takes the path to a directory & generates batches of augmented data. # Arguments @@ -515,6 +516,11 @@ class subdirectories (default: False). supported. If PIL version 3.4.0 or newer is installed, `"box"` and `"hamming"` are also supported. By default, `"nearest"` is used. + resizing_function: function, used to resize the loaded images to the + target size. this will overrule interpolation. If None, then + interpolation will happen. The input is an image in the specified + data format, and the output has to be an image in the specified + data format with the target size. # Returns A `DirectoryIterator` yielding tuples of `(x, y)` @@ -539,7 +545,8 @@ class subdirectories (default: False). follow_links=follow_links, subset=subset, interpolation=interpolation, - dtype=self.dtype + dtype=self.dtype, + resizing_function=resizing_function ) def flow_from_dataframe(self, From c7749afbc57678f8b17b00c290732710643f6b67 Mon Sep 17 00:00:00 2001 From: Zaccharie Ramzi Date: Fri, 11 Oct 2019 16:34:43 +0200 Subject: [PATCH 6/8] corrected size checking in image loading --- keras_preprocessing/image/iterator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/keras_preprocessing/image/iterator.py b/keras_preprocessing/image/iterator.py index 9e01947d..39a36aa2 100644 --- a/keras_preprocessing/image/iterator.py +++ b/keras_preprocessing/image/iterator.py @@ -242,11 +242,11 @@ def _get_batches_of_transformed_samples(self, index_array): # NOTE: we could potentially have keyword arguments for the # resizing function x = self.resizing_function(x) - if x.shape[:-1] != self.target_size: + if x.shape != self.image_shape: raise ValueError( - 'The loaded image size %s (at %s) does not correspond to' - 'the target size %s' % - (str(x.shape[:-1]), filepaths[j], str(self.target_size))) + 'The loaded image shape %s (at %s) does not correspond to' + 'the specified image shape %s' % + (str(x.shape), filepaths[j], str(self.image_shape))) # Pillow images should be closed after `load_img`, # but not PIL images. if hasattr(img, 'close'): From 90229596942d5f792e28fdc90d057b80697b6034 Mon Sep 17 00:00:00 2001 From: Zaccharie Ramzi Date: Mon, 18 Nov 2019 10:40:30 +0100 Subject: [PATCH 7/8] corrected PR errors --- keras_preprocessing/image/dataframe_iterator.py | 4 +++- keras_preprocessing/image/iterator.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/keras_preprocessing/image/dataframe_iterator.py b/keras_preprocessing/image/dataframe_iterator.py index 5412df24..50773ccc 100644 --- a/keras_preprocessing/image/dataframe_iterator.py +++ b/keras_preprocessing/image/dataframe_iterator.py @@ -109,6 +109,7 @@ def __init__(self, save_format='png', subset=None, interpolation='nearest', + resizing_function=None, dtype='float32', validate_filenames=True): @@ -120,7 +121,8 @@ def __init__(self, save_prefix, save_format, subset, - interpolation) + interpolation, + resizing_function) df = dataframe.copy() self.directory = directory or '' self.class_mode = class_mode diff --git a/keras_preprocessing/image/iterator.py b/keras_preprocessing/image/iterator.py index 39a36aa2..ada7ecb4 100644 --- a/keras_preprocessing/image/iterator.py +++ b/keras_preprocessing/image/iterator.py @@ -241,7 +241,8 @@ def _get_batches_of_transformed_samples(self, index_array): x = img_to_array(img, data_format=self.data_format) # NOTE: we could potentially have keyword arguments for the # resizing function - x = self.resizing_function(x) + if self.resizing_function is not None: + x = self.resizing_function(x) if x.shape != self.image_shape: raise ValueError( 'The loaded image shape %s (at %s) does not correspond to' From e1acacec772445c517f5d383ddc205da2ff4af07 Mon Sep 17 00:00:00 2001 From: Zaccharie Ramzi Date: Mon, 18 Nov 2019 18:45:12 +0100 Subject: [PATCH 8/8] added docs for the resizing function in dataframe iterator --- keras_preprocessing/image/dataframe_iterator.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/keras_preprocessing/image/dataframe_iterator.py b/keras_preprocessing/image/dataframe_iterator.py index 50773ccc..dfc0b9a8 100644 --- a/keras_preprocessing/image/dataframe_iterator.py +++ b/keras_preprocessing/image/dataframe_iterator.py @@ -80,6 +80,11 @@ class DataFrameIterator(BatchFromFilesMixin, Iterator): If PIL version 1.1.3 or newer is installed, "lanczos" is also supported. If PIL version 3.4.0 or newer is installed, "box" and "hamming" are also supported. By default, "nearest" is used. + resizing_function: function, used to resize the loaded images to the + target size. this will overrule interpolation. If None, then + interpolation will happen. The input is an image in the specified + data format, and the output has to be an image in the specified + data format with the target size. dtype: Dtype to use for the generated arrays. validate_filenames: Boolean, whether to validate image filenames in `x_col`. If `True`, invalid images will be ignored. Disabling this option