這裏是你可以用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]])
整潔 - 和觀賞性的代碼發展。 :) –
@WarrenWeckesser是的,真棒的方法,我們得到了,所有與scipy! – Divakar