kwarray.util_slices module¶
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.
- kwarray.util_slices.padded_slice(data, slices, pad=None, padkw=None, return_info=False)[source]¶
Allows slices with out-of-bound coordinates. Any out of bounds coordinate will be sampled via padding.
- Parameters:
data (Sliceable) – 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
>>> import kwarray >>> data = np.arange(5) >>> slices = [slice(-2, 7)]
>>> data_sliced = kwarray.padded_slice(data, slices) >>> print(ub.urepr(data_sliced, with_dtype=False)) np.array([0, 0, 0, 1, 2, 3, 4, 0, 0])
>>> data_sliced = kwarray.padded_slice(data, slices, pad=[(3, 3)]) >>> print(ub.urepr(data_sliced, with_dtype=False)) np.array([0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0, 0])
>>> data_sliced = kwarray.padded_slice(data, slice(3, 4), pad=[(1, 0)]) >>> print(ub.urepr(data_sliced, with_dtype=False)) np.array([2, 3])
- kwarray.util_slices.apply_embedded_slice(data, data_slice, extra_padding, **padkw)[source]¶
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)[source]¶
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)[source]¶
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 (int | List[int | Tuple[int, int]]) – extra pad applied to (start / end) / (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 >>> import kwarray >>> slices = (slice(0, 10), slice(0, 10)) >>> data_dims = [300, 300] >>> pad = [10, 5] >>> a, b = kwarray.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 >>> import kwarray >>> slices = (slice(-10, 400), slice(-10, 400)) >>> data_dims = [300, 300] >>> pad = [10, 5] >>> a, b = kwarray.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 >>> import kwarray >>> slices = (slice(10, 40), slice(10, 40)) >>> data_dims = [300, 300] >>> pad = None >>> a, b = kwarray.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)]
Example
>>> # Test error cases >>> import kwarray >>> import pytest >>> slices = (slice(0, 40), slice(10, 40)) >>> data_dims = [300, 300] >>> with pytest.raises(ValueError): >>> kwarray.embed_slice(slices, data_dims[0:1]) >>> with pytest.raises(ValueError): >>> kwarray.embed_slice(slices[0:1], data_dims) >>> with pytest.raises(ValueError): >>> kwarray.embed_slice(slices, data_dims, pad=[(1, 1)]) >>> with pytest.raises(ValueError): >>> kwarray.embed_slice(slices, data_dims, pad=[1])