如何从 matplotlib 中的图像数组制作视频?
Posted
技术标签:
【中文标题】如何从 matplotlib 中的图像数组制作视频?【英文标题】:How can I make a video from array of images in 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
【问题讨论】:
您附加的视频链接已损坏!你能解决这个问题吗? 【参考方案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 导出图像。
查看这些示例:
Agg Buffer to Array CanvasAgg demo这是您的完整代码:
# 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
【讨论】:
以上是关于如何从 matplotlib 中的图像数组制作视频?的主要内容,如果未能解决你的问题,请参考以下文章
从 Python 的 pandas 中的数据帧制作 matplotlib 散点图