How to update matplotlib's imshow() window interactively?

后端 未结 4 1515
孤独总比滥情好
孤独总比滥情好 2020-11-30 05:19

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(

相关标签:
4条回答
  • 2020-11-30 05:52

    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)
    
    0 讨论(0)
  • 2020-11-30 06:04

    I implemented a handy script that just suits your needs. Try it out here

    An example that shows images in a custom directory is like this:

      import os
      import glob
      from scipy.misc import imread
    
      img_dir = 'YOUR-IMAGE-DIRECTORY'
      img_files = glob.glob(os.path.join(video_dir, '*.jpg'))
    
      def redraw_fn(f, axes):
        img_file = img_files[f]
        img = imread(img_file)
        if not redraw_fn.initialized:
          redraw_fn.im = axes.imshow(img, animated=True)
          redraw_fn.initialized = True
        else:
          redraw_fn.im.set_array(img)
      redraw_fn.initialized = False
    
      videofig(len(img_files), redraw_fn, play_fps=30)
    
    0 讨论(0)
  • 2020-11-30 06:07

    I struggled to make it work because many post talk about this problem, but no one seems to care about providing a working example. In this case however, the reasons were different :

    • I couln't use Tiago's or Bily's answers because they are not in the same paradigm as the question. In the question, the refresh is scheduled by the algorithm itself, while with funcanimation or videofig, we are in an event driven paradigm. Event drivent programming is unavoidable for modern user interface programming, but when you start from a complex algorithm, it might be difficult to convert it to an event driven scheme - and I wanted to be able to do it in the classic procedural paradigm too.
    • Bub Espinja replied suffered another problem : I didn't try it in the context of jupyter notebooks, but repeating imshow is wrong since it recreates new data structures each time which causes an important memory leak and slows down the whole display process.

    Also Tiago mentioned calling draw(), but without specifying where to get it from - and by the way, you don't need it. the function you really need to call is flush_event(). sometime it works without, but it's because it has been triggered from somewhere else. You can't count on it. The real important point is that you cannot call imshow() on an empty table, or it will fail to initialize it's color map and set_data will fail too.

    Here is a working solution :

    IMAGE_SIZE = 500
    import numpy as np
    import matplotlib.pyplot as plt
    
    
    plt.ion()
    
    fig1, ax1 = plt.subplots()
    fig2, ax2 = plt.subplots()
    
    # this example doesn't work because array only contains zeroes
    array = np.zeros(shape=(IMAGE_SIZE, IMAGE_SIZE), dtype=np.uint8)
    axim1 = ax1.imshow(array)
    
    array[0, 0] = 99 # this value allow imshow to initialise it's color scale
    axim2 = ax2.imshow(array)
    
    del array
    
    for _ in range(50):
        print(".", end="")
        matrix = np.random.randint(0, 100, size=(IMAGE_SIZE, IMAGE_SIZE), dtype=np.uint8)
        
        axim1.set_data(matrix)
        fig1.canvas.flush_events()
        
        axim2.set_data(matrix)
        fig1.canvas.flush_events()
    print()
    
    0 讨论(0)
  • 2020-11-30 06:14

    If you are using Jupyter, maybe this answer interests you. I read in this site that the emmbebed function of clear_output can make the trick:

    %matplotlib inline
    from matplotlib import pyplot as plt
    from IPython.display import clear_output
    
    plt.figure()
    for i in range(len(list_of_frames)):
        plt.imshow(list_of_frames[i])
        plt.title('Frame %d' % i)
        plt.show()
        clear_output(wait=True)
    

    It is true that this method is quite slow, but it can be used for testing purposes.

    0 讨论(0)
提交回复
热议问题