Python 两两之间的成对距离;岛屿“/&引用;“连接部件”;在Numpy数组中
考虑以下存储为numpy数组的图像:Python 两两之间的成对距离;岛屿“/&引用;“连接部件”;在Numpy数组中,python,arrays,numpy,scipy,image-segmentation,Python,Arrays,Numpy,Scipy,Image Segmentation,考虑以下存储为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
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)
零表示背景像素,1、2、3和4表示属于对象的像素。您可以看到,对象总是在图像中形成连续的岛或区域。我想知道每对物体之间的距离。作为距离度量,我希望在物体的像素之间,有一个最短的、最接近的直线距离。示例:距离(2,3)=1,因为它们相互接触<代码>距离(1,2)=2,因为正好有一个背景像素将两个区域分开,或者换句话说,对象最近的像素相隔两个像素
有人能告诉我如何用Python解决这个问题吗?或者将我链接到一些资源?这是您需要的:
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
更快):
找到岛屿的位置,计算位置的成对距离,得到最小值。我不能100%确定您想要的距离,但我认为您正在寻找l1
norm。如果没有,您可以将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
对于许多BLOB或更大的BLOB,或者如果性能/内存效率是一个标准,您可能需要处理这些孤岛的轮廓。考虑到这一点,我们将使用获得轮廓,然后执行两两距离计算,并获得min
1作为最终输出。实现看起来像这样,可以获得所有可能的成对距离-
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)}
给定样本的输出dict-
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(idxs[i],idxs[j])
将更改为cdist(idxs[i],idxs[j],metric=…)
,这是否回答了您的问题?不,不幸的是没有。您发布的链接处理的是1D案例,并且是一个完全不同的问题。我认为您的问题的解决方案基本相同。我会开始尝试调整里面的东西,看看你是否被困在什么地方。我想如果这些岛屿已经被“标记”了,下面的方法应该可以很好地工作。如果不需要,connectec组件会更多labeled@r0f13号岛和4号岛之间的直线是多少?我不确定这种情况下的距离定义是否清晰。请详细说明。谢谢。这回答了问题。您可以直接使用metric='cityblock'
,速度更快,而且不需要p
参数。@MaxPowers谢谢。不知道它有自己的度量标准。你能详细说明一下为什么那台性能更快吗?它们不应该几乎相似吗?L1范数计算为向量元素差值之和Minkowski
使用np.norm
计算为广义Lp范数。因此,阶梯取每个向量元素的幂,并计算其总差的根。@MaxPowers。非常感谢。我原以为它在p=1
FYI的情况下会更智能,@Ehsan:perminkowski
在p=1
和p=2
的情况下会更智能。这将在1.16.0版中提供。
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}