Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: distance from index to 1s in binary mask

I have a binary mask like this:

X = [[0, 0, 0, 0, 0, 1],
     [0, 0, 0, 0, 1, 1],
     [0, 0, 0, 1, 1, 1],
     [0, 0, 1, 1, 1, 1],
     [0, 0, 1, 1, 1, 1],
     [0, 0, 0, 1, 1, 1]]

I have a certain index in this array and want to compute the distance from that index to the closest 1 in the mask. If there's already a 1 at that index, the distance should be zero. Examples (assuming Manhattan distance):

distance(X, idx=(0, 5)) == 0 # already is a 1 -> distance is zero
distance(X, idx=(1, 2)) == 2 # second row, third column
distance(X, idx=(0, 0)) == 5 # upper left corner

Is there already existing functionality like this in Python/NumPy/SciPy? Both Euclidian and Manhattan distance would be fine. I'd prefer to avoid computing distances for the entire matrix (as that is pretty big in my case), and only get the distance for my one index.

like image 398
knub Avatar asked Mar 03 '23 19:03

knub


1 Answers

Here's one for manhattan distance metric for one entry -

def bwdist_manhattan_single_entry(X, idx):
    nz = np.argwhere(X==1)
    return np.abs((idx-nz).sum(1)).min()

Sample run -

In [143]: bwdist_manhattan_single_entry(X, idx=(0,5))
Out[143]: 0

In [144]: bwdist_manhattan_single_entry(X, idx=(1,2))
Out[144]: 2

In [145]: bwdist_manhattan_single_entry(X, idx=(0,0))
Out[145]: 5

Optimize further on performance by extracting the boudary elements only off the blobs of 1s -

from scipy.ndimage.morphology import binary_erosion

def bwdist_manhattan_single_entry_v2(X, idx):
    k = np.ones((3,3),dtype=int)
    nz = np.argwhere((X==1) & (~binary_erosion(X,k,border_value=1)))
    return np.abs((idx-nz).sum(1)).min()

Number of elements in nz with this method would be smaller number than the earlier one, hence it improves.

like image 56
Divakar Avatar answered Mar 18 '23 18:03

Divakar