def _run_single_comparison_test(cls, fname, image_imgaug, image_imgcor, severity, seed): image_imgaug_sum = np.sum(image_imgaug) image_imgcor_sum = np.sum(image_imgcor) image_aug, image_aug_exp = cls._generate_augmented_images( fname, image_imgaug, image_imgcor, severity, seed) # assert that the original image is unchanged, # i.e. it was not augmented in-place assert np.isclose(np.sum(image_imgcor), image_imgcor_sum, rtol=0, atol=1e-4) assert np.isclose(np.sum(image_imgaug), image_imgaug_sum, rtol=0, atol=1e-4) # assert that the functions returned numpy arrays and not PIL images assert ia.is_np_array(image_aug_exp) assert ia.is_np_array(image_aug) assert image_aug.shape == image_imgaug.shape assert image_aug.dtype.name == image_aug_exp.dtype.name atol = 1e-4 # set this to 0.5+1e-4 if output is converted to uint8 assert np.allclose(image_aug, image_aug_exp, rtol=0, atol=atol)
def gate_dtypes(dtypes, allowed, disallowed, augmenter=None): assert len(allowed) > 0 assert ia.is_string(allowed[0]) if len(disallowed) > 0: assert ia.is_string(disallowed[0]) if ia.is_np_array(dtypes): dtypes = [dtypes.dtype] else: dtypes = [np.dtype(dtype) if not ia.is_np_array(dtype) else dtype.dtype for dtype in dtypes] for dtype in dtypes: if dtype.name in allowed: pass elif dtype.name in disallowed: if augmenter is None: raise ValueError("Got dtype '%s', which is a forbidden dtype (%s)." % ( dtype.name, ", ".join(disallowed) )) else: raise ValueError("Got dtype '%s' in augmenter '%s' (class '%s'), which is a forbidden dtype (%s)." % ( dtype.name, augmenter.name, augmenter.__class__.__name__, ", ".join(disallowed) )) else: if augmenter is None: warnings.warn(("Got dtype '%s', which was neither explicitly allowed " + "(%s), nor explicitly disallowed (%s). Generated outputs may contain errors.") % ( dtype.name, ", ".join(allowed), ", ".join(disallowed) )) else: warnings.warn(("Got dtype '%s' in augmenter '%s' (class '%s'), which was neither explicitly allowed " + "(%s), nor explicitly disallowed (%s). Generated outputs may contain errors.") % ( dtype.name, augmenter.name, augmenter.__class__.__name__, ", ".join(allowed), ", ".join(disallowed) ))
def change_dtypes_(images, dtypes, clip=True, round=True): if ia.is_np_array(images): if ia.is_iterable(dtypes): dtypes = normalize_dtypes(dtypes) n_distinct_dtypes = len(set([dt.name for dt in dtypes])) assert len(dtypes) == len(images), ( "If an iterable of dtypes is provided to " "change_dtypes_(), it must contain as many dtypes as " "there are images. Got %d dtypes and %d images." % (len(dtypes), len(images))) assert n_distinct_dtypes == 1, ( "If an image array is provided to change_dtypes_(), the " "provided 'dtypes' argument must either be a single dtype " "or an iterable of N times the *same* dtype for N images. " "Got %d distinct dtypes." % (n_distinct_dtypes, )) dtype = dtypes[0] else: dtype = normalize_dtype(dtypes) result = change_dtype_(images, dtype, clip=clip, round=round) elif ia.is_iterable(images): dtypes = ([normalize_dtype(dtypes)] * len(images) if not isinstance(dtypes, list) else normalize_dtypes(dtypes)) assert len(dtypes) == len(images) result = images for i, (image, dtype) in enumerate(zip(images, dtypes)): assert ia.is_np_array(image) result[i] = change_dtype_(image, dtype, clip=clip, round=round) else: raise Exception("Expected numpy array or iterable of numpy arrays, " "got type '%s'." % (type(images), )) return result
def restore_dtypes_(images, dtypes, clip=True, round=True): if ia.is_np_array(images): if ia.is_iterable(dtypes): assert len(dtypes) > 0 if len(dtypes) > 1: assert all([dtype_i == dtypes[0] for dtype_i in dtypes]) dtypes = dtypes[0] dtypes = np.dtype(dtypes) dtype_to = dtypes if images.dtype.type == dtype_to: result = images else: if round and dtype_to.kind in ["u", "i", "b"]: images = np.round(images) if clip: min_value, _, max_value = get_value_range_of_dtype(dtype_to) images = clip_(images, min_value, max_value) result = images.astype(dtype_to, copy=False) elif ia.is_iterable(images): result = images dtypes = dtypes if not isinstance(dtypes, np.dtype) else [dtypes] * len(images) for i, (image, dtype) in enumerate(zip(images, dtypes)): assert ia.is_np_array(image) result[i] = restore_dtypes_(image, dtype, clip=clip) else: raise Exception("Expected numpy array or iterable of numpy arrays, got type '%s'." % (type(images),)) return result
def restore_dtypes_(images, dtypes, clip=True, round=True): if ia.is_np_array(images): if ia.is_iterable(dtypes): assert len(dtypes) > 0 if len(dtypes) > 1: assert all([dtype_i == dtypes[0] for dtype_i in dtypes]) dtypes = dtypes[0] dtypes = np.dtype(dtypes) dtype_to = dtypes if images.dtype.type == dtype_to: result = images else: if round and dtype_to.kind in ["u", "i", "b"]: images = np.round(images) if clip: min_value, _, max_value = get_value_range_of_dtype(dtype_to) images = np.clip(images, min_value, max_value, out=images) result = images.astype(dtype_to, copy=False) elif ia.is_iterable(images): result = images dtypes = dtypes if not isinstance(dtypes, np.dtype) else [dtypes] * len(images) for i, (image, dtype) in enumerate(zip(images, dtypes)): assert ia.is_np_array(image) result[i] = restore_dtypes_(image, dtype, clip=clip) else: raise Exception( "Expected numpy array or iterable of numpy arrays, got type '%s'." % (type(images), )) return result
def copy_augmentables(augmentables): if ia.is_np_array(augmentables): return np.copy(augmentables) result = [] for augmentable in augmentables: if ia.is_np_array(augmentable): result.append(np.copy(augmentable)) else: result.append(augmentable.deepcopy()) return result
def test_fill_from_augmented_normalized_batch(self): batch = ia.UnnormalizedBatch( images=np.zeros((1, 2, 2, 3), dtype=np.uint8), heatmaps=[np.zeros((2, 2, 1), dtype=np.float32)], segmentation_maps=[np.zeros((2, 2, 1), dtype=np.int32)], keypoints=[[(0, 0)]], bounding_boxes=[[ia.BoundingBox(0, 0, 1, 1)]], polygons=[[ia.Polygon([(0, 0), (1, 0), (1, 1)])]], line_strings=[[ia.LineString([(0, 0), (1, 0)])]]) batch_norm = ia.Batch( images=np.zeros((1, 2, 2, 3), dtype=np.uint8), heatmaps=[ ia.HeatmapsOnImage(np.zeros((2, 2, 1), dtype=np.float32), shape=(2, 2, 3)) ], segmentation_maps=[ ia.SegmentationMapsOnImage(np.zeros((2, 2, 1), dtype=np.int32), shape=(2, 2, 3)) ], keypoints=[ ia.KeypointsOnImage([ia.Keypoint(0, 0)], shape=(2, 2, 3)) ], bounding_boxes=[ ia.BoundingBoxesOnImage([ia.BoundingBox(0, 0, 1, 1)], shape=(2, 2, 3)) ], polygons=[ ia.PolygonsOnImage([ia.Polygon([(0, 0), (1, 0), (1, 1)])], shape=(2, 2, 3)) ], line_strings=[ ia.LineStringsOnImage([ia.LineString([(0, 0), (1, 0)])], shape=(2, 2, 3)) ]) batch_norm.images_aug = batch_norm.images_unaug batch_norm.heatmaps_aug = batch_norm.heatmaps_unaug batch_norm.segmentation_maps_aug = batch_norm.segmentation_maps_unaug batch_norm.keypoints_aug = batch_norm.keypoints_unaug batch_norm.bounding_boxes_aug = batch_norm.bounding_boxes_unaug batch_norm.polygons_aug = batch_norm.polygons_unaug batch_norm.line_strings_aug = batch_norm.line_strings_unaug batch = batch.fill_from_augmented_normalized_batch(batch_norm) assert batch.images_aug.shape == (1, 2, 2, 3) assert ia.is_np_array(batch.heatmaps_aug[0]) assert ia.is_np_array(batch.segmentation_maps_aug[0]) assert batch.keypoints_aug[0][0] == (0, 0) assert batch.bounding_boxes_aug[0][0].x1 == 0 assert batch.polygons_aug[0][0].exterior[0][0] == 0 assert batch.line_strings_aug[0][0].coords[0][0] == 0
def __init__(self, matrix=None, name=None, deterministic=False, random_state=None): super(Convolve, self).__init__(name=name, deterministic=deterministic, random_state=random_state) if matrix is None: self.matrix = None self.matrix_type = "None" elif ia.is_np_array(matrix): ia.do_assert( len(matrix.shape) == 2, "Expected convolution matrix to have 2 axis, got %d (shape %s)." % (len(matrix.shape), matrix.shape)) self.matrix = matrix self.matrix_type = "constant" elif isinstance(matrix, types.FunctionType): self.matrix = matrix self.matrix_type = "function" else: raise Exception( "Expected float, int, tuple/list with 2 entries or StochasticParameter. Got %s." % (type(matrix), ))
def __init__(self, matrix=None, name=None, deterministic=False, random_state=None): super(Convolve, self).__init__(name=name, deterministic=deterministic, random_state=random_state) if matrix is None: self.matrix = None self.matrix_type = "None" elif ia.is_np_array(matrix): assert matrix.ndim == 2, ( "Expected convolution matrix to have exactly two dimensions, " "got %d (shape %s)." % (matrix.ndim, matrix.shape)) self.matrix = matrix self.matrix_type = "constant" elif ia.is_callable(matrix): self.matrix = matrix self.matrix_type = "function" else: raise Exception( "Expected float, int, tuple/list with 2 entries or " "StochasticParameter. Got %s." % (type(matrix), ))
def test_augment_images__hue(self): def augment_images(images, random_state, parents, hooks): assert images[0].dtype.name == "int16" images = np.copy(images) images[..., 0] += 10 return images aug = iaa.WithHueAndSaturation(iaa.Lambda(func_images=augment_images)) # example image image = np.arange(0, 255).reshape((1, 255, 1)).astype(np.uint8) image = np.tile(image, (1, 1, 3)) image[..., 0] += 0 image[..., 1] += 1 image[..., 2] += 2 # compute expected output image_hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV) image_hsv = image_hsv.astype(np.int16) image_hsv[..., 0] = ((image_hsv[..., 0].astype(np.float32) / 180) * 255).astype(np.int16) image_hsv[..., 0] += 10 image_hsv[..., 0] = np.mod(image_hsv[..., 0], 255) image_hsv[..., 0] = ((image_hsv[..., 0].astype(np.float32) / 255) * 180).astype(np.int16) image_hsv = image_hsv.astype(np.uint8) image_expected = cv2.cvtColor(image_hsv, cv2.COLOR_HSV2RGB) assert not np.array_equal(image_expected, image) # augment and verify images_aug = aug.augment_images(np.stack([image, image], axis=0)) assert ia.is_np_array(images_aug) for image_aug in images_aug: assert image_aug.shape == (1, 255, 3) assert np.array_equal(image_aug, image_expected)
def test_to_normalized_batch__all_columns(self): batch = ia.UnnormalizedBatch( images=np.zeros((1, 2, 2, 3), dtype=np.uint8), heatmaps=[np.zeros((2, 2, 1), dtype=np.float32)], segmentation_maps=[np.zeros((2, 2, 1), dtype=np.int32)], keypoints=[[(0, 0)]], bounding_boxes=[[ia.BoundingBox(0, 0, 1, 1)]], polygons=[[ia.Polygon([(0, 0), (1, 0), (1, 1)])]], line_strings=[[ia.LineString([(0, 0), (1, 0)])]]) batch_norm = batch.to_normalized_batch() assert isinstance(batch_norm, ia.Batch) assert ia.is_np_array(batch_norm.images_unaug) assert batch_norm.images_unaug.shape == (1, 2, 2, 3) assert isinstance(batch_norm.heatmaps_unaug[0], ia.HeatmapsOnImage) assert isinstance(batch_norm.segmentation_maps_unaug[0], ia.SegmentationMapsOnImage) assert isinstance(batch_norm.keypoints_unaug[0], ia.KeypointsOnImage) assert isinstance(batch_norm.bounding_boxes_unaug[0], ia.BoundingBoxesOnImage) assert isinstance(batch_norm.polygons_unaug[0], ia.PolygonsOnImage) assert isinstance(batch_norm.line_strings_unaug[0], ia.LineStringsOnImage) assert batch_norm.get_column_names() == [ "images", "heatmaps", "segmentation_maps", "keypoints", "bounding_boxes", "polygons", "line_strings" ]
def project_coords(coords, from_shape, to_shape): """Project coordinates from one image shape to another. This performs a relative projection, e.g. a point at ``60%`` of the old image width will be at ``60%`` of the new image width after projection. Parameters ---------- coords : ndarray or list of tuple of number Coordinates to project. Either an ``(N,2)`` numpy array or a ``list`` containing ``(x,y)`` coordinate ``tuple`` s. from_shape : tuple of int or ndarray Old image shape. to_shape : tuple of int or ndarray New image shape. Returns ------- ndarray Projected coordinates as ``(N,2)`` ``float32`` numpy array. """ if ia.is_np_array(coords): coords = np.copy(coords) return project_coords_(coords, from_shape, to_shape)
def normalize_imglike_shape(shape): """Normalize a shape tuple or image-like ``array`` to a shape tuple. Added in 0.5.0. Parameters ---------- shape : tuple of int or ndarray The input to normalize. May optionally be an array. If it is an array, it must be 2-dimensional (height, width) or 3-dimensional (height, width, channels). Otherwise an error will be raised. Returns ------- tuple of int Shape ``tuple``. """ if isinstance(shape, tuple): return shape assert ia.is_np_array(shape), ("Expected tuple of ints or array, got %s." % (type(shape), )) shape = shape.shape assert len(shape) in [ 2, 3 ], ("Expected image array to be 2-dimensional or 3-dimensional, got " "%d-dimensional input of shape %s." % (len(shape), shape)) return shape
def copy_dtypes_for_restore(images, force_list=False): if ia.is_np_array(images): if force_list: return [images.dtype for _ in sm.xrange(len(images))] else: return images.dtype else: return [image.dtype for image in images]
def test_deepcopy_only_images_provided(self): images = np.zeros((1, 1, 3), dtype=np.uint8) batch = ia.Batch(images=images) observed = batch.deepcopy() for attr_name in observed.__dict__.keys(): if attr_name != "images_unaug": assert getattr(observed, attr_name) is None assert ia.is_np_array(observed.images_unaug)
def normalize_dtype(dtype): assert not isinstance(dtype, list), ( "Expected a single dtype-like, got a list instead.") return ( dtype.dtype if ia.is_np_array(dtype) or ia.is_np_scalar(dtype) else np.dtype(dtype) )
def copy_dtypes_for_restore(images, force_list=False): if ia.is_np_array(images): if force_list: return [images.dtype for _ in sm.xrange(len(images))] else: return images.dtype else: return [image.dtype for image in images]
def _generate_images_description(images): """Generate description for image columns.""" if ia.is_np_array(images): shapes_str = "array, shape %11s" % (str(images.shape),) dtypes_str = "dtype %8s" % (images.dtype.name,) if len(images) == 0: value_range_str = "" elif images.dtype.kind in ["u", "i", "b"]: value_range_str = "value range: %3d to %3d" % ( np.min(images), np.max(images)) else: value_range_str = "value range: %7.4f to %7.4f" % ( np.min(images), np.max(images)) else: stats = _ListOfArraysStats(images) if stats.empty: shapes_str = "" elif stats.all_same_shape: shapes_str = ( "list of %3d arrays\n" "all shape %11s" ) % (len(images), stats.shapes[0],) else: shapes_str = ( "list of %3d arrays\n" "varying shapes\n" "smallest image: %11s\n" "largest image: %11s\n" "height: %3d to %3d\n" "width: %3d to %3d\n" "channels: %1s to %1s" ) % (len(images), stats.smallest_shape, stats.largest_shape, stats.height_min, stats.height_max, stats.width_min, stats.width_max, stats.get_channels_min("None"), stats.get_channels_max("None")) if stats.empty: dtypes_str = "" elif stats.all_same_dtype: dtypes_str = "all dtype %8s" % (stats.dtypes[0],) else: dtypes_str = "dtypes: %s" % (", ".join(stats.unique_dtype_names),) if stats.empty: value_range_str = "" else: value_range_str = "value range: %3d to %3d" if not stats.all_dtypes_intlike: value_range_str = "value range: %6.4f to %6.4f" value_range_str = value_range_str % (stats.value_min, stats.value_max) strs = [shapes_str, dtypes_str, value_range_str] return _join_description_strs(strs)
def test_to_batch_in_augmentation__only_images(self): batch = ia.Batch(images=np.zeros((1, 2, 2, 3), dtype=np.uint8)) batch_inaug = batch.to_batch_in_augmentation() assert isinstance(batch_inaug, ia.BatchInAugmentation) assert ia.is_np_array(batch_inaug.images) assert batch_inaug.images.shape == (1, 2, 2, 3) assert batch_inaug.get_column_names() == ["images"]
def test_to_normalized_batch__only_images(self): batch = ia.UnnormalizedBatch( images=np.zeros((1, 2, 2, 3), dtype=np.uint8)) batch_norm = batch.to_normalized_batch() assert isinstance(batch_norm, ia.Batch) assert ia.is_np_array(batch_norm.images_unaug) assert batch_norm.images_unaug.shape == (1, 2, 2, 3) assert batch_norm.get_column_names() == ["images"]
def gate_dtypes(dtypes, allowed, disallowed, augmenter=None): assert len(allowed) > 0 assert ia.is_string(allowed[0]) if len(disallowed) > 0: assert ia.is_string(disallowed[0]) if ia.is_np_array(dtypes): dtypes = [dtypes.dtype] else: dtypes = [ np.dtype(dtype) if not ia.is_np_array(dtype) else dtype.dtype for dtype in dtypes ] for dtype in dtypes: if dtype.name in allowed: pass elif dtype.name in disallowed: if augmenter is None: raise ValueError( "Got dtype '%s', which is a forbidden dtype (%s)." % (dtype.name, ", ".join(disallowed))) else: raise ValueError( "Got dtype '%s' in augmenter '%s' (class '%s'), which is a forbidden dtype (%s)." % (dtype.name, augmenter.name, augmenter.__class__.__name__, ", ".join(disallowed))) else: if augmenter is None: warnings.warn(( "Got dtype '%s', which was neither explicitly allowed " "(%s), nor explicitly disallowed (%s). Generated outputs may contain errors.." ) % (dtype.name, augmenter.name, augmenter.__class__.__name__, ", ".join(allowed), ", ".join(disallowed))) else: warnings.warn(( "Got dtype '%s' in augmenter '%s' (class '%s'), which was neither explicitly allowed " "(%s), nor explicitly disallowed (%s). Generated outputs may contain errors.." ) % (dtype.name, augmenter.name, augmenter.__class__.__name__, ", ".join(allowed), ", ".join(disallowed)))
def project_coords_(coords, from_shape, to_shape): """Project coordinates from one image shape to another in-place. This performs a relative projection, e.g. a point at ``60%`` of the old image width will be at ``60%`` of the new image width after projection. Added in 0.4.0. Parameters ---------- coords : ndarray or list of tuple of number Coordinates to project. Either an ``(N,2)`` numpy array or a ``list`` containing ``(x,y)`` coordinate ``tuple`` s. from_shape : tuple of int or ndarray Old image shape. to_shape : tuple of int or ndarray New image shape. Returns ------- ndarray Projected coordinates as ``(N,2)`` ``float32`` numpy array. This function may change the input data in-place. """ from_shape = normalize_shape(from_shape) to_shape = normalize_shape(to_shape) if from_shape[0:2] == to_shape[0:2]: return coords from_height, from_width = from_shape[0:2] to_height, to_width = to_shape[0:2] no_zeros_in_shapes = (all( [v > 0 for v in [from_height, from_width, to_height, to_width]])) assert no_zeros_in_shapes, ( "Expected from_shape and to_shape to not contain zeros. Got shapes " "%s (from_shape) and %s (to_shape)." % (from_shape, to_shape)) coords_proj = coords if not ia.is_np_array(coords) or coords.dtype.kind != "f": coords_proj = np.array(coords).astype(np.float32) coords_proj[:, 0] = (coords_proj[:, 0] / from_width) * to_width coords_proj[:, 1] = (coords_proj[:, 1] / from_height) * to_height return coords_proj
def test_mocked(self, mock_pilsh): aug = iaa.pillike.EnhanceSharpness(0.75) image = np.zeros((3, 3, 3), dtype=np.uint8) mock_pilsh.return_value = np.full((3, 3, 3), 128, dtype=np.uint8) image_aug = aug(image=image) assert mock_pilsh.call_count == 1 assert ia.is_np_array(mock_pilsh.call_args_list[0][0][0]) assert np.isclose(mock_pilsh.call_args_list[0][0][1], 0.75, rtol=0, atol=1e-4) assert np.all(image_aug == 128)
def deepcopy_fast(obj): if obj is None: return None if ia.is_single_number(obj) or ia.is_string(obj): return obj if isinstance(obj, list): return [deepcopy_fast(el) for el in obj] if isinstance(obj, tuple): return tuple([deepcopy_fast(el) for el in obj]) if ia.is_np_array(obj): return np.copy(obj) if hasattr(obj, "deepcopy"): return obj.deepcopy() return copylib.deepcopy(obj)
def _augment_arrays_by_samples(cls, arrs, ks, keep_size, resize_func): input_was_array = ia.is_np_array(arrs) input_dtype = arrs.dtype if input_was_array else None arrs_aug = [] for arr, k_i in zip(arrs, ks): arr_aug = np.rot90(arr, k_i) if keep_size and arr.shape != arr_aug.shape and resize_func is not None: arr_aug = resize_func(arr_aug, arr.shape[0:2]) arrs_aug.append(arr_aug) if keep_size and input_was_array: n_shapes = len(set([arr.shape for arr in arrs_aug])) if n_shapes == 1: arrs_aug = np.array(arrs_aug, dtype=input_dtype) return arrs_aug
def change_dtype_(arr, dtype, clip=True, round=True): assert ia.is_np_array(arr), ("Expected array as input, got type %s." % (type(arr), )) dtype = normalize_dtype(dtype) if arr.dtype.name == dtype.name: return arr if round and arr.dtype.kind == "f" and dtype.kind in ["u", "i", "b"]: arr = np.round(arr) if clip: min_value, _, max_value = get_value_range_of_dtype(dtype) arr = clip_(arr, min_value, max_value) return arr.astype(dtype, copy=False)
def _generate_augmented_images(cls, fname, image_imgaug, image_imgcor, severity, seed): func_imgaug = getattr(iaa.imgcorruptlike, "apply_%s" % (fname, )) func_imagecor = functools.partial(corrupt, corruption_name=fname) with iarandom.temporary_numpy_seed(seed): image_aug_exp = func_imagecor(image_imgcor, severity=severity) if not ia.is_np_array(image_aug_exp): image_aug_exp = np.asarray(image_aug_exp) if image_imgcor.ndim == 2: image_aug_exp = image_aug_exp[:, :, 0] elif image_imgcor.shape[-1] == 1: image_aug_exp = image_aug_exp[:, :, 0:1] image_aug = func_imgaug(image_imgaug, severity=severity, seed=seed) return image_aug, image_aug_exp
def test_augment_images__mul_hue_and_mul_saturation(self): # this is almost identical to test_augment_images__mul # only # aug = ... # and # image_hsv[...] *= 1.2 # have been changed aug = iaa.MultiplyHueAndSaturation(mul_hue=1.5, mul_saturation=1.6) # changed # example image image = np.arange(0, 255).reshape((1, 255, 1)).astype(np.uint8) image = np.tile(image, (1, 1, 3)) image[..., 0] += 0 image[..., 1] += 5 image[..., 2] += 10 # compute expected output image_hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV) image_hsv = image_hsv.astype(np.int16) # simulate WithHueAndSaturation image_hsv[..., 0] = ((image_hsv[..., 0].astype(np.float32) / 180) * 255).astype(np.int16) image_hsv = image_hsv.astype(np.float32) # simulate Multiply image_hsv[..., 0] *= 1.5 image_hsv[..., 1] *= 1.6 # changed over __mul image_hsv = np.round(image_hsv).astype(np.int16) image_hsv[..., 0] = np.mod(image_hsv[..., 0], 255) image_hsv[..., 0] = ((image_hsv[..., 0].astype(np.float32) / 255) * 180).astype(np.int16) image_hsv[..., 1] = np.clip(image_hsv[..., 1], 0, 255) image_hsv = image_hsv.astype(np.uint8) image_expected = cv2.cvtColor(image_hsv, cv2.COLOR_HSV2RGB) assert not np.array_equal(image_expected, image) # augment and verify images_aug = aug.augment_images(np.stack([image, image], axis=0)) assert ia.is_np_array(images_aug) for image_aug in images_aug: assert image_aug.shape == (1, 255, 3) diff = np.abs(image_aug.astype(np.int16) - image_expected) assert np.all(diff <= 1)
def _warn_on_suspicious_multi_image_shapes(images): if images is None: return # check if it looks like (H, W, C) instead of (N, H, W) if ia.is_np_array(images): if images.ndim == 3 and images.shape[-1] in [1, 3]: ia.warn("You provided a numpy array of shape %s as a " "multi-image augmentation input, which was interpreted as " "(N, H, W). The last dimension however has value 1 or " "3, which indicates that you provided a single image " "with shape (H, W, C) instead. If that is the case, " "you should use e.g. augmenter(image=<your input>) or " "augment_image(<your input>) -- note the singular 'image' " "instead of 'imageS'. Otherwise your single input image " "will be interpreted as multiple images of shape (H, W) " "during augmentation." % (images.shape, ), category=SuspiciousMultiImageShapeWarning)
def get_minimal_dtype_for_values(values, allowed_kinds, default, allow_bool_as_intlike=True): values_normalized = [] for value in values: if ia.is_np_array(value): values_normalized.extend([np.min(values), np.max(values)]) else: values_normalized.append(value) vmin = np.min(values_normalized) vmax = np.max(values_normalized) possible_kinds = [] if ia.is_single_float(vmin) or ia.is_single_float(vmax): # at least one is a float possible_kinds.append("f") elif ia.is_single_bool(vmin) and ia.is_single_bool(vmax): # both are bools possible_kinds.extend(["b", "u", "i"]) else: # at least one of them is an integer and none is float if vmin >= 0: possible_kinds.append("u") possible_kinds.append("i") # vmin and vmax are already guarantueed to not be float due to if-statement above if allow_bool_as_intlike and 0 <= vmin <= 1 and 0 <= vmax <= 1: possible_kinds.append("b") for allowed_kind in allowed_kinds: if allowed_kind in possible_kinds: dt = get_minimal_dtype_by_value_range(vmin, vmax, allowed_kind, default=None) if dt is not None: return dt if ia.is_string(default) and default == "raise": raise Exception(( "Did not find matching dtypes for vmin=%s (type %s) and vmax=%s (type %s). " + "Got %s input values of types %s.") % (vmin, type(vmin), vmax, type(vmax), ", ".join( [str(type(value)) for value in values]))) return default
def test_to_batch_in_augmentation__all_columns(self): batch = ia.Batch( images=np.zeros((1, 2, 2, 3), dtype=np.uint8), heatmaps=[ ia.HeatmapsOnImage(np.zeros((2, 2, 1), dtype=np.float32), shape=(2, 2, 3)) ], segmentation_maps=[ ia.SegmentationMapsOnImage(np.zeros((2, 2, 1), dtype=np.int32), shape=(2, 2, 3)) ], keypoints=[ ia.KeypointsOnImage([ia.Keypoint(x=0, y=0)], shape=(2, 2, 3)) ], bounding_boxes=[ ia.BoundingBoxesOnImage([ia.BoundingBox(0, 0, 1, 1)], shape=(2, 2, 3)) ], polygons=[ ia.PolygonsOnImage([ia.Polygon([(0, 0), (1, 0), (1, 1)])], shape=(2, 2, 3)) ], line_strings=[ ia.LineStringsOnImage([ia.LineString([(0, 0), (1, 0)])], shape=(2, 2, 3)) ]) batch_inaug = batch.to_batch_in_augmentation() assert isinstance(batch_inaug, ia.BatchInAugmentation) assert ia.is_np_array(batch_inaug.images) assert batch_inaug.images.shape == (1, 2, 2, 3) assert isinstance(batch_inaug.heatmaps[0], ia.HeatmapsOnImage) assert isinstance(batch_inaug.segmentation_maps[0], ia.SegmentationMapsOnImage) assert isinstance(batch_inaug.keypoints[0], ia.KeypointsOnImage) assert isinstance(batch_inaug.bounding_boxes[0], ia.BoundingBoxesOnImage) assert isinstance(batch_inaug.polygons[0], ia.PolygonsOnImage) assert isinstance(batch_inaug.line_strings[0], ia.LineStringsOnImage) assert batch_inaug.get_column_names() == [ "images", "heatmaps", "segmentation_maps", "keypoints", "bounding_boxes", "polygons", "line_strings" ]
def normalize_shape(shape): """Normalize a shape ``tuple`` or ``array`` to a shape ``tuple``. Parameters ---------- shape : tuple of int or ndarray The input to normalize. May optionally be an array. Returns ------- tuple of int Shape ``tuple``. """ if isinstance(shape, tuple): return shape assert ia.is_np_array(shape), ("Expected tuple of ints or array, got %s." % (type(shape), )) return shape.shape
def normalize_shape(shape): """ Normalize a shape tuple or array to a shape tuple. Parameters ---------- shape : tuple of int or ndarray The input to normalize. May optionally be an array. Returns ------- tuple of int Shape tuple. """ if isinstance(shape, tuple): return shape assert ia.is_np_array(shape), ( "Expected tuple of ints or array, got %s." % (type(shape),)) return shape.shape
def get_minimal_dtype_for_values(values, allowed_kinds, default, allow_bool_as_intlike=True): values_normalized = [] for value in values: if ia.is_np_array(value): values_normalized.extend([np.min(values), np.max(values)]) else: values_normalized.append(value) vmin = np.min(values_normalized) vmax = np.max(values_normalized) possible_kinds = [] if ia.is_single_float(vmin) or ia.is_single_float(vmax): # at least one is a float possible_kinds.append("f") elif ia.is_single_bool(vmin) and ia.is_single_bool(vmax): # both are bools possible_kinds.extend(["b", "u", "i"]) else: # at least one of them is an integer and none is float if vmin >= 0: possible_kinds.append("u") possible_kinds.append("i") # vmin and vmax are already guarantueed to not be float due to if-statement above if allow_bool_as_intlike and 0 <= vmin <= 1 and 0 <= vmax <= 1: possible_kinds.append("b") for allowed_kind in allowed_kinds: if allowed_kind in possible_kinds: dt = get_minimal_dtype_by_value_range(vmin, vmax, allowed_kind, default=None) if dt is not None: return dt if ia.is_string(default) and default == "raise": raise Exception(("Did not find matching dtypes for vmin=%s (type %s) and vmax=%s (type %s). " + "Got %s input values of types %s.") % ( vmin, type(vmin), vmax, type(vmax), ", ".join([str(type(value)) for value in values]))) return default
def _augment_images(self, images, random_state, parents, hooks): iadt.gate_dtypes(images, allowed=[ "bool", "uint8", "uint16", "int8", "int16", "float16", "float32", "float64" ], disallowed=[ "uint32", "uint64", "uint128", "uint256", "int32", "int64", "int128", "int256", "float96", "float128", "float256" ], augmenter=self) rss = random_state.duplicate(len(images)) for i, image in enumerate(images): _height, _width, nb_channels = images[i].shape input_dtype = image.dtype if image.dtype.type in [np.bool_, np.float16]: image = image.astype(np.float32, copy=False) elif image.dtype.type == np.int8: image = image.astype(np.int16, copy=False) if self.matrix_type == "None": matrices = [None] * nb_channels elif self.matrix_type == "constant": matrices = [self.matrix] * nb_channels elif self.matrix_type == "function": matrices = self.matrix(images[i], nb_channels, rss[i]) if ia.is_np_array(matrices) and matrices.ndim == 2: matrices = np.tile(matrices[..., np.newaxis], (1, 1, nb_channels)) is_valid_list = (isinstance(matrices, list) and len(matrices) == nb_channels) is_valid_array = (ia.is_np_array(matrices) and matrices.ndim == 3 and matrices.shape[2] == nb_channels) assert is_valid_list or is_valid_array, ( "Callable provided to Convole must return either a " "list of 2D matrices (one per image channel) " "or a 2D numpy array " "or a 3D numpy array where the last dimension's size " "matches the number of image channels. " "Got type %s." % (type(matrices), )) if ia.is_np_array(matrices): # Shape of matrices is currently (H, W, C), but in the # loop below we need the first axis to be the channel # index to unify handling of lists of arrays and arrays. # So we move the channel axis here to the start. matrices = matrices.transpose((2, 0, 1)) else: raise Exception("Invalid matrix type") image_aug = image for channel in sm.xrange(nb_channels): if matrices[channel] is not None: # ndimage.convolve caused problems here cv2.filter2D() # always returns same output dtype as input dtype image_aug[..., channel] = cv2.filter2D(image_aug[..., channel], -1, matrices[channel]) if input_dtype == np.bool_: image_aug = image_aug > 0.5 elif input_dtype in [np.int8, np.float16]: image_aug = iadt.restore_dtypes_(image_aug, input_dtype) images[i] = image_aug return images
def test_deepcopy(self): batch = ia.Batch() observed = batch.deepcopy() keys = list(observed.__dict__.keys()) assert len(keys) >= 14 for attr_name in keys: assert getattr(observed, attr_name) is None batch = ia.Batch(images=np.zeros((1, 1, 3), dtype=np.uint8)) observed = batch.deepcopy() for attr_name in observed.__dict__.keys(): if attr_name != "images_unaug": assert getattr(observed, attr_name) is None assert ia.is_np_array(observed.images_unaug) batch = ia.Batch( images=np.zeros((1, 1, 3), dtype=np.uint8), heatmaps=[ ia.HeatmapsOnImage(np.zeros((1, 1, 1), dtype=np.float32), shape=(4, 4, 3)) ], segmentation_maps=[ ia.SegmentationMapOnImage(np.zeros((1, 1), dtype=np.int32), shape=(5, 5, 3), nb_classes=20) ], keypoints=[ ia.KeypointsOnImage([ia.Keypoint(x=1, y=2)], shape=(6, 6, 3)) ], bounding_boxes=[ ia.BoundingBoxesOnImage([ ia.BoundingBox(x1=1, y1=2, x2=3, y2=4)], shape=(7, 7, 3)) ], polygons=[ ia.PolygonsOnImage([ ia.Polygon([(0, 0), (10, 0), (10, 10)]) ], shape=(100, 100, 3)) ], line_strings=[ ia.LineStringsOnImage([ ia.LineString([(1, 1), (11, 1), (11, 11)]) ], shape=(101, 101, 3)) ], data={"test": 123, "foo": "bar", "test2": [1, 2, 3]} ) observed = batch.deepcopy() for attr_name in observed.__dict__.keys(): if "_unaug" not in attr_name and attr_name != "data": assert getattr(observed, attr_name) is None assert ia.is_np_array(observed.images_unaug) assert observed.images_unaug.shape == (1, 1, 3) assert isinstance(observed.heatmaps_unaug[0], ia.HeatmapsOnImage) assert isinstance(observed.segmentation_maps_unaug[0], ia.SegmentationMapOnImage) assert isinstance(observed.keypoints_unaug[0], ia.KeypointsOnImage) assert isinstance(observed.bounding_boxes_unaug[0], ia.BoundingBoxesOnImage) assert isinstance(observed.polygons_unaug[0], ia.PolygonsOnImage) assert isinstance(observed.line_strings_unaug[0], ia.LineStringsOnImage) assert isinstance(observed.data, dict) assert observed.heatmaps_unaug[0].shape == (4, 4, 3) assert observed.segmentation_maps_unaug[0].shape == (5, 5, 3) assert observed.keypoints_unaug[0].shape == (6, 6, 3) assert observed.bounding_boxes_unaug[0].shape == (7, 7, 3) assert observed.polygons_unaug[0].shape == (100, 100, 3) assert observed.line_strings_unaug[0].shape == (101, 101, 3) assert observed.heatmaps_unaug[0].arr_0to1.shape == (1, 1, 1) assert observed.segmentation_maps_unaug[0].arr.shape == (1, 1, 20) assert observed.keypoints_unaug[0].keypoints[0].x == 1 assert observed.keypoints_unaug[0].keypoints[0].y == 2 assert observed.bounding_boxes_unaug[0].bounding_boxes[0].x1 == 1 assert observed.bounding_boxes_unaug[0].bounding_boxes[0].y1 == 2 assert observed.bounding_boxes_unaug[0].bounding_boxes[0].x2 == 3 assert observed.bounding_boxes_unaug[0].bounding_boxes[0].y2 == 4 assert observed.polygons_unaug[0].polygons[0].exterior[0, 0] == 0 assert observed.polygons_unaug[0].polygons[0].exterior[0, 1] == 0 assert observed.polygons_unaug[0].polygons[0].exterior[1, 0] == 10 assert observed.polygons_unaug[0].polygons[0].exterior[1, 1] == 0 assert observed.polygons_unaug[0].polygons[0].exterior[2, 0] == 10 assert observed.polygons_unaug[0].polygons[0].exterior[2, 1] == 10 assert observed.line_strings_unaug[0].line_strings[0].coords[0, 0] == 1 assert observed.line_strings_unaug[0].line_strings[0].coords[0, 1] == 1 assert observed.line_strings_unaug[0].line_strings[0].coords[1, 0] == 11 assert observed.line_strings_unaug[0].line_strings[0].coords[1, 1] == 1 assert observed.line_strings_unaug[0].line_strings[0].coords[2, 0] == 11 assert observed.line_strings_unaug[0].line_strings[0].coords[2, 1] == 11 assert observed.data["test"] == 123 assert observed.data["foo"] == "bar" assert observed.data["test2"] == [1, 2, 3]