2016-11-08 149 views
1

我有1小號& 0個numpy的陣列(或布爾變量,如果這是更容易)「來自邊緣的距離」查找一個numpy的陣列的

我想找到每個1其最接近的「邊緣的距離'(邊緣是1符合0的地方)。

玩具例子:

原始數組:

array([[0, 0, 0, 0], 
     [0, 1, 1, 1], 
     [0, 1, 1, 1], 
     [0, 1, 1, 1]]) 

結果:

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

如果可能的話,我想用 'cityblock' 的距離,但這是低優先級

謝謝!

回答

2

下面是一個使用量化方法binary_erosion & cdist(..'cityblock') -

from scipy.ndimage.morphology import binary_erosion 
from scipy.spatial.distance import cdist 

def dist_from_edge(img): 
    I = binary_erosion(img) # Interior mask 
    C = img - I    # Contour mask 
    out = C.astype(int)  # Setup o/p and assign cityblock distances 
    out[I] = cdist(np.argwhere(C), np.argwhere(I), 'cityblock').min(0) + 1 
    return out 

採樣運行 -

In [188]: img.astype(int) 
Out[188]: 
array([[0, 0, 0, 0, 1, 0, 0], 
     [0, 1, 1, 1, 1, 1, 0], 
     [0, 1, 1, 1, 1, 1, 1], 
     [0, 1, 1, 1, 1, 1, 1], 
     [0, 0, 1, 1, 1, 1, 1], 
     [0, 0, 0, 1, 0, 0, 0]]) 

In [189]: dist_from_edge(img) 
Out[189]: 
array([[0, 0, 0, 0, 1, 0, 0], 
     [0, 1, 1, 1, 2, 1, 0], 
     [0, 1, 2, 2, 3, 2, 1], 
     [0, 1, 2, 3, 2, 2, 1], 
     [0, 0, 1, 2, 1, 1, 1], 
     [0, 0, 0, 1, 0, 0, 0]]) 

下面是一個輸入,輸出對人的斑點 -

enter image description hereenter image description here

+0

整潔 - 和觀賞性的代碼發展。 :) –

+0

@WarrenWeckesser是的,真棒的方法,我們得到了,所有與scipy! – Divakar

2

這裏是你可以用scipy.ndimage.distance_transform_cdt(或scipy.ndimage.distance_transform_bf)做到這一點的一種方法:

import numpy as np 
from scipy.ndimage import distance_transform_cdt 


def distance_from_edge(x): 
    x = np.pad(x, 1, mode='constant') 
    dist = distance_transform_cdt(x, metric='taxicab') 
    return dist[1:-1, 1:-1] 

例如:

In [327]: a 
Out[327]: 
array([[0, 0, 0, 0], 
     [0, 1, 1, 1], 
     [0, 1, 1, 1], 
     [0, 1, 1, 1]]) 

In [328]: distance_from_edge(a) 
Out[328]: 
array([[0, 0, 0, 0], 
     [0, 1, 1, 1], 
     [0, 1, 2, 1], 
     [0, 1, 1, 1]], dtype=int32) 

In [329]: x 
Out[329]: 
array([[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], 
     [1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0], 
     [1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0], 
     [1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0], 
     [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], 
     [1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0], 
     [0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1], 
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1]]) 

In [330]: distance_from_edge(x) 
Out[330]: 
array([[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], 
     [1, 2, 2, 2, 2, 1, 0, 0, 0, 1, 0, 0], 
     [1, 2, 3, 3, 2, 1, 0, 0, 1, 2, 1, 0], 
     [1, 2, 3, 3, 2, 1, 0, 0, 0, 1, 0, 0], 
     [1, 2, 3, 3, 2, 1, 0, 0, 0, 0, 0, 0], 
     [1, 1, 2, 2, 2, 1, 0, 0, 0, 1, 1, 0], 
     [0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 2, 1], 
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1]], dtype=int32) 

如果不墊用零數組,你得到的距離到最近的0 在陣列中

In [335]: distance_transform_cdt(a, metric='taxicab') 
Out[335]: 
array([[0, 0, 0, 0], 
     [0, 1, 1, 1], 
     [0, 1, 2, 2], 
     [0, 1, 2, 3]], dtype=int32) 

In [336]: distance_transform_cdt(x, metric='taxicab') 
Out[336]: 
array([[6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0], 
     [5, 5, 4, 3, 2, 1, 0, 0, 0, 1, 0, 0], 
     [4, 4, 4, 3, 2, 1, 0, 0, 1, 2, 1, 0], 
     [3, 3, 4, 3, 2, 1, 0, 0, 0, 1, 0, 0], 
     [2, 2, 3, 3, 2, 1, 0, 0, 0, 0, 0, 0], 
     [1, 1, 2, 2, 2, 1, 0, 0, 0, 1, 1, 0], 
     [0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 2, 1], 
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2]], dtype=int32) 

這裏使用scipy.ndimage.binary_erosion的不同方法。在我發現距離轉換函數之前,我寫了這個。我確信有更多更高效的方法,但這對於不太大的圖像來說應該是合理的。

import numpy as np 
from scipy.ndimage import binary_erosion 


def distance_from_edge(x): 
    dist = np.zeros_like(x, dtype=int) 
    while np.count_nonzero(x) > 0: 
     dist += x # Assumes x is an array of 0s and 1s, or bools. 
     x = binary_erosion(x) 
    return dist 

例如,

In [291]: a 
Out[291]: 
array([[0, 0, 0, 0], 
     [0, 1, 1, 1], 
     [0, 1, 1, 1], 
     [0, 1, 1, 1]]) 

In [292]: distance_from_edge(a) 
Out[292]: 
array([[0, 0, 0, 0], 
     [0, 1, 1, 1], 
     [0, 1, 2, 1], 
     [0, 1, 1, 1]]) 

In [293]: x 
Out[293]: 
array([[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], 
     [1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0], 
     [1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0], 
     [1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0], 
     [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], 
     [1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0], 
     [0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1], 
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1]]) 

In [294]: distance_from_edge(x) 
Out[294]: 
array([[1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], 
     [1, 2, 2, 2, 2, 1, 0, 0, 0, 1, 0, 0], 
     [1, 2, 3, 3, 2, 1, 0, 0, 1, 2, 1, 0], 
     [1, 2, 3, 3, 2, 1, 0, 0, 0, 1, 0, 0], 
     [1, 2, 3, 3, 2, 1, 0, 0, 0, 0, 0, 0], 
     [1, 1, 2, 2, 2, 1, 0, 0, 0, 1, 1, 0], 
     [0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 2, 1], 
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1]])