kwarray.util_slices

Utilities related to slicing

References

https://stackoverflow.com/questions/41153803/zero-padding-slice-past-end-of-array-in-numpy

Todo

  • [ ] Could have a kwarray function to expose this inverse slice

    functionality. Also having a top-level call to apply an embedded slice would be good.

Module Contents

Functions

padded_slice(data, slices, pad=None, padkw=None, return_info=False)

Allows slices with out-of-bound coordinates. Any out of bounds coordinate

apply_embedded_slice(data, data_slice, extra_padding, **padkw)

Apply a precomputed embedded slice.

_apply_padding(array, pad_width, **padkw)

Alternative to numpy pad with different short-cut semantics for

embed_slice(slices, data_dims, pad=None)

Embeds a "padded-slice" inside known data dimension.

Attributes

__TODO__

kwarray.util_slices.padded_slice(data, slices, pad=None, padkw=None, return_info=False)

Allows slices with out-of-bound coordinates. Any out of bounds coordinate will be sampled via padding.

Parameters
  • data (Sliceable[T]) – data to slice into. Any channels must be the last dimension.

  • slices (slice | Tuple[slice, …]) – slice for each dimensions

  • ndim (int) – number of spatial dimensions

  • pad (List[int|Tuple]) – additional padding of the slice

  • padkw (Dict) – if unspecified defaults to {'mode': 'constant'}

  • return_info (bool, default=False) – if True, return extra information about the transform.

Note

Negative slices have a different meaning here then they usually do. Normally, they indicate a wrap-around or a reversed stride, but here they index into out-of-bounds space (which depends on the pad mode). For example a slice of -2:1 literally samples two pixels to the left of the data and one pixel from the data, so you get two padded values and one data value.

SeeAlso:

embed_slice - finds the embedded slice and padding

Returns

data_sliced: subregion of the input data (possibly with padding,

depending on if the original slice went out of bounds)

Tuple[Sliceable, Dict] :

data_sliced : as above

transform : information on how to return to the original coordinates

Currently a dict containing:
st_dims: a list indicating the low and high space-time

coordinate values of the returned data slice.

The structure of this dictionary mach change in the future

Return type

Sliceable

Example

>>> data = np.arange(5)
>>> slices = [slice(-2, 7)]
>>> data_sliced = padded_slice(data, slices)
>>> print(ub.repr2(data_sliced, with_dtype=False))
np.array([0, 0, 0, 1, 2, 3, 4, 0, 0])
>>> data_sliced = padded_slice(data, slices, pad=(3, 3))
>>> print(ub.repr2(data_sliced, with_dtype=False))
np.array([0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0, 0])
>>> data_sliced = padded_slice(data, slice(3, 4), pad=[(1, 0)])
>>> print(ub.repr2(data_sliced, with_dtype=False))
np.array([2, 3])
kwarray.util_slices.__TODO__ = Multiline-String
Show Value
 1    - [ ] Could have a kwarray function to expose this inverse slice
 2          functionality. Also having a top-level call to apply an embedded slice
 3          would be good.
 4
 5    chip_index = tuple([slice(tl_y, br_y), slice(tl_x, br_x)])
 6    data_slice, padding = kwarray.embed_slice(chip_index, imdata.shape)
 7    # TODO: could have a kwarray function to expose this inverse slice
 8    # functionality. Also having a top-level call to apply an embedded
 9    # slice would be good
10    inverse_slice = (
11        slice(padding[0][0], imdata.shape[0] - padding[0][1]),
12        slice(padding[1][0], imdata.shape[1] - padding[1][1]),
13    )
14    chip = kwarray.padded_slice(imdata, chip_index)
15    chip = imdata[chip_index]
16
17    fgdata = function(chip)
18
19    # Apply just the data part back to the original
20    imdata[tl_y:br_y, tl_x:br_x, :] = fgdata[inverse_slice]
kwarray.util_slices.apply_embedded_slice(data, data_slice, extra_padding, **padkw)

Apply a precomputed embedded slice.

This is used as a subroutine in padded_slice.

Parameters
  • data (ndarray) – data to slice

  • data_slice (Tuple[slice])

  • extra_padding (Tuple[slice])

Returns

ndarray

kwarray.util_slices._apply_padding(array, pad_width, **padkw)

Alternative to numpy pad with different short-cut semantics for the “pad_width” argument.

Unlike numpy pad, you must specify a (start, stop) tuple for each dimension. The shortcut is that you only need to specify this for the leading dimensions. Any unspecified trailing dimension will get an implicit (0, 0) padding.

TODO: does this get exposed as a public function?

kwarray.util_slices.embed_slice(slices, data_dims, pad=None)

Embeds a “padded-slice” inside known data dimension.

Returns the valid data portion of the slice with extra padding for regions outside of the available dimension.

Given a slices for each dimension, image dimensions, and a padding get the corresponding slice from the image and any extra padding needed to achieve the requested window size.

Todo

  • [ ] Add the option to return the inverse slice

Parameters
  • slices (Tuple[slice, …]) – a tuple of slices for to apply to data data dimension.

  • data_dims (Tuple[int, …]) – n-dimension data sizes (e.g. 2d height, width)

  • pad (List[int|Tuple]) – extra pad applied to (left and right) / (both) sides of each slice dim

Returns

data_slice - Tuple[slice] a slice that can be applied to an array

with with shape data_dims. This slice will not correspond to the full window size if the requested slice is out of bounds.

extra_padding - extra padding needed after slicing to achieve

the requested window size.

Return type

Tuple

Example

>>> # Case where slice is inside the data dims on left edge
>>> from kwarray.util_slices import *  # NOQA
>>> slices = (slice(0, 10), slice(0, 10))
>>> data_dims  = [300, 300]
>>> pad        = [10, 5]
>>> a, b = embed_slice(slices, data_dims, pad)
>>> print('data_slice = {!r}'.format(a))
>>> print('extra_padding = {!r}'.format(b))
data_slice = (slice(0, 20, None), slice(0, 15, None))
extra_padding = [(10, 0), (5, 0)]

Example

>>> # Case where slice is bigger than the image
>>> slices = (slice(-10, 400), slice(-10, 400))
>>> data_dims  = [300, 300]
>>> pad        = [10, 5]
>>> a, b = embed_slice(slices, data_dims, pad)
>>> print('data_slice = {!r}'.format(a))
>>> print('extra_padding = {!r}'.format(b))
data_slice = (slice(0, 300, None), slice(0, 300, None))
extra_padding = [(20, 110), (15, 105)]

Example

>>> # Case where slice is inside than the image
>>> slices = (slice(10, 40), slice(10, 40))
>>> data_dims  = [300, 300]
>>> pad        = None
>>> a, b = embed_slice(slices, data_dims, pad)
>>> print('data_slice = {!r}'.format(a))
>>> print('extra_padding = {!r}'.format(b))
data_slice = (slice(10, 40, None), slice(10, 40, None))
extra_padding = [(0, 0), (0, 0)]