2016-06-28 20 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