Hidden label erosion

How to save a ring of pixels around marked areas in a numpy array?

In a simple case, I would subtract erosion. This approach does not work when labels are superimposed. How can I get B from A ?

 A = 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 = 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]]) 

I work with large arrays with many labels, so separate erosion on each label is not an option.

+4
source share
1 answer

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) # Preform abs in-place B /= B # This will produce a divide by zero warning that you can safely ignore B *= A 

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 ....

+2
source

Source: https://habr.com/ru/post/1387253/


All Articles