How to update matplotlib's imshow() window int

2019-01-07 17:43发布

问题:

I'm working on some computer vision algorithm and I'd like to show how a numpy array changes in each step.

What works now is that if I have a simple imshow( array ) at the end of my code, the window displays and shows the final image.

However what I'd like to do is to update and display the imshow window as the image changes in each iteration.

So for example I'd like to do:

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)

The problem is that this way, the Matplotlib window doesn't get activated, only once the whole computation is finished.

I've tried both native matplotlib and pyplot, but the results are the same. For plotting commands I found an .ion() switch, but here it doesn't seem to work.

Q1. What is the best way to continuously display updates to a numpy array (actually a uint8 greyscale image)?

Q2. Is it possible to do this with an animation function, like in the dynamic image example? I'd like to call a function inside a loop, thus I don't know how to achieve this with an animation function.

回答1:

You don't need to call imshow all the time. It is much faster to use the object's set_data method:

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

The draw() should make sure that the backend updates the image.

UPDATE: your question was significantly modified. In such cases it is better to ask another question. Here is a way to deal with your second question:

Matplotlib's animation only deals with one increasing dimension (time), so your double loop won't do. You need to convert your indices to a single index. Here is an example:

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)


回答2:

I implemented a handy script that just suit your need. Try it out here

An example that draws a dynamic sine wave:

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)