2016-06-28 22 views
5

Sto cercando quanto segue. Ho una matrice numpy che è etichettata come regioni. La matrice numpy rappresenta un'immagine segmentata. Una regione è un numero di celle adiacenti con lo stesso valore. Ogni regione ha il suo valore unico. Una versione semplificata con 3 regioni sarebbe simile a questa:Determinare le regioni adiacenti nell'array numpy

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

uscita:

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

Nell'esempio sopra abbiamo 3 regioni distinte, ciascuna marcata con un valore univoco (1,2,3 in questo caso).

Quello che voglio è il valore delle regioni adiacenti (vicini) per ogni singola regione. Quindi in questo caso:

  • Regione 1 è adiacente alla regione 2
  • Regione 2 è adiacente alla zona 1 e 3
  • regione 3 è adiacente alla regione 2

Quale sarebbe il modo più elegante e veloce per raggiungere questo?

Grazie mille!

+0

Puoi spiegare cosa intendi per regioni? Vuoi dire colonne? –

+0

Ho aggiunto alcune spiegazioni aggiuntive sulla definizione delle regioni in questo caso. – cf2

risposta

4

Capisco che il compito è quello di restituire tutte le voci distinte della matrice che sono adiacenti a un dato numero (ad esempio 2). Un modo per ottenere questo risultato con i metodi NumPy è utilizzare roll per spostare la regione specificata di un'unità verso l'alto, il basso, sinistra e destra. L'OR logico delle regioni spostate viene preso e vengono restituiti tutti gli elementi distinti che corrispondono a questa condizione. Rimane quindi da rimuovere la regione stessa, dal momento che non è considerata il suo vicino.

Poiché roll reintroduce i valori che si muovono oltre i limiti dell'array alle estremità opposte (che non è desiderato qui), un ulteriore passo è sostituire questa riga o colonna con 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

Funziona perfettamente. L'ho anche testato su un grande set di dati, dove le regioni sono numerate casualmente e lì funziona anche come dovrebbe. Mille grazie per la tua soluzione! – cf2

2

Se le regioni sono etichettati con numeri piccoli (dalla 0 a n idealmente), le etichette possono essere usate per indicizzare una matrice risultato:

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) 

Per l'esempio matrice nella domanda:

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

Mi piace molto la soluzione in quanto restituisce un array di risultati indicizzati per tutte le regioni. Tuttavia, le mie regioni sono numerate casualmente e, a causa di ciò, la tua soluzione purtroppo non funziona sul mio set di dati. Grazie comunque per lo sforzo! Terrò questa soluzione per quando avrò un set di dati con regioni ordinate. – cf2

Problemi correlati