New answer
Actually, I just thought of a better way:
B = A * (np.abs(scipy.ndimage.laplace(A)) > 0)
As a complete example:
import numpy as np import scipy.ndimage A = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], [0, 0, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) B = A * (np.abs(scipy.ndimage.laplace(A)) > 0)
I think this should work in all cases ("tagged" arrays like A , anyway ...).
If you are worried about performance, you can break it down into several parts to reduce overhead:
B = scipy.ndimage.laplace(A) B = np.abs(B, B)
This version is much more complicated, but should use much less memory.
Old answer
I cannot think of a good way to do this in one step with the usual scipy.ndimage functions. (I feel the filter filter should do what you want, but I can't figure it out.)
However, as you mentioned, you can make several separate erosions.
You should get reasonable performance even on very large arrays if you use find_objects to retrieve the subregion of each label, and then just do the blur on the subregion.
For instance:
import numpy as np import scipy.ndimage A = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], [0, 0, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) regions = scipy.ndimage.find_objects(A) mask = np.zeros_like(A).astype(np.bool) for val, region in enumerate(regions, start=1): if region is not None: subregion = A[region] mask[region] = scipy.ndimage.binary_erosion(subregion == val) B = A.copy() B[mask] = 0
This gives:
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], [0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0], [0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0], [0, 0, 2, 0, 0, 2, 2, 2, 2, 0, 0, 0], [0, 0, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
Performance should be reasonable for large arrays, but it will greatly depend on how large the area is occupied by different marked objects and the number of marked objects that you have ....