I have a three-dimensional grid. For each point on the grid, I want to find its nearest neighbours. Since my grid is uniformly sampled, I just want to gather the immediate neighbors.
Sample grid:
Required neighbors:
For a given point X, I need the following neighbors:
My Current Working Code:
import numpy as np
import cProfile
class Neighbours:
# Get neighbors
@classmethod
def get_neighbour_indices(cls, row, col, frame, distance=1):
# Define the indices for the neighbor pixels
r = np.linspace(row - distance, row + distance, 2 * distance + 1)
c = np.linspace(col - distance, col + distance, 2 * distance + 1)
f = np.linspace(frame - distance, frame + distance, 2 * distance + 1)
nc, nr, nf = np.meshgrid(c, r, f)
neighbors = np.vstack((nr.flatten(), nc.flatten(), nf.flatten())).T
# Filter out valid neighbor indices within the array bounds
valid_indices = (neighbors[ :, 0] >= 0) & (neighbors[ :, 0] < nRows) & (neighbors[ :, 1] >= 0) & (neighbors[ :, 1] < nCols) & (neighbors[ :, 2] >= 0) & (neighbors[ :, 2] < nFrames)
# Return the valid neighbor indices
valid_neighbors = neighbors[valid_indices]
return valid_neighbors
@classmethod
def MapIndexVsNeighbours(cls):
neighbours_info = np.empty((nRows * nCols * nFrames), dtype=object)
for frame in range(nFrames):
for row in range(nRows):
for col in range(nCols):
neighbour_indices = cls.get_neighbour_indices(row, col, frame, distance=1)
flat_idx = frame * (nRows * nCols) + (row * nCols + col)
neighbours_info[flat_idx] = neighbour_indices
return neighbours_info
########################------------------main()-------##################
####--run
if __name__ == "__main__":
nRows = 151
nCols = 151
nFrames = 24
cProfile.run('Neighbours.MapIndexVsNeighbours()', sort='cumulative')
print()
Problem: For larger grids (e.g. 201 x 201 x 24), the program takes very long time. In the profiling results using cProfile, I can see that meshgrid() in the get_neighbour_indices() takes quite long. All in all, this is not an efficient implementation. Furthermore, I tried to execute the MapIndexVsNeighbours() on a separate thread but due to GIL lock, it does not really execute in parallel. So, something that can be execute in parallel would be a desired implementation.


You can speed-up the computation for example with numba:
Prints on my machine AMD 5700x:
201 x 201 x 24the numba function took1.14399947412312031024 x 1024 x 24the numba function took22.353679422987625