2011-12-20 65 views
4

如何在numpy數組中標記區域周圍保留一圈像素?Scipy標籤侵蝕

在一個簡單的情況下,我會減去侵蝕。這種方法在標籤接觸時不起作用。如何從A獲得B

A = array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
      [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
      [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
      [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
      [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
      [0, 0, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0], 
      [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], 
      [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], 
      [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], 
      [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 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]]) 

B = array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
      [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
      [0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0], 
      [0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0], 
      [0, 0, 2, 0, 0, 2, 2, 2, 2, 0, 0, 0], 
      [0, 0, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0], 
      [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0], 
      [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0], 
      [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0], 
      [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 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]]) 

我正在處理帶有許多標籤的大型數組,因此每個標籤上的單獨腐蝕不是一個選項。

回答

2

新建答案

其實,我只是想到了一個更好的辦法:

B = A * (np.abs(scipy.ndimage.laplace(A)) > 0) 

作爲一個完整的例子:

import numpy as np 
import scipy.ndimage 

A = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
       [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
       [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
       [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
       [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
       [0, 0, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0], 
       [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], 
       [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], 
       [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], 
       [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 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]]) 

B = A * (np.abs(scipy.ndimage.laplace(A)) > 0) 

我想這應該適用於所有情況(的「標籤」數組,如A,無論如何...)。

如果你擔心性能,你可以拆分到這幾件,以減少內存開銷:

B = scipy.ndimage.laplace(A) 
B = np.abs(B, B) # Preform abs in-place 
B /= B # This will produce a divide by zero warning that you can safely ignore 
B *= A 

這個版本是很多更詳細的,更應該用更少的內存。

老回答

我想不出一個好辦法做到這一點在一個步驟通常scipy.ndimage功能。 (我覺得像一個高帽過濾器應該做你想做的,但我不能完全弄清楚。)

但是,如你所說,做幾個單獨的腐蝕是一個選項。

如果您使用find_objects來提取每個標籤的子區域,那麼即使在非常大的陣列上也應該獲得合理的性能,然後在子區域上進行侵蝕。

例如:

import numpy as np 
import scipy.ndimage 

A = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
       [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
       [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
       [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
       [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
       [0, 0, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0], 
       [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], 
       [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], 
       [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], 
       [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 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]]) 

regions = scipy.ndimage.find_objects(A) 

mask = np.zeros_like(A).astype(np.bool) 

for val, region in enumerate(regions, start=1): 
    if region is not None: 
     subregion = A[region] 
     mask[region] = scipy.ndimage.binary_erosion(subregion == val) 

B = A.copy() 
B[mask] = 0 

這產生了:

array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
     [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0], 
     [0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0], 
     [0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0], 
     [0, 0, 2, 0, 0, 2, 2, 2, 2, 0, 0, 0], 
     [0, 0, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0], 
     [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0], 
     [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0], 
     [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0], 
     [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 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

標籤數組很稀疏,所以這應該可以正常工作。我今天早上去上班的路上也有同樣的想法...... – ajwood 2011-12-21 14:13:59

+0

其實,我只是想到了一個更好的方法。 (儘管在某些情況下原始答案可能會更快......)請參閱編輯。 – 2011-12-21 16:24:18