ICML2022/resefa
4
1# python3.72"""Contains utility functions used for formatting."""3 4import cv25import numpy as np6 7__all__ = [8 'format_time', 'format_range', 'format_image_size', 'format_image',9 'raw_label_to_one_hot', 'one_hot_to_raw_label'10]11 12 13def format_time(seconds):14 """Formats seconds to readable time string.15 16 Args:17 seconds: Number of seconds to format.18 19 Returns:20 The formatted time string.21 22 Raises:23 ValueError: If the input `seconds` is less than 0.24 """25 if seconds < 0:26 raise ValueError(f'Input `seconds` should be greater than or equal to '27 f'0, but `{seconds}` is received!')28 29 # Returns seconds as float if less than 1 minute.30 if seconds < 10:31 return f'{seconds:7.3f} s'32 if seconds < 60:33 return f'{seconds:7.2f} s'34 35 seconds = int(seconds + 0.5)36 days, seconds = divmod(seconds, 86400)37 hours, seconds = divmod(seconds, 3600)38 minutes, seconds = divmod(seconds, 60)39 if days:40 return f'{days:2d} d {hours:02d} h'41 if hours:42 return f'{hours:2d} h {minutes:02d} m'43 return f'{minutes:2d} m {seconds:02d} s'44 45 46def format_range(obj, min_val=None, max_val=None):47 """Formats the given object to a valid range.48 49 If `min_val` or `max_val` is provided, both the starting value and the end50 value will be clamped to range `[min_val, max_val]`.51 52 NOTE: (a, b) is regarded as a valid range if and only if `a <= b`.53 54 Args:55 obj: The input object to format.56 min_val: The minimum value to cut off the input range. If not provided,57 the default minimum value is negative infinity. (default: None)58 max_val: The maximum value to cut off the input range. If not provided,59 the default maximum value is infinity. (default: None)60 61 Returns:62 A two-elements tuple, indicating the start and the end of the range.63 64 Raises:65 ValueError: If the input object is an invalid range.66 """67 if not isinstance(obj, (tuple, list)):68 raise ValueError(f'Input object must be a tuple or a list, '69 f'but `{type(obj)}` received!')70 if len(obj) != 2:71 raise ValueError(f'Input object is expected to contain two elements, '72 f'but `{len(obj)}` received!')73 if obj[0] > obj[1]:74 raise ValueError(f'The second element is expected to be equal to or '75 f'greater than the first one, '76 f'but `({obj[0]}, {obj[1]})` received!')77 78 obj = list(obj)79 if min_val is not None:80 obj[0] = max(obj[0], min_val)81 obj[1] = max(obj[1], min_val)82 if max_val is not None:83 obj[0] = min(obj[0], max_val)84 obj[1] = min(obj[1], max_val)85 return tuple(obj)86 87 88def format_image_size(size):89 """Formats the given image size to a two-element tuple.90 91 A valid image size can be an integer, indicating both the height and the92 width, OR can be a two-element list or tuple. Both height and width are93 assumed to be positive integer.94 95 Args:96 size: The input size to format.97 98 Returns:99 A two-elements tuple, indicating the height and the width, respectively.100 101 Raises:102 ValueError: If the input size is invalid.103 """104 if not isinstance(size, (int, tuple, list)):105 raise ValueError(f'Input size must be an integer, a tuple, or a list, '106 f'but `{type(size)}` received!')107 if isinstance(size, int):108 size = (size, size)109 else:110 if len(size) == 1:111 size = (size[0], size[0])112 if not len(size) == 2:113 raise ValueError(f'Input size is expected to have two numbers at '114 f'most, but `{len(size)}` numbers received!')115 if not isinstance(size[0], int) or size[0] < 0:116 raise ValueError(f'The height is expected to be a non-negative '117 f'integer, but `{size[0]}` received!')118 if not isinstance(size[1], int) or size[1] < 0:119 raise ValueError(f'The width is expected to be a non-negative '120 f'integer, but `{size[1]}` received!')121 return tuple(size)122 123 124def format_image(image):125 """Formats an image read from `cv2`.126 127 NOTE: This function will always return a 3-dimensional image (i.e., with128 shape [H, W, C]) in pixel range [0, 255]. For color images, the channel129 order of the input is expected to be with `BGR` or `BGRA`, which is the130 raw image decoded by `cv2`; while the channel order of the output is set to131 `RGB` or `RGBA` by default.132 133 Args:134 image: `np.ndarray`, an image read by `cv2.imread()` or135 `cv2.imdecode()`.136 137 Returns:138 An image with shape [H, W, C] (where `C = 1` for grayscale image).139 """140 if image.ndim == 2: # add additional axis if given a grayscale image141 image = image[:, :, np.newaxis]142 143 assert isinstance(image, np.ndarray)144 assert image.dtype == np.uint8145 assert image.ndim == 3 and image.shape[2] in [1, 3, 4]146 147 if image.shape[2] == 3: # BGR image148 return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)149 if image.shape[2] == 4: # BGRA image150 return cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA)151 return image152 153 154def raw_label_to_one_hot(raw_label, num_classes):155 """Converts a single label into one-hot vector.156 157 Args:158 raw_label: The raw label.159 num_classes: Total number of classes.160 161 Returns:162 one-hot vector of the given raw label.163 """164 one_hot = np.zeros(num_classes, dtype=np.float32)165 one_hot[raw_label] = 1.0166 return one_hot167 168 169def one_hot_to_raw_label(one_hot):170 """Converts a one-hot vector to a single value label.171 172 Args:173 one_hot: `np.ndarray`, a one-hot encoded vector.174 175 Returns:176 A single integer to represent the category.177 """178 return np.argmax(one_hot)179 