Ana*_*oly 2 python grouping matrix image-segmentation
假设我有一个这样的矩阵:
m = [0, 1, 1, 0,
1, 1, 0, 0,
0, 0, 0, 1]
Run Code Online (Sandbox Code Playgroud)
我需要获得相同相邻值的坐标(但不是对角线):

因此,结果将是“矩阵”列表中的坐标列表列表,从 [0,0] 开始,如下所示:
r = [[[0,0]],
[[0,1], [0,2], [1,0], [1,1]],
[[0,3], [1,2], [1,3], [2,0], [2,1], [2,2]]
[[2,3]]]
Run Code Online (Sandbox Code Playgroud)
一定有办法做到这一点,但我真的被困住了。
tl; dr:我们取一个零和一的数组,并使用scipy.ndimage.label将其转换为零和 [1,2,3,...] 的数组。然后我们使用np.where找到每个值 > 0 的元素的坐标。具有相同值的元素最终会出现在同一个列表中。
scipy.ndimage.label将矩阵的非零元素解释为特征并标记它们。输入中的每个独特特征都被分配了一个独特的标签。特征是例如具有相同值的相邻元素(或像素)的组。
import numpy as np
from scipy.ndimage import label
# make dummy data
arr = np.array([[0,1,1,0], [1,1,0,0], [0,0,0,1]])
#initialise list of features
r = []
Run Code Online (Sandbox Code Playgroud)
由于 OP 需要所有特征,即零和非零像素组,我们使用label两次:第一次在原始数组上,第二次在1 - original array. (对于零和一的数组,1 - array只需翻转值)。
现在,label返回一个元组,包含标记数组(我们感兴趣)和它在该数组中找到的特征数量(我们可以使用,但是当我编码时,我选择忽略它。所以,我们是对由 返回的元组的第一个元素感兴趣label,我们可以通过[0]以下方式访问:
a = label(arr)[0]
b = label(1-arr)[0]
Run Code Online (Sandbox Code Playgroud)
现在我们检查label分配了哪些唯一的像素值。所以我们想要set of a and b, repectively. 为了set()工作,我们需要线性化两个数组,我们用.ravel(). 我们必须减去{0}在这两种情况下,因为这两个a和b我们感兴趣的只是非零值。
因此,找到唯一标签后,我们遍历这些值,并使用它np.where来查找给定值在数组中的位置。np.where返回一个数组元组。这个元组的第一个元素是满足条件的所有行坐标,第二个元素是列坐标。因此,我们可以使用zip(*将两个长度为 n 的容器解包到 n 个长度为 2 的容器。这意味着我们从满足条件的list of all row-coords + list of all column-coords到list of all row-column-coordinate pairs。最后,在 Python 3 中,zip 是一个生成器,我们可以通过调用list()它来评估它。然后将结果列表附加到我们的坐标列表中r。
for x in set(a.ravel())-{0}:
r.append(list(zip(*np.where(a==x))))
for x in set(b.ravel())-{0}:
r.append(list(zip(*np.where(b==x))))
print(r)
[[(0, 1), (0, 2), (1, 0), (1, 1)],
[(2, 3)],
[(0, 0)],
[(0, 3), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2)]]
Run Code Online (Sandbox Code Playgroud)
也就是说,我们可以利用label返回它分配的特征数量这一事实来稍微加快这段代码的速度。这使我们可以避免使用该set命令,该命令在大型阵列上可能需要时间:
a, num_a = label(arr)
for x in range(1, num_a+1): # range from 1 to the highest label
r.append(list(zip(*np.where(a==x))))
Run Code Online (Sandbox Code Playgroud)