2011-01-26 10 views
16

Mi occupo di array creati tramite numpy.array() e ho bisogno di disegnare punti su una tela per simulare un'immagine. Dato che ci sono molti valori zero attorno alla parte centrale dell'array che contiene i dati significativi, vorrei "tagliare" l'array, cancellando le colonne che contengono solo zeri e righe che contengono solo zeri.Esiste una funzione "bounding box" (sezione con valori diversi da zero) per un narray in NumPy?

Quindi mi piacerebbe conoscere qualche funzione numpy nativa o anche uno snippet di codice da "ritagliare" o trovare un "riquadro di delimitazione" per tagliare solo la parte contenente l'array di dati.

(. In quanto si tratta di una domanda concettuale, non ho messo alcun codice, scusa se dovrei, io sono molto fresco al lavoro su SO)

Grazie per la lettura

+0

http://stackoverflow.com/questions/31400769/bounding-box-of-numpy-array vedere la funzione bbox2 ... MOLTO più veloce, se ci sono molte righe/colonne interamente riempite con zeri e solo una piccola quantità di dati in cluster. – Benjamin

risposta

6

Il codice qui sotto, da this answer piste più veloci nel mio test:

def bbox2(img): 
    rows = np.any(img, axis=1) 
    cols = np.any(img, axis=0) 
    ymin, ymax = np.where(rows)[0][[0, -1]] 
    xmin, xmax = np.where(cols)[0][[0, -1]] 
    return img[ymin:ymax+1, xmin:xmax+1] 

La risposta accettata utilizzando argwhere ha funzionato, ma correva più lento. La mia ipotesi è, è perché argwhere alloca una matrice di output gigante di indici. Ho eseguito il test su un array 2D di grandi dimensioni (un'immagine 1024 x 1024, con circa 50x100 di area diversa da zero).

+0

Ho trovato questa risposta molto più pitone! Grazie! – heltonbiker

+0

Attenzione, questo codice può generare un errore nel caso limite di un'immagine completamente nera. È necessario verificare che nessuna delle due chiamate 'np.where()' restituisce una matrice vuota. – Delgan

0

Qualcosa di simile:

empty_cols = sp.all(array == 0, axis=0) 
empty_rows = sp.all(array == 0, axis=1) 

Gli array risultanti saranno array 1D boolian. Fai un loop su di loro da entrambe le estremità per trovare il 'bounding box'.

+1

deve essere evitato il loop su array numpy – Paul

+0

Il ciclo è solo 1D, quindi l'ordine n, non n^2. Non è un grosso problema. – kiyo

+1

Hai ragione circa l'ordine e non hai nemmeno bisogno di un ciclo sull'intera larghezza dell'array, ma il loop python contiene tutti i tipi di passaggi extra come il controllo dei tipi. In questo esempio 1D: http://www.scipy.org/Getting_Started#head-9aed725bd569d40f625240b2b6ec710550ff14b9 Il loop python esegue 25X più lentamente per eseguire lo stesso compito! Senza conoscere la dimensione o la quantità delle immagini o l'applicazione dell'algoritmo (visione del computer?), Non posso dire quanto grande sia questo tipo di accelerazione. – Paul

20

Questo dovrebbe farlo:

from numpy import array, argwhere 

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

B = argwhere(A) 
(ystart, xstart), (ystop, xstop) = B.min(0), B.max(0) + 1 
Atrim = A[ystart:ystop, xstart:xstop] 
+1

Bello! Solo su una nota di leggibilità, si potrebbe fare '(ystart, xstart), (ystop, xstop) = B.min (0), B.max (0) + 1' e quindi semplicemente indice' A' con 'Atrim = a [ystart: ystop, xstart: xstop] '. Certo, è del tutto equivalente, ma lo trovo più leggibile, in ogni caso. –

+0

Fatto. Grazie, Joe. – Paul

+0

Questo andava bene, l'esempio che hai usato è esattamente l'array tipico che userei (solo più grande). Non conoscevo la funzione argwhere, ora farò i miei compiti. Grazie! – heltonbiker

Problemi correlati