Search code examples
pythonnumpybinaryneighbours

Most efficient way of comparing each element in a 2D numpy array to its 8 neighbours


So in a binary array I'm trying to find the points where a 0 and a 1 are next to each other, and redraw the array with these crossover points indicated by modifying the 0 value. Just wondering if there's a better way of comparing each of the values in a numpy array to the 8 surrounding values than using nested for loops.

Currently I have this, which compares to 4 surrounding just for readability here

for x in range(1, rows - 1):
    for y in range(1, columns - 1):
        if f2[x, y] == 0:
            if f2[x-1, y] == 1 or f2[x+1, y] == 1 or f2[x, y-1] == 1 or f2[x, y+1] == 1:
                f2[x, y] = 2

EDIT

For example

[[1, 1, 1, 1, 1, 1, 1],
 [1, 1, 0, 0, 0, 1, 1],
 [1, 1, 0, 0, 0, 1, 1],
 [1, 1, 0, 0, 0, 1, 1],
 [1, 1, 1, 1, 1, 1, 1]]

to

[[1, 1, 1, 1, 1, 1, 1],
 [1, 1, 2, 2, 2, 1, 1],
 [1, 1, 2, 0, 2, 1, 1],
 [1, 1, 2, 2, 2, 1, 1],
 [1, 1, 1, 1, 1, 1, 1]]

Solution

  • This problem can be solved quickly with binary morphology functions

    import numpy as np
    from scipy.ndimage.morphology import binary_dilation, generate_binary_structure
    
    # Example array
    f2 = np.zeros((5,5), dtype=float)
    f2[2,2] = 1.
    
    # This line determines the connectivity (all 8 neighbors or just 4)
    struct_8_neighbors = generate_binary_structure(2, 2)
    
    # Replace cell with maximum of neighbors (True if any neighbor != 0)
    has_neighbor = binary_dilation(f2 != 0, structure=struct_8_neighbors)
    
    # Was cell zero to begin with
    was_zero = f2 == 0
    
    # Update step
    f2[has_neighbor & was_zero] = 2.