Как анимировать упорядоченную по времени последовательность графиков matplotlib - PullRequest
15 голосов
/ 14 июля 2011

Я хочу построить последовательность изображений .png в matplotlib. Цель состоит в том, чтобы построить их быстро, чтобы имитировать эффект фильма, но у меня есть дополнительные причины для того, чтобы не создавать файл .avi и не сохранять рисунки matplotlib, а затем просматривать их в последовательности вне Python.

Я специально пытаюсь просмотреть файлы изображений в последовательности внутри цикла for в Python. Предполагая, что я импортировал matplotlib правильно, и у меня есть свои собственные функции 'new_image ()' и 'new_rect ()', вот несколько примеров кода, который не работает из-за эффекта блокировки вызова функции show () к mainloop GUI:

 for index in index_list:
     img = new_image(index)
     rect = new_rect(index)

     plt.imshow(img)
     plt.gca().add_patch(rect)
     plt.show()

     #I also tried pausing briefly and then closing, but this doesn't
     #get executed due to the GUI mainloop from show()
     time.sleep(0.25)
     plt.close()

Приведенный выше код работает, чтобы показать только первое изображение, но затем программа просто зависает и ждет, пока я вручную закрою окно с результирующим рисунком. Как только я закрываю его, программа просто зависает и не перерисовывает новые данные изображения. Что мне делать? Также обратите внимание, что я попытался заменить команду plt.show () командой plt.draw (), а затем добавить plt.show () вне цикла for. Это ничего не отображает и просто зависает.

Ответы [ 3 ]

8 голосов
/ 14 июля 2011

На основе http://matplotlib.sourceforge.net/examples/animation/simple_anim_tkagg.html:

import time
import numpy as np
import matplotlib
matplotlib.use('TkAgg') # do this before importing pylab

import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)

def animate():
    tstart = time.time()                   # for profiling
    data=np.random.randn(10,10)
    im=plt.imshow(data)

    for i in np.arange(1,200):
        data=np.random.randn(10,10)
        im.set_data(data)
        fig.canvas.draw()                         # redraw the canvas
    print 'FPS:' , 200/(time.time()-tstart)

win = fig.canvas.manager.window
fig.canvas.manager.window.after(100, animate)
plt.show()

plt.imshow может принимать массив с плавающей запятой, массив uint8 или изображение PIL.Поэтому, если у вас есть каталог файлов PNG, вы можете открыть их как изображения PIL и анимировать их следующим образом:

import matplotlib
matplotlib.use('TkAgg') # do this before importing pylab
import matplotlib.pyplot as plt
import Image
import glob

fig = plt.figure()
ax = fig.add_subplot(111)

def animate():
    filenames=sorted(glob.glob('*.png'))
    im=plt.imshow(Image.open(filenames[0]))
    for filename in filenames[1:]:
        image=Image.open(filename)
        im.set_data(image)
        fig.canvas.draw() 

win = fig.canvas.manager.window
fig.canvas.manager.window.after(100, animate)
plt.show()
6 голосов
/ 13 апреля 2012

Лучший способ, который я нашел для этого, был с помощью команды pylab.ion() после импорта pylab.

Вот скрипт, который использует show(), но каждый раз отображает различные графики pylab.draw() называется, и это оставляет окна графика, отображающиеся на неопределенный срок.Он использует простую логику ввода, чтобы решить, когда закрывать фигуры (потому что использование show() означает, что pylab не будет обрабатывать щелчки на кнопке windows x), но это должно быть просто добавить к вашему графическому интерфейсу как другую кнопку или как текстовое поле.

import numpy as np
import pylab
pylab.ion()

def get_fig(fig_num, some_data, some_labels):

    fig = pylab.figure(fig_num,figsize=(8,8),frameon=False)
    ax = fig.add_subplot(111)
    ax.set_ylim([0.1,0.8]); ax.set_xlim([0.1, 0.8]);
    ax.set_title("Quarterly Stapler Thefts")
    ax.pie(some_data, labels=some_labels, autopct='%1.1f%%', shadow=True);
    return fig

my_labels = ("You", "Me", "Some guy", "Bob")

# To ensure first plot is always made.
do_plot = 1; num_plots = 0;

while do_plot:
    num_plots = num_plots + 1;
    data = np.random.rand(1,4).tolist()[0]

    fig = get_fig(num_plots,data,my_labels)
    fig.canvas.draw()
    pylab.draw()

    print "Close any of the previous plots? If yes, enter its number, otherwise enter 0..."
    close_plot = raw_input()

    if int(close_plot) > 0:
        pylab.close(int(close_plot))

    print "Create another random plot? 1 for yes; 0 for no."
    do_plot = raw_input();

    # Don't allow plots to go over 10.
    if num_plots > 10:
        do_plot = 0

pylab.show()

Изменяя основную логику здесь, я могу заставить его закрывать окна и наносить изображения последовательно для имитации воспроизведения фильма, или я могу контролировать клавиатуру, как она проходит по фильму.

Примечание: Это сработало для меня на разных платформах и, кажется, строго превосходит подход менеджера оконного полотна, описанный выше, и не требует опции 'TkAgg'.

0 голосов
/ 10 мая 2017

Я реализовал удобный скрипт, который просто соответствует вашим потребностям.Попробуйте здесь

Ниже приведен пример, который показывает изображения вместе с ограничительной рамкой:

import os
import glob
from scipy.misc import imread
from matplotlib.pyplot import Rectangle

video_dir = 'YOUR-VIDEO-DIRECTORY'

img_files = glob.glob(os.path.join(video_dir, '*.jpg'))
box_files = glob.glob(os.path.join(video_dir, '*.txt'))

def redraw_fn(f, axes):
    img = imread(img_files[f])
    box = bbread(box_files[f])  # Define your own bounding box reading utility
    x, y, w, h = box
    if not redraw_fn.initialized:
        im = axes.imshow(img, animated=True)
        bb = Rectangle((x, y), w, h,
                       fill=False,  # remove background
                       edgecolor="red")
        axes.add_patch(bb)
        redraw_fn.im = im
        redraw_fn.bb = bb
        redraw_fn.initialized = True
    else:
        redraw_fn.im.set_array(img)
        redraw_fn.bb.set_xy((x, y))
        redraw_fn.bb.set_width(w)
        redraw_fn.bb.set_height(h)
redraw_fn.initialized = False

videofig(len(img_files), redraw_fn, play_fps=30)
...