I need to create stochastic boolean masks for a set of images. Each mask is an array of 1s with 6 random squares, in which the values are 0. The length of the squares are 56 pixels. The mask can be created with the following code:
mask = np.ones(shape=(3, h, w))
for _ in range(6):
x_coordinate = np.random.randint(0, w)
y_coordinate = np.random.randint(0, h)
mask[:, x_coordinate: x_coordinate + 56, y_coordinate: y_coordinate + 56] = 0
Now the tricky thing that I want to do is vectorize this process for a batch of images. Is this even possible? Right now, I'm just calling this function using a simple for-loop for each image in my batch, but I was wondering if there was a way to avoid the for-loop altogether.
ALSO: the mask must be different for each image in the batch (can't use the same mask for each image)
We can leverage np.lib.stride_tricks.as_strided based scikit-image's view_as_windows to get sliding windows and hence solve our case here. More info on use of as_strided based view_as_windows.
Being views-based, it would be as efficient as it can get!
from skimage.util.shape import view_as_windows
N = 3 # number of images in the batch
image_H,image_W = 5,7 # edit to image height, width
bbox_H,bbox_W = 2,3 # edit to window height, width to be set as 0s
w_off = image_W-bbox_W+1
h_off = image_H-bbox_H+1
M = w_off*h_off
R,C = np.unravel_index(np.random.choice(M, size=N, replace=False), (h_off, w_off))
mask_out = np.ones(shape=(N, image_H, image_W), dtype=bool)
win = view_as_windows(mask_out, (1, bbox_H,bbox_W))[...,0,:,:]
win[np.arange(len(R)),R,C] = 0
If you don't mind duplicate masks, simply use replace=True in the code.
Sample output with given input parameters -
In [6]: mask_out
Out[6]:
array([[[ True, True, True, True, True, True, True],
[ True, True, False, False, False, True, True],
[ True, True, False, False, False, True, True],
[ True, True, True, True, True, True, True],
[ True, True, True, True, True, True, True]],
[[ True, True, True, True, True, True, True],
[ True, False, False, False, True, True, True],
[ True, False, False, False, True, True, True],
[ True, True, True, True, True, True, True],
[ True, True, True, True, True, True, True]],
[[ True, True, True, True, True, True, True],
[ True, True, True, True, True, True, True],
[False, False, False, True, True, True, True],
[False, False, False, True, True, True, True],
[ True, True, True, True, True, True, True]]])
This question already has answers here:
How can I find a number of True statements in an Array of Bools in Swift
(2 answers)
Closed 5 years ago.
I have an array with 200 items. These are either true or false:
let shouldMascotChangeVotes: [Bool] = [false, false, false, true, false, true, true, true, false, true, true, true, true, false, true, true, false, true, true, true, false, true, true, true, true, true, true, true, false, true, false, true, false, true, true, false, false, true, true, false, false, true, true, true, false, true, false, true, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, false, true, true, true, false, true, true, false, false, true, false, true, true, false, false, false, true, false, true, true, false, true, true, true, true, true, true, true, false, true, false, true, false, true, true, true, true, true, true, true, false, true, true, false, true, true, true, true, true, true, true, false, true, true, false, true, true, false, true, true, true, true, true, false, false, false, false, true, true, true, false, true, true, false, false, true, false, false, true, true, true, true, false, true, true, true, true, false, true, true, false, true, false, false, true, true, false, true, false, false, false, true, false, false, false, true, false, true, true, false, true, true, false, true, true, true, false, false, false, true, false, true, false, true, true, true, true, false, true, false, false, true, true, true, true, true, false]
I know how to count the total items in the array but I need to be able to count just the true or false values in the array. How do I do that?
shouldMascotChangeVotes.count // returns 200
shouldMascotChangeVotes.filter{$0 == true}.count
you can filter it first and then count it.
I'm not sure how important the actual performance to you, but you can do such thing, for instance.
import UIKit
let shouldMascotChangeVotes: [Bool] = [false, false, false, true, false, true, true, true, false, true, true, true, true, false, true, true, false, true, true, true, false, true, true, true, true, true, true, true, false, true, false, true, false, true, true, false, false, true, true, false, false, true, true, true, false, true, false, true, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, false, true, true, true, false, true, true, false, false, true, false, true, true, false, false, false, true, false, true, true, false, true, true, true, true, true, true, true, false, true, false, true, false, true, true, true, true, true, true, true, false, true, true, false, true, true, true, true, true, true, true, false, true, true, false, true, true, false, true, true, true, true, true, false, false, false, false, true, true, true, false, true, true, false, false, true, false, false, true, true, true, true, false, true, true, true, true, false, true, true, false, true, false, false, true, true, false, true, false, false, false, true, false, false, false, true, false, true, true, false, true, true, false, true, true, true, false, false, false, true, false, true, false, true, true, true, true, false, true, false, false, true, true, true, true, true, false]
let countableSet = NSCountedSet()
shouldMascotChangeVotes.forEach { (item: Bool) in
countableSet.add(item)
}
debugPrint(countableSet.count(for: true)) // 125
debugPrint(countableSet.count(for: false)) // 75
NOTE: maybe not the most effective solution but it does the job; that snippet is coming from Playground directly.
You can also try using reduce(). I did it twice for presentation purpose. You can actually use total count and do a difference.
let shouldMascotChangeVotes: [Bool] = [false, false, false, true, false, true, true, true, false, true, true, true, true, false, true, true, false, true, true, true, false, true, true, true, true, true, true, true, false, true, false, true, false, true, true, false, false, true, true, false, false, true, true, true, false, true, false, true, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, false, true, true, true, false, true, true, false, false, true, false, true, true, false, false, false, true, false, true, true, false, true, true, true, true, true, true, true, false, true, false, true, false, true, true, true, true, true, true, true, false, true, true, false, true, true, true, true, true, true, true, false, true, true, false, true, true, false, true, true, true, true, true, false, false, false, false, true, true, true, false, true, true, false, false, true, false, false, true, true, true, true, false, true, true, true, true, false, true, true, false, true, false, false, true, true, false, true, false, false, false, true, false, false, false, true, false, true, true, false, true, true, false, true, true, true, false, false, false, true, false, true, false, true, true, true, true, false, true, false, false, true, true, true, true, true, false]
var trueFalseCount: (trues: Int, falses: Int)
trueFalseCount.trues = shouldMascotChangeVotes.reduce(0) { $0 + ($1 ? 1 : 0) }
trueFalseCount.falses = shouldMascotChangeVotes.reduce(0) { $0 + ($1 ? 0 : 1) }
print(trueFalseCount) // (trues: 125, falses: 75)