有没有一种更有效的方法来获取与python中矩阵内的特定元素具有一个欧几里德距离的元素的所有索引?

时间:2019-04-30 10:45:30

标签: python numpy

这是一个矩阵。

1 2 1
1 1 0
0 1 1

我正试图获得直接链接到数字2的数字1的所有索引,即[0,0],[0,2]和[1,1]

ds = np.array([[1, 2, 1],
       [1, 1, 0],
       [0, 1, 1]])
p0 = np.where(ds == 2)
p1 = np.where(ds == 1)
d1 = np.array(p1) - np.array(p0)
idx = np.where(np.linalg.norm(d1,axis=0, keepdims=True) == 1)[1]
np.take(p1, idx, axis=1 )

如果2个以上,则需要分别存储2个邻居。

虽然这段代码有效,但我想知道是否有更有效的方法来做到这一点?

3 个答案:

答案 0 :(得分:1)

首先,如果数组中的2个以上,则您的代码将无法工作,因此您需要一种更通用的方法。

根据您的期望,如果两个索引的一个轴相同,而另一个轴相差1个单位,则它们是相邻的。

    X
  X O X
    X

现在,如果您有一个如下数组:

In [87]: arr # I changed the value of [2, 2] index to 2
Out[87]: 
array([[1, 2, 1],
       [1, 1, 0],
       [0, 1, 2]])

您可以通过以下矢量化方法来找到预期的印章:

In [88]: one_indices = np.argwhere(arr==1)

In [89]: two_indices = np.argwhere(arr==2)

In [90]: x, y = np.where(two_indices[:, 0][:,None] == one_indices[:, 0])

In [91]: neighbor_on_row = one_indices[y[np.where(np.abs(one_indices[:, 1][y] - two_indices[:, 1][x]) == 1)[0]]]

In [92]: neighbor_on_row
Out[92]: 
array([[0, 0],
       [0, 2],
       [2, 1]])

In [93]: x, y = np.where(two_indices[:, 1][:,None] == one_indices[:, 1])

In [94]: neighbor_on_col = one_indices[y[np.where(np.abs(one_indices[:, 0][y] - two_indices[:, 0][x]) == 1)[0]]]

In [95]: neighbor_on_col
Out[95]: array([[1, 1]])

最后:

In [103]: np.concatenate((neighbor_on_row, neighbor_on_col))
Out[103]: 
array([[0, 0],
       [0, 2],
       [2, 1],
       [1, 1]])

答案 1 :(得分:1)

代码:

ds = np.array([[1, 2, 1],
       [1, 1, 0],
       [0, 1, 2]])
p0 = np.where(ds == 2)
p0 = np.array(p0)
p1 = np.where(ds == 1)
for i in range(len(p0[0])):
    d1 = np.array(p1) - p0[:,i].reshape(2,1)
    idx = np.where(np.linalg.norm(d1,axis=0, keepdims=True) == 1)[1]
    print('neighbors of', p0[:,i])
    print(np.take(p1, idx, axis=1))

输出:

neighbors of [0 1]
[[0 0 1]
 [0 2 1]]
neighbors of [2 2]
[[2]
 [1]]

答案 2 :(得分:0)

我认为您可以使用open-cv库中的形态学dilation来尝试您的方法,而我用该操作编写的方法和我的方法要快两倍。我还尝试了scipy implementation of dilation,但是它比您的实现花费了更多时间。 如果可以使用open-cv,则此代码可能对您有用:

kernel = np.array([[0, 1, 0],
                   [1, 1, 1],
                   [0, 1, 0]], dtype=np.uint8) 

def get_twoes_neighbor2(ds, kernel):
    img = (ds == 2).astype(np.uint8)
    img_dilation = cv2.dilate(img, kernel, iterations=1) 
    neighbors = (ds == 1) & img_dilation
    return np.array(np.where(neighbors == 1))