2013-07-24 10 views
18

Ich arbeite an einem Computer Vision Algorithmus und ich möchte zeigen, wie sich ein numpliges Array in jedem Schritt ändert.Wie matplotlib's imshow() Fenster interaktiv aktualisieren?

Was jetzt funktioniert ist, dass, wenn ich eine einfache imshow(array) am Ende meines Codes habe, das Fenster angezeigt wird und das endgültige Bild zeigt.

Allerdings möchte ich das Imshow-Fenster aktualisieren und anzeigen, wie sich das Bild in jeder Iteration ändert.

zum Beispiel Also würde ich tun:

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) 

Das Problem ist, dass diese Art und Weise, die Matplotlib Fenster nicht aktiviert bekommen, nur einmal die ganze Berechnung abgeschlossen ist.

Ich habe sowohl native Matplotlib und Pyplot ausprobiert, aber die Ergebnisse sind die gleichen. Zum Plotten von Befehlen habe ich einen .ion() Schalter gefunden, aber hier scheint es nicht zu funktionieren.

Q1. Was ist der beste Weg, Updates für ein numpy Array (eigentlich ein Uint8 Graustufenbild) kontinuierlich anzuzeigen?

Q2. Ist es möglich, dies mit einer Animationsfunktion zu tun, wie in der dynamic image example? Ich würde gerne eine Funktion innerhalb einer Schleife aufrufen, daher weiß ich nicht, wie ich das mit einer Animationsfunktion erreichen soll.

+1

Es kann davon abhängen, welches Backend Sie verwenden, sondern versuchen, mindestens eine 'show() aufrufen' oder 'ziehen()' vor Starten Sie Ihre Schleife - Siehe hierzu [Antwort] (http://stackoverflow.com/questions/2130913/no-plot-window-in-matplotlib). – Bonlenfum

Antwort

24

Sie müssen die ganze Zeit nicht imshow anrufen. Es ist viel schneller auf das set_data Methode des Objekts zu verwenden:

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

Die draw() sollte sicherstellen, dass das Backend das Bild aktualisiert.

UPDATE: Ihre Frage wurde erheblich geändert. In solchen Fällen ist es besser, eine andere Frage zu stellen. Hier ist eine Möglichkeit, mit Ihrer zweiten Frage umzugehen:

Matplotlibs Animation behandelt nur eine zunehmende Dimension (Zeit), so dass Ihre Doppelschleife nicht ausreicht. Sie müssen Ihre Indizes in einen einzigen Index konvertieren. Hier ein Beispiel:

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

Leider klappt es nicht, das selbe passiert. Vielleicht sollte ich die Animationsfunktionen verwenden, wie im Beispiel des dynamischen Bildes: http://matplotlib.org/examples/animation/dynamic_image.html, aber ich weiß nicht, wie ich das in einen Schleifen-basierten Code umwandeln kann. – zsero

+0

@zsero: Wenn die einfachere Version nicht funktioniert, frage ich mich, ob die komplexeren Animationen funktionieren. Ich habe gerade ein Beispiel hinzugefügt, das für mich funktioniert (Matplotlib 1.2), sehen Sie, ob es für Sie funktioniert. – tiago

+1

Ich habe versucht, das Beispiel zu ändern, und ich denke 'im = imshow (data, ...)' sollte 'im = plt.imshow (data, ...)' lesen. Um die Animation zu starten, benötigen Sie 'plt.show()'. Prost – Chrigi

0

Ich habe ein praktisches Skript implementiert, das genau Ihren Anforderungen entspricht. Probieren Sie es aus here

Ein Beispiel, das eine dynamische Sinuswelle zieht:

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)