确定numpy数组中的相邻区域

时间:2016-06-28 10:16:56

标签: python arrays numpy region neighbours

我正在寻找以下内容。我有一个numpy数组,标记为区域。 numpy数组表示分段图像。区域是具有相同值的多个相邻单元。每个地区都有自己独特的价值。包含3个区域的简化版本如下所示:

x = np.array([[1, 1, 1], [1, 1, 2], [2, 2, 2], [3, 3, 3]], np.int32)

输出:

array([[1, 1, 1],
       [1, 1, 2],
       [2, 2, 2],
       [3, 3, 3]])

在上面的例子中,我们有3个独立的区域,每个区域都标有唯一值(在这种情况下为1,2,3)。

我想要的是每个区域的相邻(邻居)区域的值。所以在这种情况下:

  • 区域1与区域2相邻
  • 区域2与区域1和3相邻
  • 区域3与区域2相邻

实现这一目标的最优雅,最快捷的方法是什么?

非常感谢!

2 个答案:

答案 0 :(得分:4)

我知道该任务是返回与给定数字相邻的数组的所有不同条目(例如2)。使用NumPy方法实现此目的的一种方法是使用roll将给定区域向上,向下,向左和向右移动一个单位。采用移位区域的逻辑OR,并返回与该条件匹配的所有不同元素。然后它仍然是删除该区域本身,因为它不被认为是它自己的邻居。

由于roll重新引入了在相反端超出数组边界的值(这里不需要),另外一步是将此行或列替换为False。

import numpy as np

x = np.array([[1, 1, 1], [1, 1, 2], [2, 2, 2], [3, 3, 3]], np.int32)
region = 2   # number of region whose neighbors we want

y = x == region  # convert to Boolean

rolled = np.roll(y, 1, axis=0)          # shift down
rolled[0, :] = False             
z = np.logical_or(y, rolled)

rolled = np.roll(y, -1, axis=0)         # shift up 
rolled[-1, :] = False
z = np.logical_or(z, rolled)

rolled = np.roll(y, 1, axis=1)          # shift right
rolled[:, 0] = False
z = np.logical_or(z, rolled)

rolled = np.roll(y, -1, axis=1)         # shift left
rolled[:, -1] = False
z = np.logical_or(z, rolled)

neighbors = set(np.unique(np.extract(z, x))) - set([region])
print(neighbors)

答案 1 :(得分:3)

如果区域标有小整数(理想情况下从0n),则标签可用于索引到结果数组中:

n = x.max()
tmp = np.zeros((n+1, n+1), bool)

# check the vertical adjacency
a, b = x[:-1, :], x[1:, :]
tmp[a[a!=b], b[a!=b]] = True

# check the horizontal adjacency
a, b = x[:, :-1], x[:, 1:]
tmp[a[a!=b], b[a!=b]] = True

# register adjacency in both directions (up, down) and (left,right)
result = (tmp | tmp.T)

对于问题中的示例数组:

In [58]: result.astype(int)
Out[58]: 
array([[0, 0, 0, 0],
       [0, 0, 1, 0],
       [0, 1, 0, 1],
       [0, 0, 1, 0]])

In [60]: np.column_stack(np.nonzero(result))
Out[60]: 
array([[1, 2],
       [2, 1],
       [2, 3],
       [3, 2]])

In [361]: # Assuming labels start from `1`
          [np.flatnonzero(row) for row in result[1:]]
Out[361]: [array([2]), array([1, 3]), array([2])]