问题
I have a 3d numpy array. It's an array of 2d square images, all of the same size. my task is to block out a random square patch of the images (set all the pixel values to 0). I can figure out how to do it in the case where i just have 1 image as follows
x = np.random.randint(image_width - size)
y = np.random.randint(image_width - size)
image[x:x + size, y:y + size] = 0
where size is the size of the blocked out area. I'm not sure how to efficiently do this technique to an array of 2d images, where the blocked out patch is randomly generated for each one (not necessarily the same patch blocked out in each image in the array). I'm feeling a bit lost in all the new indexing tools I have to deal with (broadcasting, fancy indexing etc) and was wondering if there was a quick and simple way to do this thanks. My approach at the moment is to simply iterate over each image using a for loop, doing one image at a time but I wondered if numpy is powerful enough to somehow do them all in one fell swoop. I do realize that I need to use
x_array = np.random.randint(image_width - size, size=len(image_array))
y_array = np.random.randint(image_width - size, size=len(image_array))
at some point but I don't know where.
回答1:
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]]])
来源:https://stackoverflow.com/questions/52353944/efficient-way-to-assign-values-into-random-blocks-of-an-array-of-images