2016-06-28 9 views
5

Szukam następujących. Mam tablicę numpy oznaczoną jako regiony. Tablica numpy reprezentuje segmentowany obraz. Region to liczba sąsiednich komórek o tej samej wartości. Każdy region ma swoją unikalną wartość. Uproszczona wersja z 3 regionach będzie wyglądać następująco:Określanie sąsiednich regionów w tablicy numpy

x = np.array([[1, 1, 1], [1, 1, 2], [2, 2, 2], [3, 3, 3]], np.int32) 

Wydajność:

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

W powyższym przykładzie 3 oddzielne obszary, z których każdy oznaczony unikalną wartość (1,2,3 w ta sprawa).

To, czego chcę, to wartość sąsiadujących regionów (sąsiadów) dla każdego regionu. Więc w tym przypadku:

  • Region 1 przylega do obszaru 2
  • Region 2 przylega do obszaru 1 i 3
  • Region 3 przylega do obszaru 2

Jaki byłby najbardziej elegancki i najszybszy sposób na osiągnięcie tego?

Wielkie dzięki!

+0

Czy możesz wyjaśnić, co masz na myśli przez regiony? –

+0

Dodałem kilka dodatkowych wyjaśnień dotyczących definicji regionów w tym przypadku. – cf2

Odpowiedz

4

Rozumiem, że zadaniem jest zwrócenie wszystkich różnych pozycji tablicy, które sąsiadują z podaną liczbą (np. 2). Jednym ze sposobów osiągnięcia tego za pomocą metod NumPy jest użycie roll do przesunięcia danego regionu o jedną jednostkę w górę, w dół, w lewo i w prawo. Logiczne OR przesuniętych regionów jest brane i zwracane są wszystkie odrębne elementy, które pasują do tego warunku. Pozostaje wówczas usunąć sam region, ponieważ nie jest uważany za swojego sąsiada.

Ponieważ roll ponownie wprowadza wartości, które wykraczają poza granice tablicy na przeciwnych końcach (co nie jest tutaj pożądane), dodatkowym krokiem jest zastąpienie tego wiersza lub kolumny Fałszem.

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

To działa idealnie. Przetestowałem go również na dużym zbiorze danych, gdzie regiony są losowo ponumerowane i tam też działają tak, jak powinny. Wielkie dzięki za twoje rozwiązanie! – cf2

2

Jeśli obszary oznaczone są małymi liczbami całkowitymi (od 0 do n idealnie), etykiety mogą być wykorzystywane do indeksu w tabeli wyników:

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) 

, na przykładzie tablicy w kwestii:

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

Bardzo podoba mi się twoje rozwiązanie, ponieważ zwraca indeksowaną tablicę wyników dla wszystkich regionów. Jednak moje regiony są losowo ponumerowane iz tego powodu twoje rozwiązanie niestety nie działa na moim zestawie danych. Dzięki za wysiłek! Zachowam to rozwiązanie, gdy mam zbiór danych z uporządkowanymi regionami. – cf2