Skip to content

Find closest 8-connected chessboard distance between multiple pairs of points: shortest m-path

An answer to this question on Stack Overflow.

Question

I am working on binary images in Python using OpenCV. I have two sets of points: PNodes and FNodes. I want to find the closest PNode to each of the FNodes (shortest m-path); closest in terms of 8-connected chessboard distance.

In the example below, suppose PNodes (donated by *) are: (6,1), (6,5) and (5,8). (indexing starts from 0, first element is row number). FNodes (denoted by #) are: (0,1), (0,9), (1,6), (2,5) and (4,3).

import numpy as np 
In = np.array ((
      [ 0,  1#, 0,  0,  0,  0,  0,  0,  0,  1#, 0],
      [ 1,  0,  0,  0,  0,  0,  1#, 0,  1,  0,  0],
      [ 0,  1,  0,  0,  0,  1#, 0,  0,  1,  0,  0],
      [ 0,  0,  1,  0,  0,  0,  1,  0,  0,  1,  0],
      [ 0,  1,  1,  1#, 0,  1,  0,  0,  1,  0,  0],
      [ 0,  1,  0,  0,  0,  1,  0,  0,  1*, 0,  0],
      [ 0,  1*, 0,  0,  0,  1*, 0,  0,  1,  0,  0],
      [ 0,  1,  0,  0,  1,  0,  1,  1,  0,  0,  0],
      [ 0,  0,  1,  1,  0,  0,  0,  1,  0,  0,  0]), dtype = "uint8") 
Distance_Matrix =  np.array ((
      [ 0,  6#, 0,  0,  0,  0,  0,  0,  0,  5#, 0],
      [ 5,  0,  0,  0,  0,  0,  5#, 0,  4,  0,  0],
      [ 0,  4,  0,  0,  0,  4#, 0,  0,  3,  0,  0],
      [ 0,  0,  3,  0,  0,  0,  3,  0,  0,  2,  0],
      [ 0,  2,  2,  3#, 0,  2,  0,  0,  1,  0,  0],
      [ 0,  1,  0,  0,  0,  1,  0,  0,  **, 0,  0],
      [ 0, **,  0,  0,  0,  **, 0,  0,  1,  0,  0],
      [ 0,  1,  0,  0,  1,  0,  1,  1,  0,  0,  0],
      [ 0,  0,  1,  1,  0,  0,  0,  1,  0,  0,  0]), dtype = "uint8")

I am not concerned with the exact value of distance, I just want to find out the closest pair. Something like this: FNode at (0,1) is closest to PNode at (6,1). FNode at (4,3) is closest to PNode at (6,1). All distances are in terms of 8-connected chessboard distance.

Ultimate requirement from this entire process: Basically, I just want to make sure all PNodes have atleast 1 FNode which lie within a given distance range (along the path of 1s).

Suppose PNode (PN_1) has a FNode (FN_1) which lies within the required distance range, I also make sure that PN_1 is closest to FN_1, and not any other PNode.

For a better understanding, I have attached an image below; FNodes are rectangular and PNodes are circular.

I don't care about other elements in this matrix, apart from those of PNodes and FNodes, as depicted.

enter image description here

Answer

I'd use Dijkstra's algorithm for this. It finds the shortest distance between a source node and every other node by exploring nearer nodes before farther nodes.

Seed a Dijkstra search at each of your P-nodes and halt the search when you either find the first F-node or exceed your distance constraint.

Since you don't have a graph, per se, you can generate neighbours using offsets. For instance if you have a cell (x,y) you can define some offsets

dx = [-1,-1, 0, 1,1,1,0,-1]
dy = [ 0,-1,-1,-1,0,1,1, 1]

and then take (x+dx[i], y+dy[i]) for i∈[0,7] to generate the neighbours of a given cell.

You can define a separate 2D array/matrix for tracking whether cells have been visited.