【问题标题】:How can I make a video from array of images in matplotlib?如何从 matplotlib 中的图像数组制作视频?
【发布时间】:2016-04-30 18:44:25
【问题描述】:

我有几张图片展示了事物是如何随时间变化的。我使用以下代码将它们可视化为同一图上的许多图像:

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()

并得到类似:

这没关系,但我宁愿为它们制作动画以获取something like this video。如何使用 python 实现这一点,最好(不一定)使用 matplotlib

【问题讨论】:

  • 您附加的视频链接已损坏!你能解决这个问题吗?

标签: python matplotlib animation video-processing


【解决方案1】:

这是一个可复制粘贴的功能,如果您正在处理长视频并使用流式迭代器(来自here),则非常方便

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()

【讨论】:

    【解决方案2】:

    另一种解决方案是使用matplotlib.animation 中的AnimationArtist,如animated image demo 中所述。适应您的示例将是

    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()
    

    【讨论】:

    • 这里的ims是什么?
    • @PyWalker2797 一个错字。现在应该修好了。
    【解决方案3】:

    您可以使用 Agg 接口从 matplotlib 导出图像。

    查看这些示例:

    这是您的完整代码:

    # 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()
    

    【讨论】:

      【解决方案4】:

      您可以尝试延迟按顺序绘制图像(帧)。如果您有很多帧,那么在 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
      

      【讨论】:

      • 除了提供代码之外,最好能解释一下解决方案并添加一些细节。
      【解决方案5】:

      我实现了一个适合您和新手的便捷脚本。试试看here

      你的例子:

      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)
      

      【讨论】:

        【解决方案6】:

        我自己的未来是这样的:

        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)
        

        【讨论】:

          【解决方案7】:

          例如,您可以使用plt.savefig("file%d.png" % i) 将图像导出为 png,然后使用 ffmpeg 生成视频。

          Here you find help to generate video from images

          【讨论】:

            猜你喜欢
            • 2012-12-23
            • 2015-06-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多