Search code examples
pythonnumpyscipydistancescipy-spatial

How to compute a spatial distance matrix from a given value


I've been looking for a way to (efficiently) compute a distance matrix from a target value and an input matrix.

If you consider an input array as:

[0 0 1 2 5 2 1]  
[0 0 2 3 5 2 1]  
[0 1 1 2 5 4 1]  
[1 1 1 2 5 4 0]

Ho do you compute the spatial distance matrix associated to the target value 0?

i.e. what is the distance from each pixel to the closest 0 value?

Thanks in advance


Solution

  • You are looking for scipy.ndimage.morphology.distance_transform_edt. It operates on a binary array and computes euclidean distances on each TRUE position to the nearest background FALSE position. In our case, since we want to find out distances from nearest 0s, so the background is 0. Now, under the hoods, it converts the input to a binary array assuming 0 as the background, so we can just use it with the default parameters. Hence, it would be as simple as -

    In [179]: a
    Out[179]: 
    array([[0, 0, 1, 2, 5, 2, 1],
           [0, 0, 2, 3, 5, 2, 1],
           [0, 1, 1, 2, 5, 4, 1],
           [1, 1, 1, 2, 5, 4, 0]])
    
    In [180]: from scipy import ndimage
    
    In [181]: ndimage.distance_transform_edt(a)
    Out[181]: 
    array([[0.  , 0.  , 1.  , 2.  , 3.  , 3.16, 3.  ],
           [0.  , 0.  , 1.  , 2.  , 2.83, 2.24, 2.  ],
           [0.  , 1.  , 1.41, 2.24, 2.24, 1.41, 1.  ],
           [1.  , 1.41, 2.24, 2.83, 2.  , 1.  , 0.  ]])
    

    Solving for generic case

    Now, let's say we want to find out distances from nearest 1s, then it would be -

    In [183]: background = 1 # element from which distances are to be computed
    
    # compare this with original array, a to verify
    In [184]: ndimage.distance_transform_edt(a!=background)
    Out[184]: 
    array([[2.  , 1.  , 0.  , 1.  , 2.  , 1.  , 0.  ],
           [1.41, 1.  , 1.  , 1.41, 2.  , 1.  , 0.  ],
           [1.  , 0.  , 0.  , 1.  , 2.  , 1.  , 0.  ],
           [0.  , 0.  , 0.  , 1.  , 2.  , 1.41, 1.  ]])