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)
