Numpy 数组中两个 "islands"/"connected components" 之间的成对距离

Pairwise Distances Between Two "islands"/"connected components" in Numpy Array

考虑下图,存储为 numpy 数组:

a = [[0,0,0,0,0,1,1,0,0,0],
     [0,0,0,0,1,1,1,1,0,0],
     [0,0,0,0,0,1,1,0,0,0],
     [0,0,0,0,0,0,0,0,0,0],
     [0,0,0,0,0,2,0,0,0,0],
     [0,0,0,0,0,2,2,0,0,0],
     [0,0,0,0,0,2,0,0,0,0],
     [0,0,0,0,3,3,3,0,0,0],
     [4,0,0,0,0,0,0,0,0,0],
     [4,4,0,0,0,0,0,0,0,0],
     [4,4,4,0,0,0,0,0,0,0]]

a = np.array(a)

0 表示背景像素,1、2、3 和 4 表示属于对象的像素。您可以看到物体总是在图像中形成连续的岛或区域。我想知道每对物体之间的距离。作为距离度量,我希望对象的那些像素之间的最短直线距离彼此最接近。示例:Distance(2,3) = 1,因为它们正在接触。 Distance(1,2) = 2,因为恰好有一个背景像素将两个区域分开,或者说,物体最近的像素相隔两个像素。

谁能告诉我如何解决 Python 中的这个问题?或者 link 我要一些资源?

这是您需要的:

from scipy.spatial.distance import cdist
def Distance(a, m, n):
  return cdist(np.argwhere(a==m),np.argwhere(a==n),'minkowski',p=1.).min()

或类似的 @MaxPowers 评论(声称:cityblock 更快):

  return cdist(np.argwhere(a==m),np.argwhere(a==n),'cityblock').min()

找到岛屿的位置并计算位置的成对距离并获得最小值。我不是 100% 确定您想要的距离,但我认为您正在寻找 l1 标准。如果不是,您可以将 cdist 度量更改为您想要的指标。

输出:

Distance(a,2,3)
1.0
Distance(a,2,1)
2.0
Distance(a,3,1)
5.0
Distance(a,4,3)
5.0

对于许多斑点或更大的斑点,或者如果 performance/memory 效率是一个标准,您可能希望使用这些岛屿的轮廓。考虑到这一点,我们将使用 OpenCV's findContours 来获取轮廓,然后执行成对距离计算并获得 min 作为最终输出。实现看起来像这样获取所有可能的成对距离 -

from scipy.spatial.distance import cdist
import cv2

ids = np.arange(1, a.max()+1) #np.unique(a)[1:] if not in ranged sequence

idxs = []
for id_ in ids:
    im = (a == id_).astype(np.uint8)
    contours,_ = cv2.findContours(im, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    idx = contours[0][:, 0]
    idxs.append(idx)

# Get pairwise indices and then distances
r,c = np.triu_indices(len(ids), 1)
pdists = {(ids[i],ids[j]):cdist(idxs[i], idxs[j]).min() for (i, j) in zip(r, c)}

给定样本的输出字典 -

In [225]: pdists
Out[225]: 
{(1, 2): 2.0,
 (1, 3): 5.0,
 (1, 4): 7.810249675906654,
 (2, 3): 1.0,
 (2, 4): 5.0,
 (3, 4): 3.605551275463989}

默认情况下,cdist 使用欧氏距离作为 metric。根据您对岛屿之间直线的定义,您可能想尝试其他指标,即 'minkowski''cityblock' 分别用于 MinkowskiManhattan 距离。

因此,cdist(idxs[i], idxs[j]) 将更改为 cdist(idxs[i], idxs[j], metric=...)