For a 2d numpy array, e.g.,
import numpy as np
a = np.random.rand(5, 4)
a
a
looks like
array([[0.92576936, 0.41860519, 0.26446948, 0.31691141],
[0.31797497, 0.2044637 , 0.20939504, 0.54034017],
[0.85781227, 0.40367301, 0.40215265, 0.95902499],
[0.15700837, 0.10680368, 0.61971475, 0.35586694],
[0.25211967, 0.98171005, 0.60740472, 0.89452886]])
Apparently, each element has neighbors. For elements in the border, it has 3 or 5 neighbors. And for central elements, it has 8. Thus, is there an efficient and elegant way to mask a
by only selecting elements and their neighbors together greater than 0.5? That means, do not consider isolated elements larger than 0.5, whose neighbors all smaller than 0.5.
For a
, the expected output mask would be
array([[False, False, False, False],
[False, False , False, True],
[False, False, False, True],
[False, False, True, False],
[False, True, True, True]])
CodePudding user response:
You can use a 2D convolution:
from scipy.signal import convolve2d
kernel = np.array([[1, 1, 1],
[1, 10, 1],
[1, 1, 1]])
out = convolve2d(a>0.5, kernel, mode='same') > 10
The kernel is designed to count 10 for each center > 0.5 and 1 for each surrounding value > 0.5, and the convolution computes the sum. Thus if you have a total sum > 10, you know that the value is > 0.5 and so it at least one of its neighbors.
Output:
array([[False, False, False, False],
[False, False, False, True],
[False, False, False, True],
[False, False, True, False],
[False, True, True, True]])
more classical alternative
from scipy.signal import convolve2d
m = a>0.5
kernel = np.array([[1, 1, 1],
[1, 0, 1],
[1, 1, 1]])
out = m & (convolve2d(m, kernel, mode='same') > 0)