Exemple #1
0
    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)
Exemple #2
0
    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)
Exemple #3
0
 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
Exemple #4
0
    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)
Exemple #5
0
 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)
Exemple #6
0
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]
Exemple #7
0
 def __init__(self,
              spatial_border,
              mode: Union[NumpyPadMode, str] = NumpyPadMode.CONSTANT):
     self.spatial_border = spatial_border
     self.mode: NumpyPadMode = NumpyPadMode(mode)