2016-06-28 22 views
5

我在寻找以下内容。我有一个numpy数组,它被标记为区域。 numpy数组表示一个分段图像。区域是具有相同值的多个相邻单元。每个地区都有其独特的价值。与3个区域的简化版本看起来像这样:确定numpy阵列中的相邻区域

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

会是什么最优雅和最快的方式来实现这一目标?

非常感谢!

+0

你能解释一下你所说的地区吗?你是指专栏吗? –

+0

我在这种情况下添加了一些关于区域定义的附加说明。 – cf2

回答

4

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

由于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) 
+0

这工作完美。我也在一个大型的数据集上进行了测试,其中的区域是随机编号的,在那里它也能正常工作。非常感谢您的解决方案! – cf2

2

如果区域都标有小整数(从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])] 
+0

我真的很喜欢你的解决方案,因为它为所有地区返回一个索引结果数组。但是,我的区域是随机编号的,因此您的解决方案不幸在我的数据集中无法使用。感谢您的努力!当我有一个有序区域的数据集时,我会保留这个解决方案。 – cf2