简体   繁体   中英

numpy - how to slice of an array passed the limit of the array and back to the beginning

在此处输入图像描述

I have an image in a numpy array and I want to take the slice in red.

I expect the output to look like this.

在此处输入图像描述

Imagine the shape is [600,800,3]

I've tried img[200:400,400:900,:] the 900 being higher than the limit hoping it would wrap around but no.

I know i could also take it as two slices and then hstack them, but i cant help think there is a better way?

Its also possible that the slice could overrun horizontally or vertically or both.

Any suggestions?

You could use np.roll() , which does a cyclic permutation / cyclic shift, along the specified axis (or axes)

If the shift happens along just axis1, use:

new_img = np.roll (img, split, axis=1)

where split is the col value at which your image is to be split. The effect of this cyclic shift is exactly as though the image had been split at the specified point on the axis, and the two resulting image-parts have been swapped.

Since you require to shift along axis1, and simultaneously slice along axis0, it would be:

new_img = np.roll (img[low:high,...], split, axis=[0,1])

where low and high are appropriate slice boundaries along axis0.

If a shift can happen along both axes simultaneously (and there is on slicing), it would be:

new_img = np.roll (img, [split_0, split_1], axis=[0,1])

where split_0 is the split point along axis0 and split_1 is the split point along axis1

Note: Somewhat surprisingly, instead of returning a view, roll() returns a copy , which means it may not give much of a speed-advantage, compared to stacking / concatenating.

Try this out:

the_red_slice = np.tile(img, (1, 2, 1))[200:400,400:900,:]

The tile should duplicate the image at the second dimension so you can index into it. The red area should not be greater than the image width to this solution to work. see: numpy docs: tile

Note: Reason for posting this additional answer:

I realized a little late, that, viewing this problem purely as a "shifting" problem isn't fully meeting the requirement, because, after the shift, the length of the image along the shifted axis remains the same as before, while the requirement is that along axis1, both shifting and slicing needs to happen.

Let:

  • L_0 be the length of the image along axis0 (in your example, 600 )
  • L_1 be the length of the image along axis1 (in your example, 800 )
  • low_0:high_0 be the required slice along axis0 (in your example, this is probably 200:500 )
  • low_1:high_1 be the required slice along axis1 (in your example, this was 200:900 )

Solution:

# Re-compute slice-lengths, slice-starts, for both axes
len_0 = (high_0 - low_0) % L_0          # slice-length for axis0
len_1 = (high_1 - low_1) % L_1          # slice-length for axis1
low_0 = (low_0 % L_0)
low_1 = (low_1 % L_1)

new_img = np.roll(img, [-1 * low_0, -1 * low_1], axis=(0,1)) [:len_0, :len_1, :]

Explanation:

What we are essentially doing is the following steps:

  1. Computing the "true" length of the slice along each axis ( len_0 , len_1 )
  2. Up-shifting the image cyclically, by low_0 (the -1 means upwards)
  3. Left-shifting the image cyclically, by low_1 (the -1 means leftwards)
  4. On the shifted image applying the slice :len_0 along axis0, and the slice :len_1 along axis1, and the full slice : for axis2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM