Efficiently Using Multiple Numpy Slices for Random Image Cropping

Efficiently Using Multiple Numpy Slices for Random Image Cropping

Leverage strided-based method for efficient patch extraction

We can leverage np.lib.stride_tricks.as_strided based scikit-image's view_as_windows to get sliding windows that would be merely views into the input array and hence incur no extra memory overhead and virtually free! We can surely use np.lib.stride_tricks.as_strided directly, but the setup work required is hard to manage especially on arrays with higher dimensions. If scikit-image is not available, we can directly use the source code that works standalone.

Explanation on usage of view_as_windows

The idea with view_as_windows is that we feed in the input arg window_shape as a tuple of length same as the number of dimensions in the input array whose sliding windows are needed. The axes along which we need to slide are fed with the respective window lengths and rest are fed with 1s. This would create an array of views with singleton dims/axes i.e. axes with lengths=1 corresponding to the 1s in window_shape arg. So, for those cases we might want to index into the zeroth element corresponding to the axes that are fed 1 as the sliding window lengths to have a squeezed version of the sliding windows.

Thus, we would have a solution, like so -

# Get sliding windows
from skimage.util.shape import view_as_windows
w = view_as_windows(X, (1,16,16,1))[...,0,:,:,0]

# Index and get our specific windows
out = w[np.arange(X.shape[0]),x,y]

# If you need those in the same format as in the posted loopy code
out = out.transpose(0,2,3,1)

Efficient way to assign values into random blocks of an array of images?

We can leverage np.lib.stride_tricks.as_strided based scikit-image's view_as_windows to get sliding windows. More info on use of as_strided based view_as_windows.

from skimage.util.shape import view_as_windows

# Get sliding windows as views
w = view_as_windows(image_array,(1,size,size))[...,0,:,:]

# Index with advanced-indexing into windows array and
# assign into it, thus reassigning into input array directly being views
w[np.arange(len(x_array)),x_array,y_array] = 0

Sample run

Setup inputs -

In [60]: image_array # input array
Out[60]:
array([[[54, 57, 74, 77, 77],
[19, 93, 31, 46, 97],
[80, 98, 98, 22, 68],
[75, 49, 97, 56, 98]],

[[91, 47, 35, 87, 82],
[19, 30, 90, 79, 89],
[57, 74, 92, 98, 59],
[39, 29, 29, 24, 49]],

[[42, 75, 19, 67, 42],
[41, 84, 33, 45, 85],
[65, 38, 44, 10, 10],
[46, 63, 15, 48, 27]]])

In [68]: size
Out[68]: 2

# x and y starting indices for 0s assignments
In [65]: x_array
Out[65]: array([1, 0, 1])

In [66]: y_array
Out[66]: array([2, 2, 0])

Use proposed solution -

In [62]: w = view_as_windows(a,(1,size,size))[...,0,:,:]

In [63]: w[np.arange(len(x_array)),x_array,y_array] = 0

In [64]: image_array # verify
Out[64]:
array([[[54, 57, 74, 77, 77], # start at (1,2)
[19, 93, 0, 0, 97],
[80, 98, 0, 0, 68],
[75, 49, 97, 56, 98]],

[[91, 47, 0, 0, 82], # start at (0,2)
[19, 30, 0, 0, 89],
[57, 74, 92, 98, 59],
[39, 29, 29, 24, 49]],

[[42, 75, 19, 67, 42], # start at (1,0)
[ 0, 0, 33, 45, 85],
[ 0, 0, 44, 10, 10],
[46, 63, 15, 48, 27]]])

How to crop each element of a numpy array with a window size at the same time without looping over each pixel?

You are basically getting sliding windows across the image. We can leverage np.lib.stride_tricks.as_strided based scikit-image's view_as_windows to get sliding windows. More info on use of as_strided based view_as_windows.

from skimage.util.shape import view_as_windows

out = view_as_windows(image,(ws,ws,1)).transpose(0,1,4,3,2,5)[:-1,:-1,...,0]

# Alternatively :
out = view_as_windows(image,(ws,ws,1))[:-1,:-1,...,0].transpose(0,1,4,3,2)

Also note that you are missing out on the last possible window, if you had for i in range(height+1) and for j in range(width+1). To get the same result with our solution, the last indexing step would modify to [...,0] in place of [:-1,:-1,...,0], thus giving us -

out = view_as_windows(image,(ws,ws,1))[...,0].transpose(0,1,4,3,2)

Selecting multiple slices from a numpy array at once

You can use the indexes to select the rows you want into the appropriate shape.
For example:

 data = np.random.normal(size=(100,2,2,2))

# Creating an array of row-indexes
indexes = np.array([np.arange(0,5), np.arange(1,6), np.arange(2,7)])
# data[indexes] will return an element of shape (3,5,2,2,2). Converting
# to list happens along axis 0
data_extractions = list(data[indexes])

np.all(data_extractions[1] == data[1:6])
True

The final comparison is against the original data.

Numpy slicing multiple 2D ranges with an array of indices

We can leverage np.lib.stride_tricks.as_strided based scikit-image's view_as_windows to get sliding windows. More info on use of as_strided based view_as_windows. Then, indexing into those windows with advanced-indexing using those indices from points solves it for us!

from skimage.util.shape import view_as_windows

w = view_as_windows(img,(h,w))
out = w[points[:,0],points[:,1]]

How to slice np array's certain dimention with different start point?

We can leverage np.lib.stride_tricks.as_strided based scikit-image's view_as_windows to get sliding windows. More info on use of as_strided based view_as_windows.

from skimage.util.shape import view_as_windows

# Get all sliding windows along the last axis
w = view_as_windows(data,(1,1,length))[...,0,0,:]

# Index into windows with start indices and slice out singleton dims
out = np.take_along_axis(w,ind[...,None,None],axis=-1)[...,0]

Last step is basically using advanced-indexing into the windows with those start indices. This could be made a bit simpler and might be easier to understand. So, alternatively, we could do -

m,n = ind.shape
I,J = np.ogrid[:m,:n]
out = w[I,J,ind]


Related Topics



Leave a reply



Submit