web-dev-qa-db-fra.com

Comment mettre à jour la fenêtre imshow () de matplotlib de manière interactive?

Je travaille sur un algorithme de vision par ordinateur et j'aimerais montrer comment un tableau numpy change à chaque étape.

Ce qui fonctionne maintenant, c’est que si j’ai une simple imshow( array ) à la fin de mon code, la fenêtre s’affiche et affiche l’image finale.

Cependant, ce que j'aimerais faire est de mettre à jour et d'afficher la fenêtre imshow au fur et à mesure que l'image change à chaque itération. 

Donc, par exemple, j'aimerais faire:

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)

Le problème est que de cette façon, la fenêtre Matplotlib n'est pas activée, une fois que le calcul est terminé.

J'ai essayé à la fois natif matplotlib et pyplot, mais les résultats sont les mêmes. Pour les commandes de traçage, j'ai trouvé un commutateur .ion(), mais ici, il ne semble pas fonctionner.

Q1. Quel est le meilleur moyen d’afficher en continu les mises à jour d’un tableau numpy (en fait une image en niveaux de gris uint8)?

Q2. Est-il possible de faire cela avec une fonction d’animation, comme dans le exemple d’image dynamique ? J'aimerais appeler une fonction dans une boucle, donc je ne sais pas comment y parvenir avec une fonction d'animation.

28
hyperknot

Vous n'avez pas besoin d'appeler imshow tout le temps. Il est beaucoup plus rapide d'utiliser la méthode set_data de l'objet:

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

La draw() doit s'assurer que le serveur met à jour l'image.

MISE À JOUR: votre question a été modifiée de manière significative. Dans de tels cas, il est préférable de poser une autre question. Voici un moyen de traiter votre deuxième question:

L'animation de Matplotlib ne traite que d'une dimension croissante (le temps), votre double boucle ne fera donc pas l'affaire. Vous devez convertir vos index en un seul index. Voici un exemple:

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)
30
tiago

J'ai mis en place un script pratique qui répond à vos besoins. Essayez-le ici

Un exemple qui dessine une onde sinusoïdale dynamique:

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)
1
Bily