Spaces:
Runtime error
Runtime error
| # coding=utf-8 | |
| # Copyright 2021 The Deeplab2 Authors. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| """This file contains functions to preprocess images and labels.""" | |
| import tensorflow as tf | |
| from deeplab2.data.preprocessing import autoaugment_utils | |
| from deeplab2.data.preprocessing import preprocess_utils | |
| # The probability of flipping the images and labels | |
| # left-right during training | |
| _PROB_OF_FLIP = 0.5 | |
| _MEAN_PIXEL = [127.5, 127.5, 127.5] | |
| def _pad_image_and_label(image, label, offset_height, offset_width, | |
| target_height, target_width, ignore_label=None): | |
| """Pads the image and the label to the given size. | |
| Args: | |
| image: A tf.Tensor of shape [height, width, channels]. | |
| label: A tf.Tensor of shape [height, width, 1] or None. | |
| offset_height: The number of rows of zeros to add on top of the image and | |
| label. | |
| offset_width: The number of columns of zeros to add on the left of the image | |
| and label. | |
| target_height: The total height after padding. | |
| target_width: The total width after padding. | |
| ignore_label: The ignore_label for the label. Must only be set when label is | |
| given. | |
| Returns: | |
| The padded image and label as a tuple (padded_image, padded_label). | |
| Raises: | |
| tf.errors.InvalidArgumentError: An error occurs if the padding configuration | |
| is invalid. | |
| ValueError: An error occurs if label is given without an ignore_label. | |
| """ | |
| height = tf.shape(image)[0] | |
| width = tf.shape(image)[1] | |
| original_dtype = image.dtype | |
| if original_dtype not in (tf.float32, tf.float64): | |
| image = tf.cast(image, tf.float32) | |
| bottom_padding = target_height - offset_height - height | |
| right_padding = target_width - offset_width - width | |
| assert_bottom_padding = tf.assert_greater( | |
| bottom_padding, -1, | |
| 'The padding configuration is not valid. Please either increase the ' | |
| 'target size or reduce the padding offset.') | |
| assert_right_padding = tf.assert_greater( | |
| right_padding, -1, 'The padding configuration is not valid. Please either' | |
| ' increase the target size or reduce the padding offset.') | |
| with tf.control_dependencies([assert_bottom_padding, assert_right_padding]): | |
| paddings = [[offset_height, bottom_padding], [offset_width, right_padding], | |
| [0, 0]] | |
| image = image - _MEAN_PIXEL | |
| image = tf.pad(image, paddings) | |
| image = image + _MEAN_PIXEL | |
| image = tf.cast(image, original_dtype) | |
| if label is not None: | |
| if ignore_label is None: | |
| raise ValueError( | |
| 'If a label is given, the ignore label must be set too.') | |
| label = tf.pad(label, paddings, constant_values=ignore_label) | |
| return image, label | |
| def _update_max_resize_value(max_resize_value, crop_size, is_inference=False): | |
| """Checks and may update max_resize_value. | |
| Args: | |
| max_resize_value: A 2-tuple of (height, width), maximum allowed value | |
| after resize. If a single element is given, then height and width | |
| share the same value. None, empty or having 0 indicates no maximum value | |
| will be used. | |
| crop_size: A 2-tuple of (height, width), crop size used. | |
| is_inference: Boolean, whether the model is performing inference or not. | |
| Returns: | |
| Updated max_resize_value. | |
| """ | |
| max_resize_value = preprocess_utils.process_resize_value(max_resize_value) | |
| if max_resize_value is None and is_inference: | |
| # During inference, default max_resize_value to crop size to allow | |
| # model taking input images with larger sizes. | |
| max_resize_value = crop_size | |
| if max_resize_value is None: | |
| return None | |
| if max_resize_value[0] > crop_size[0] or max_resize_value[1] > crop_size[1]: | |
| raise ValueError( | |
| 'Maximum resize value provided (%s) exceeds model crop size (%s)' % | |
| (max_resize_value, crop_size)) | |
| return max_resize_value | |
| def preprocess_image_and_label(image, | |
| label, | |
| crop_height, | |
| crop_width, | |
| prev_image=None, | |
| prev_label=None, | |
| min_resize_value=None, | |
| max_resize_value=None, | |
| resize_factor=None, | |
| min_scale_factor=1., | |
| max_scale_factor=1., | |
| scale_factor_step_size=0, | |
| ignore_label=None, | |
| is_training=True, | |
| autoaugment_policy_name=None): | |
| """Preprocesses the image and label. | |
| Args: | |
| image: A tf.Tensor containing the image with shape [height, width, 3]. | |
| label: A tf.Tensor containing the label with shape [height, width, 1] or | |
| None. | |
| crop_height: The height value used to crop the image and label. | |
| crop_width: The width value used to crop the image and label. | |
| prev_image: An optional tensor of shape [image_height, image_width, 3]. | |
| prev_label: An optional tensor of shape [label_height, label_width, 1]. | |
| min_resize_value: A 2-tuple of (height, width), desired minimum value | |
| after resize. If a single element is given, then height and width share | |
| the same value. None, empty or having 0 indicates no minimum value will | |
| be used. | |
| max_resize_value: A 2-tuple of (height, width), maximum allowed value | |
| after resize. If a single element is given, then height and width | |
| share the same value. None, empty or having 0 indicates no maximum value | |
| will be used. | |
| resize_factor: Resized dimensions are multiple of factor plus one. | |
| min_scale_factor: Minimum scale factor for random scale augmentation. | |
| max_scale_factor: Maximum scale factor for random scale augmentation. | |
| scale_factor_step_size: The step size from min scale factor to max scale | |
| factor. The input is randomly scaled based on the value of | |
| (min_scale_factor, max_scale_factor, scale_factor_step_size). | |
| ignore_label: The label value which will be ignored for training and | |
| evaluation. | |
| is_training: If the preprocessing is used for training or not. | |
| autoaugment_policy_name: String, autoaugment policy name. See | |
| autoaugment_policy.py for available policies. | |
| Returns: | |
| resized_image: The resized input image without other augmentations as a | |
| tf.Tensor. | |
| processed_image: The preprocessed image as a tf.Tensor. | |
| label: The preprocessed groundtruth segmentation label as a tf.Tensor. | |
| Raises: | |
| ValueError: Ground truth label not provided during training. | |
| """ | |
| if is_training and label is None: | |
| raise ValueError('During training, label must be provided.') | |
| image.get_shape().assert_is_compatible_with(tf.TensorShape([None, None, 3])) | |
| # Keep reference to original image. | |
| resized_image = image | |
| if prev_image is not None: | |
| image = tf.concat([image, prev_image], axis=2) | |
| processed_image = tf.cast(image, tf.float32) | |
| processed_prev_image = None | |
| if label is not None: | |
| label.get_shape().assert_is_compatible_with(tf.TensorShape([None, None, 1])) | |
| if prev_label is not None: | |
| label = tf.concat([label, prev_label], axis=2) | |
| label = tf.cast(label, tf.int32) | |
| # Resize image and label to the desired range. | |
| if any([min_resize_value, max_resize_value, not is_training]): | |
| max_resize_value = _update_max_resize_value( | |
| max_resize_value, | |
| crop_size=(crop_height, crop_width), | |
| is_inference=not is_training) | |
| processed_image, label = ( | |
| preprocess_utils.resize_to_range( | |
| image=processed_image, | |
| label=label, | |
| min_size=min_resize_value, | |
| max_size=max_resize_value, | |
| factor=resize_factor, | |
| align_corners=True)) | |
| if prev_image is None: | |
| resized_image = tf.identity(processed_image) | |
| else: | |
| resized_image, _ = tf.split(processed_image, 2, axis=2) | |
| if prev_image is not None: | |
| processed_image, processed_prev_image = tf.split(processed_image, 2, axis=2) | |
| if prev_label is not None: | |
| label, prev_label = tf.split(label, 2, axis=2) | |
| if not is_training: | |
| image_height = tf.shape(processed_image)[0] | |
| image_width = tf.shape(processed_image)[1] | |
| offset_height = 0 | |
| offset_width = 0 | |
| processed_image, label = _pad_image_and_label(processed_image, label, | |
| offset_height, offset_width, | |
| crop_height, crop_width, | |
| ignore_label) | |
| processed_image.set_shape([crop_height, crop_width, 3]) | |
| if label is not None: | |
| label.set_shape([crop_height, crop_width, 1]) | |
| if prev_image is not None: | |
| processed_prev_image, prev_label = _pad_image_and_label( | |
| processed_prev_image, prev_label, offset_height, offset_width, | |
| crop_height, crop_width, ignore_label) | |
| processed_prev_image.set_shape([crop_height, crop_width, 3]) | |
| if prev_label is not None: | |
| prev_label.set_shape([crop_height, crop_width, 1]) | |
| return (resized_image, processed_image, label, processed_prev_image, | |
| prev_label) | |
| # Data augmentation by randomly scaling the inputs. | |
| scale = preprocess_utils.get_random_scale( | |
| min_scale_factor, max_scale_factor, scale_factor_step_size) | |
| processed_image, label = preprocess_utils.randomly_scale_image_and_label( | |
| processed_image, label, scale) | |
| if processed_prev_image is not None: | |
| (processed_prev_image, | |
| prev_label) = preprocess_utils.randomly_scale_image_and_label( | |
| processed_prev_image, prev_label, scale) | |
| # Apply autoaugment if any. | |
| if autoaugment_policy_name: | |
| processed_image, label = _autoaugment_helper( | |
| processed_image, label, ignore_label, autoaugment_policy_name) | |
| if processed_prev_image is not None: | |
| processed_prev_image, prev_label = _autoaugment_helper( | |
| processed_prev_image, prev_label, ignore_label, | |
| autoaugment_policy_name) | |
| # Pad image and label to have dimensions >= [crop_height, crop_width]. | |
| image_height = tf.shape(processed_image)[0] | |
| image_width = tf.shape(processed_image)[1] | |
| target_height = image_height + tf.maximum(crop_height - image_height, 0) | |
| target_width = image_width + tf.maximum(crop_width - image_width, 0) | |
| # Randomly crop the image and label. | |
| def _uniform_offset(margin): | |
| return tf.random.uniform( | |
| [], minval=0, maxval=tf.maximum(margin, 1), dtype=tf.int32) | |
| offset_height = _uniform_offset(crop_height - image_height) | |
| offset_width = _uniform_offset(crop_width - image_width) | |
| processed_image, label = _pad_image_and_label(processed_image, label, | |
| offset_height, offset_width, | |
| target_height, target_width, | |
| ignore_label) | |
| if processed_prev_image is not None: | |
| processed_prev_image, prev_label = _pad_image_and_label( | |
| processed_prev_image, prev_label, offset_height, offset_width, | |
| target_height, target_width, ignore_label) | |
| if processed_prev_image is not None: | |
| (processed_image, label, processed_prev_image, | |
| prev_label) = preprocess_utils.random_crop( | |
| [processed_image, label, processed_prev_image, prev_label], | |
| crop_height, crop_width) | |
| # Randomly left-right flip the image and label. | |
| (processed_image, label, processed_prev_image, prev_label, | |
| _) = preprocess_utils.flip_dim( | |
| [processed_image, label, processed_prev_image, prev_label], | |
| _PROB_OF_FLIP, | |
| dim=1) | |
| else: | |
| processed_image, label = preprocess_utils.random_crop( | |
| [processed_image, label], crop_height, crop_width) | |
| # Randomly left-right flip the image and label. | |
| processed_image, label, _ = preprocess_utils.flip_dim( | |
| [processed_image, label], _PROB_OF_FLIP, dim=1) | |
| return resized_image, processed_image, label, processed_prev_image, prev_label | |
| def _autoaugment_helper(image, label, ignore_label, policy_name): | |
| image = tf.cast(image, tf.uint8) | |
| label = tf.cast(label, tf.int32) | |
| image, label = autoaugment_utils.distort_image_with_autoaugment( | |
| image, label, ignore_label, policy_name) | |
| image = tf.cast(image, tf.float32) | |
| return image, label | |