Wilmar van Ommeren - 6 months ago 32
Python Question

# Applying a disc shaped mask to several locations in a NumPy array

I have a question which is similar to the one asked here: How to apply a disc shaped mask to a numpy array?. However, instead of masking a single circular sector, I would like to create a mask with multiple circular sectors (number is variable). These masks all have the same radius, but different centers. The coordinates of these centers are stored in a numpy 2d array. For example:

``````maskcenters = array([[1, 1],
[7, 2],
[2, 8]])
``````

Now to create a round mask (radius 2) around a single center I could simply use the solution given by Bi Rico:

``````import numpy as np

n = 10
r = 2

y,x = np.ogrid[-a:n-a, -b:n-b]
mask = x*x + y*y <= r*r
``````

Where a and b represent the center of the mask; n the size of the array to mask; and r the radius.

This would result in a mask like:

``````#output
array([[ True,  True,  True, False, False, False, False, False, False],
[ True,  True,  True,  True, False, False, False, False, False],
[ True,  True,  True, False, False, False, False, False, False],
[False,  True, False, False, False, False, False, False, False],
[False, False, False, False, False, False, False, False, False],
[False, False, False, False, False, False, False, False, False],
[False, False, False, False, False, False, False, False, False],
[False, False, False, False, False, False, False, False, False],
[False, False, False, False, False, False, False, False, False]], dtype=bool)
``````

However, I have a variable number of centers around which I want to create masks. I know how to create multiple circular masks with a for loop, but this slows down the code. My optimal outcome, using the example mask centers in a 10x10 array, would be:

``````#output
array([[ True,  True,  True, False, False, False, False, False,  True],
[ True,  True,  True,  True, False, False, False,  True,  True],
[ True,  True,  True, False, False, False,  True,  True,  True],
[False,  True, False, False, False, False, False,  True,  True],
[False, False, False, False, False, False, False, False,  True],
[False, False,  True, False, False, False, False, False, False],
[False,  True,  True,  True, False, False, False, False, False],
[ True,  True,  True,  True,  True, False, False, False, False],
[False,  True,  True,  True, False, False, False, False, False]], dtype=bool)
``````

Any idea how to create this mask without using loops?

You can use `scipy's binary_dilation` with a disk shaped kernel, like so -

``````# Define inputs
[1, 1],
[7, 2],
[2, 8]])

out_shp = (10,10) # Output array shape
r = 2 # Radius of circles

# Get a disk kernel
X,Y = [np.arange(-r,r+1)]*2
disk_mask = X[:,None]**2 + Y**2 <= r*r

# Initialize output array and set the maskcenters as 1s
out = np.zeros(out_shp,dtype=bool)

# Use binary dilation to get the desired output
``````

Output -

``````In [64]: print out
[[ True  True  True False False False False False  True False]
[ True  True  True  True False False False  True  True  True]
[ True  True  True False False False  True  True  True  True]
[False  True False False False False False  True  True  True]
[False False False False False False False False  True False]
[False False  True False False False False False False False]
[False  True  True  True False False False False False False]
[ True  True  True  True  True False False False False False]
[False  True  True  True False False False False False False]
[False False  True False False False False False False False]]
``````

Here's another approach using `simple indexing` -

``````X,Y = [np.arange(-r,r+1)]*2
disk_mask = X[:,None]**2 + Y**2 <= r*r