在 numpy 矩阵中查找点

Finding spots in a numpy matrix

我有以下由 0 和 1 组成的矩阵,我想识别它的位置(值为 1 且相互连接的元素)。

M = np.array([[1,1,1,0,0,0,0,0,0,0,0],
              [1,1,1,0,0,0,0,0,0,1,1],
              [1,1,1,0,0,0,0,0,0,1,1],
              [1,1,1,0,0,1,1,1,0,0,0],
              [0,0,0,0,0,1,1,1,0,0,0],
              [1,1,1,0,1,1,1,1,0,0,0],
              [1,1,1,0,0,1,1,1,0,0,0],
              [1,1,1,0,0,1,1,1,0,0,0]])

矩阵中有四个点。

我的输出示例如下所示

spot_0 = array[(0,0),(0,1), (0,2), (1,0),(1,1), (1,2), (2,0),(2,1), (2,2), (3,0),(3,1), (3,2)]
Nbr_0 = 12
Top_Left = (0, 0)
and that is the same process for the other 3 spots

有谁知道如何使用 numpy 函数识别每个点的元素数量和 top_left 元素? 谢谢

您可以使用连通分量标记来查找斑点。然后,您可以使用 np.max so 来查找组件的数量,并使用 np.argwhere so 来查找每个组件的位置。这是一个例子:

# OpenCV provides a similar function
from skimage.measure import label

components = label(M)
# array([[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
#        [1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2],
#        [1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2],
#        [1, 1, 1, 0, 0, 3, 3, 3, 0, 0, 0],
#        [0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0],
#        [4, 4, 4, 0, 3, 3, 3, 3, 0, 0, 0],
#        [4, 4, 4, 0, 0, 3, 3, 3, 0, 0, 0],
#        [4, 4, 4, 0, 0, 3, 3, 3, 0, 0, 0]])

for i in range(1, np.max(components)+1):
    spot_i = np.argwhere(components == i)
    Nbr_i = len(spot_i)
    Top_Left_i = spot_i[0]

请注意,Top_Left 仅对 矩形区域 有意义。如果它们不是矩形,则需要仔细定义此点。

另请注意,此方法仅在组件很少时有效。如果有很多组件,那么最好通过对 components 数组的迭代来替换当前循环(在这种情况下,输出结构存储在列表 l 中,而 l[components[i,j]] 是使用 components 的所有项目位置 (i,j) 找到的信息更新)。除非使用 Numba/Cython 来加快处理速度,否则最后一个算法会很慢。

您可以使用 skimage.measure.label 或其他工具(例如,OpenCVigraph)为连接的组件创建标签:

#from @Jérôme's answer
from skimage.measure import label
components = label(M)

# array([[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
#        [1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2],
#        [1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2],
#        [1, 1, 1, 0, 0, 3, 3, 3, 0, 0, 0],
#        [0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0],
#        [4, 4, 4, 0, 3, 3, 3, 3, 0, 0, 0],
#        [4, 4, 4, 0, 0, 3, 3, 3, 0, 0, 0],
#        [4, 4, 4, 0, 0, 3, 3, 3, 0, 0, 0]])

在后面的部分中,您可以创建一个 one-dimensional 图像视图,对像素值进行排序并找到排序标签值的分割点:

components_ravel = components.ravel()
c = np.arange(1, np.max(components_ravel) + 1)
argidx = np.argsort(components_ravel)
div_points = np.searchsorted(components_ravel, c, sorter=argidx)

# Sorted label values are:
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
# 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
# 2, 2, 2, 2
# 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
# 4, 4, 4, 4, 4, 4, 4, 4, 4
# So you find indices that divides these groups:
# [47, 59, 63, 79]

之后,您可以拆分索引数组,在这些点对您的 one-dimensional 图像视图进行排序,并将它们转换为 two-dimensional 个:

spots = []
for n in np.split(argidx, div_points)[1:]: #in case there are no zeros, cancel `[1:]`
    x, y = np.unravel_index(n, components.shape)
    spots.append(np.transpose([x, y]))

它创建了每个组的点坐标列表:

[array([[1, 0], [1, 2], [0, 2], [0, 1], [1, 1], [0, 0], [2, 2], [2, 1], [2, 0], [3, 2], [3, 1], [3, 0]]),
 array([[2, 10], [1, 9], [2, 9], [1, 10]]),
 array([[6, 5], [7, 5], [7, 6], [7, 7], [6, 7], [6, 6], [3, 5], [4, 6], [3, 6], [4, 5], [3, 7], [5, 7], [5, 6], [4, 7], [5, 5], [5, 4]]),
 array([[5, 0], [5, 1], [5, 2], [6, 2], [7, 0], [6, 0], [6, 1], [7, 1], [7, 2]])]

请注意,每组像素的顺序是混合的。这是因为 np.argsort 使用了不稳定的排序。您可以这样修复它:

argidx = np.argsort(components_ravel, kind='stable')

在这种情况下,您将获得:

[array([[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2], [3, 0], [3, 1], [3, 2]]),
 array([[1, 9], [1, 10], [2, 9], [2, 10]]),
 array([[3, 5], [3, 6], [3, 7], [4, 5], [4, 6], [4, 7], [5, 4], [5, 5], [5, 6], [5, 7], [6, 5], [6, 6], [6, 7], [7, 5], [7, 6], [7, 7]]),
 array([[5, 0], [5, 1], [5, 2], [6, 0], [6, 1], [6, 2], [7, 0], [7, 1], [7, 2]])]