2013-07-24 19 views
18

Sto lavorando su un algoritmo di visione artificiale e mi piacerebbe mostrare come una matrice numpy cambia in ogni passaggio.Come aggiornare la finestra imshow() di matplotlib in modo interattivo?

Ciò che funziona ora è che se ho un semplice imshow(array) alla fine del mio codice, la finestra visualizza e mostra l'immagine finale.

Tuttavia, ciò che mi piacerebbe fare è aggiornare e visualizzare la finestra di anteprima mentre l'immagine cambia in ogni iterazione.

Così, per esempio mi piacerebbe fare:

import numpy as np 
import matplotlib.pyplot as plt 
import time 

array = np.zeros((100, 100), np.uint8) 

for i in xrange(0, 100): 
    for j in xrange(0, 50): 
     array[j, i] = 1 

     #_show_updated_window_briefly_ 
     plt.imshow(array) 
     time.sleep(0.1) 

Il problema è che in questo modo, la finestra Matplotlib non si attivano, solo una volta l'intero calcolo è finito.

Ho provato sia matplotlib nativo che pyplot, ma i risultati sono gli stessi. Per i comandi di tracciamento ho trovato uno switch .ion(), ma qui non sembra funzionare.

Q1. Qual è il modo migliore per visualizzare continuamente gli aggiornamenti su una matrice numpy (in realtà un'immagine in scala di grigi uint8)?

Q2. È possibile farlo con una funzione di animazione, come nel dynamic image example? Mi piacerebbe chiamare una funzione all'interno di un ciclo, quindi non so come ottenere ciò con una funzione di animazione.

+1

Può dipendere da quale backend si utilizza, ma provare a chiamare almeno un 'show()' o 'draw()' prima Avvio del ciclo - Vedi questo [risposta] (http://stackoverflow.com/questions/2130913/no-plot-window-in-matplotlib). – Bonlenfum

risposta

24

Non è necessario chiamare imshow tutto il tempo. E 'molto più veloce di utilizzare il metodo set_data dell'oggetto:

myobj = imshow(first_image) 
for pixel in pixels: 
    addpixel(pixel) 
    myobj.set_data(segmentedimg) 
    draw() 

Il draw() dovrebbe fare in modo che il backend aggiorna l'immagine.

AGGIORNAMENTO: la tua domanda è stata modificata in modo significativo. In questi casi è meglio fare un'altra domanda. Ecco un modo per affrontare la tua seconda domanda:

L'animazione di Matplotlib si occupa solo di una dimensione crescente (tempo), quindi il tuo doppio ciclo non funzionerà. Devi convertire i tuoi indici in un singolo indice. Ecco un esempio:

import numpy as np 
from matplotlib import pyplot as plt 
from matplotlib import animation 

nx = 150 
ny = 50 

fig = plt.figure() 
data = np.zeros((nx, ny)) 
im = plt.imshow(data, cmap='gist_gray_r', vmin=0, vmax=1) 

def init(): 
    im.set_data(np.zeros((nx, ny))) 

def animate(i): 
    xi = i // ny 
    yi = i % ny 
    data[xi, yi] = 1 
    im.set_data(data) 
    return im 

anim = animation.FuncAnimation(fig, animate, init_func=init, frames=nx * ny, 
           interval=50) 
+0

Purtroppo non funziona, succede la stessa cosa. Forse dovrei usare le funzioni di animazione, come nell'esempio di immagine dinamico: http://matplotlib.org/examples/animation/dynamic_image.html ma non so come posso trasformarlo in un codice basato su loop. – zsero

+0

@zsero: se la versione più semplice non funziona, mi chiedo se le animazioni più complesse funzioneranno. Ho appena aggiunto un esempio che funziona per me (matplotlib 1.2), vedi se funziona per te. – tiago

+1

Ho appena provato a modificare il tuo esempio e penso che 'im = imshow (data, ...)' dovrebbe leggere 'im = plt.imshow (data, ...)'. Inoltre, per eseguire l'animazione è necessario 'plt.show()'. Cheers – Chrigi

0

Ho implementato un comodo script che soddisfa le tue necessità. Provalo here

Un esempio che disegna una dinamica onda sinusoidale:

import numpy as np 

def redraw_fn(f, axes): 
    amp = float(f)/3000 
    f0 = 3 
    t = np.arange(0.0, 1.0, 0.001) 
    s = amp * np.sin(2 * np.pi * f0 * t) 
    if not redraw_fn.initialized: 
    redraw_fn.l, = axes.plot(t, s, lw=2, color='red') 
    redraw_fn.initialized = True 
    else: 
    redraw_fn.l.set_ydata(s) 

redraw_fn.initialized = False 

videofig(100, redraw_fn) 
Problemi correlati