Как сделать видео из массива изображений в matplotlib?

У меня есть пара изображений, которые показывают, как что-то меняется во времени. Я визуализирую их как множество изображений на одном графике с помощью следующего кода:

import matplotlib.pyplot as plt
import matplotlib.cm as cm

img = [] # some array of images
fig = plt.figure()
for i in xrange(6):
    fig.add_subplot(2, 3, i + 1)
    plt.imshow(img[i], cmap=cm.Greys_r)

plt.show()

и получите что-то вроде: введите здесь описание изображения

Это нормально, но я бы предпочел анимировать их, чтобы получить что-то нравится это видео. Как я могу добиться этого с помощью python и желательно (не обязательно) с помощью matplotlib


person Salvador Dali    schedule 24.01.2016    source источник


Ответы (7)


На будущее, вот что у меня получилось:

def generate_video(img):
    for i in xrange(len(img)):
        plt.imshow(img[i], cmap=cm.Greys_r)
        plt.savefig(folder + "/file%02d.png" % i)

    os.chdir("your_folder")
    subprocess.call([
        'ffmpeg', '-framerate', '8', '-i', 'file%02d.png', '-r', '30', '-pix_fmt', 'yuv420p',
        'video_name.mp4'
    ])
    for file_name in glob.glob("*.png"):
        os.remove(file_name)
person Salvador Dali    schedule 25.01.2016

Другое решение — использовать AnimationArtist из matplotlib.animation, как описано в демонстрации анимированного изображения. Адаптация для вашего примера будет

import matplotlib.pyplot as plt
import matplotlib.cm as cm
import matplotlib.animation as animation

img = [] # some array of images
frames = [] # for storing the generated images
fig = plt.figure()
for i in xrange(6):
    frames.append([plt.imshow(img[i], cmap=cm.Greys_r,animated=True)])

ani = animation.ArtistAnimation(fig, frames, interval=50, blit=True,
                                repeat_delay=1000)
# ani.save('movie.mp4')
plt.show()
person Keith Prussing    schedule 14.09.2018
comment
при чем тут имс? - person PyWalker2797; 18.12.2019
comment
@PyWalker2797 опечатка. Должно быть исправлено сейчас. - person Keith Prussing; 18.12.2019

Вы можете экспортировать изображения из matplotlib, используя интерфейс Agg.

См. эти примеры:

Вот ваш полный код:

# imports
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import cv2

# Use Agg backend for canvas
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas

# create OpenCV video writer
video = cv2.VideoWriter('video.mp4', cv2.VideoWriter_fourcc('A','V','C','1'), 1, (mat.shape[0],mat.shape[1]))

# loop over your images
for i in xrange(len(img)):

    fig = plt.figure()
    plt.imshow(img[i], cmap=cm.Greys_r)

    # put pixel buffer in numpy array
    canvas = FigureCanvas(fig)
    canvas.draw()
    mat = np.array(canvas.renderer._renderer)
    mat = cv2.cvtColor(mat, cv2.COLOR_RGB2BGR)

    # write frame to video
    video.write(mat)

# close video writer
cv2.destroyAllWindows()
video.release()
person darkdragon    schedule 16.07.2019

Например, вы можете экспортировать изображения в png, используя plt.savefig("file%d.png" % i), а затем использовать ffmpeg для создания видео.

Здесь вы найдете помощь в создании видео из изображений

person David Frank    schedule 24.01.2016

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

Для вашего примера:

imagelist = YOUR-IMAGE-LIST
def redraw_fn(f, axes):
    img = imagelist[f]
    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(imagelist), redraw_fn, play_fps=30)
person Bily    schedule 03.11.2017

Можно попробовать отрисовывать изображения (кадры) последовательно с задержкой. Если у вас много кадров, может иметь смысл уменьшить время ожидания между кадрами в функции plt.pause().

# need this line if you're using jupyter notebooks
%matplotlib notebook

x = [] # Some array of images
fig = plt.figure()
viewer = fig.add_subplot(111)
plt.ion() # Turns interactive mode on (probably unnecessary)
fig.show() # Initially shows the figure

for i in range(len(x)):
    viewer.clear() # Clears the previous image
    viewer.imshow(x[i]) # Loads the new image
    plt.pause(.1) # Delay in seconds
    fig.canvas.draw() # Draws the image to the screen
person saetch_g    schedule 08.04.2019
comment
Было бы здорово объяснить решение и добавить некоторые детали в дополнение к предоставлению кода. - person Peyman; 08.04.2019

Вот функция копирования и вставки, удобная, если вы имеете дело с длинными видео и используете потоковый итератор (из здесь)

from typing import Iterator, Optional, Tuple
from pathlib import Path

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np


def write_animation(
    itr: Iterator[np.array],
    out_file: Path,
    dpi: int = 50,
    fps: int = 30,
    title: str = "Animation",
    comment: Optional[str] = None,
    writer: str = "ffmpeg",
) -> None:
    """Function that writes an animation from a stream of input tensors.

    Args:
        itr: The image iterator, yielding images with shape (H, W, C).
        out_file: The path to the output file.
        dpi: Dots per inch for output image.
        fps: Frames per second for the video.
        title: Title for the video metadata.
        comment: Comment for the video metadata.
        writer: The Matplotlib animation writer to use (if you use the
            default one, make sure you have `ffmpeg` installed on your
            system).
    """

    first_img = next(itr)
    height, width, _ = first_img.shape
    fig, ax = plt.subplots(figsize=(width / dpi, height / dpi))

    # Ensures that there's no extra space around the image.
    fig.subplots_adjust(
        left=0,
        bottom=0,
        right=1,
        top=1,
        wspace=None,
        hspace=None,
    )

    # Creates the writer with the given metadata.
    Writer = mpl.animation.writers[writer]
    metadata = {
        "title": title,
        "artist": __name__,
        "comment": comment,
    }
    mpl_writer = Writer(
        fps=fps,
        metadata={k: v for k, v in metadata.items() if v is not None},
    )

    with mpl_writer.saving(fig, out_file, dpi=dpi):
        im = ax.imshow(first_img, interpolation="nearest")
        mpl_writer.grab_frame()

        for img in itr:
            im.set_data(img)
            mpl_writer.grab_frame()
person benja    schedule 30.04.2021