def __call__(self, img: np.ndarray, mode: Optional[Union[NumpyPadMode, str]] = None): """ Args: img: data to be transformed, assuming `img` is channel-first and padding doesn't apply to the channel dim. mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} One of the listed string values or a user supplied function. Defaults to ``self.mode``. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html Raises: ValueError: When ``self.spatial_border`` does not contain ints. ValueError: When ``self.spatial_border`` length is not one of [1, len(spatial_shape), 2*len(spatial_shape)]. """ spatial_shape = img.shape[1:] spatial_border = ensure_tuple(self.spatial_border) if not all(isinstance(b, int) for b in spatial_border): raise ValueError( f"self.spatial_border must contain only ints, got {spatial_border}." ) spatial_border = tuple(max(0, b) for b in spatial_border) if len(spatial_border) == 1: data_pad_width = [(spatial_border[0], spatial_border[0]) for _ in range(len(spatial_shape))] elif len(spatial_border) == len(spatial_shape): data_pad_width = [(spatial_border[i], spatial_border[i]) for i in range(len(spatial_shape))] elif len(spatial_border) == len(spatial_shape) * 2: data_pad_width = [(spatial_border[2 * i], spatial_border[2 * i + 1]) for i in range(len(spatial_shape))] else: raise ValueError( f"Unsupported spatial_border length: {len(spatial_border)}, available options are " f"[1, len(spatial_shape)={len(spatial_shape)}, 2*len(spatial_shape)={2*len(spatial_shape)}]." ) return np.pad( img, [(0, 0)] + data_pad_width, mode=self.mode.value if mode is None else NumpyPadMode(mode).value)
def __init__( self, k: Union[Sequence[int], int], mode: Union[NumpyPadMode, str] = NumpyPadMode.CONSTANT) -> None: """ Args: k: the target k for each spatial dimension. if `k` is negative or 0, the original size is preserved. if `k` is an int, the same `k` be applied to all the input spatial dimensions. mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} One of the listed string values or a user supplied function. Defaults to ``"constant"``. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html See also :py:class:`monai.transforms.SpatialPad` """ self.k = k self.mode: NumpyPadMode = NumpyPadMode(mode)
def __call__(self, img, mode: Optional[Union[NumpyPadMode, str]] = None): """ Args: img: data to be transformed, assuming `img` is channel-first and padding doesn't apply to the channel dim. mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} One of the listed string values or a user supplied function. Defaults to ``self.mode``. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html """ data_pad_width = self._determine_data_pad_width(img.shape[1:]) all_pad_width = [(0, 0)] + data_pad_width if not np.asarray(all_pad_width).any(): # all zeros, skip padding return img else: img = np.pad(img, all_pad_width, mode=self.mode.value if mode is None else NumpyPadMode(mode).value) return img
def __call__(self, img, mode: Optional[Union[NumpyPadMode, str]] = None): """ Args: img: data to be transformed, assuming `img` is channel-first and padding doesn't apply to the channel dim. mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} One of the listed string values or a user supplied function. Defaults to ``self.mode``. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html Raises: ValueError: spatial_border must be int number and can not be less than 0. ValueError: unsupported length of spatial_border definition. """ spatial_shape = img.shape[1:] spatial_border = ensure_tuple(self.spatial_border) for b in spatial_border: if b < 0 or not isinstance(b, int): raise ValueError( "spatial_border must be int number and can not be less than 0." ) if len(spatial_border) == 1: data_pad_width = [(spatial_border[0], spatial_border[0]) for _ in range(len(spatial_shape))] elif len(spatial_border) == len(spatial_shape): data_pad_width = [(spatial_border[i], spatial_border[i]) for i in range(len(spatial_shape))] elif len(spatial_border) == len(spatial_shape) * 2: data_pad_width = [(spatial_border[2 * i], spatial_border[2 * i + 1]) for i in range(len(spatial_shape))] else: raise ValueError( "unsupported length of spatial_border definition.") return np.pad( img, [(0, 0)] + data_pad_width, mode=self.mode.value if mode is None else NumpyPadMode(mode).value)
def __init__( self, spatial_border: Union[Sequence[int], int], mode: Union[NumpyPadMode, str] = NumpyPadMode.CONSTANT) -> None: self.spatial_border = spatial_border self.mode: NumpyPadMode = NumpyPadMode(mode)
def iter_patch( arr: np.ndarray, patch_size: Union[Sequence[int], int] = 0, start_pos: Sequence[int] = (), copy_back: bool = True, mode: Union[NumpyPadMode, str] = NumpyPadMode.WRAP, **pad_opts: Dict, ): """ Yield successive patches from `arr` of size `patch_size`. The iteration can start from position `start_pos` in `arr` but drawing from a padded array extended by the `patch_size` in each dimension (so these coordinates can be negative to start in the padded region). If `copy_back` is True the values from each patch are written back to `arr`. Args: arr: array to iterate over patch_size: size of patches to generate slices for, 0 or None selects whole dimension start_pos: starting position in the array, default is 0 for each dimension copy_back: if True data from the yielded patches is copied back to `arr` once the generator completes mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} One of the listed string values or a user supplied function. Defaults to ``"wrap"``. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html pad_opts: padding options, see `numpy.pad` Yields: Patches of array data from `arr` which are views into a padded array which can be modified, if `copy_back` is True these changes will be reflected in `arr` once the iteration completes. Note: coordinate format is: [1st_dim_start, 1st_dim_end, 2nd_dim_start, 2nd_dim_end, ..., Nth_dim_start, Nth_dim_end]] """ # ensure patchSize and startPos are the right length patch_size_ = get_valid_patch_size(arr.shape, patch_size) start_pos = ensure_tuple_size(start_pos, arr.ndim) # pad image by maximum values needed to ensure patches are taken from inside an image arrpad = np.pad(arr, tuple((p, p) for p in patch_size_), NumpyPadMode(mode).value, **pad_opts) # choose a start position in the padded image start_pos_padded = tuple(s + p for s, p in zip(start_pos, patch_size_)) # choose a size to iterate over which is smaller than the actual padded image to prevent producing # patches which are only in the padded regions iter_size = tuple(s + p for s, p in zip(arr.shape, patch_size_)) for slices in iter_patch_slices(iter_size, patch_size_, start_pos_padded): # compensate original image padding coords_no_pad = tuple((coord.start - p, coord.stop - p) for coord, p in zip(slices, patch_size_)) yield arrpad[slices], np.asarray( coords_no_pad ) # data and coords (in numpy; works with torch loader) # copy back data from the padded image if required if copy_back: slices = tuple(slice(p, p + s) for p, s in zip(patch_size_, arr.shape)) arr[...] = arrpad[slices]
def __init__(self, spatial_border, mode: Union[NumpyPadMode, str] = NumpyPadMode.CONSTANT): self.spatial_border = spatial_border self.mode: NumpyPadMode = NumpyPadMode(mode)