无法用ffmpeg保存matplotlib动画

2024-04-26 00:19:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图从Jake Vanderplas中保存一个简单的matplotlib动画,但是我一直得到OSError: [Errno 13] Permission denied

我应该注意到我对Jake Vanderplas的例子做了两个小的修改。我从MacPorts安装了ffmpeg,所以添加了plt.rcParams['animation.ffmpeg_path'] = '/opt/local/bin'行,遇到了(Using FFmpeg and IPython)中讨论的问题,所以添加了FFwriter = animation.FFMpegWriter()

代码如下:

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
plt.rcParams['animation.ffmpeg_path'] = '/opt/local/bin'

fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)

def init():
    line.set_data([], [])
    return line,

def animate(i):
    x = np.linspace(0, 2, 1000)
    y = np.sin(2 * np.pi * (x - 0.01 * i))
    line.set_data(x, y)
    return line,

anim = animation.FuncAnimation(fig, animate, init_func=init,
                           frames=200, interval=20, blit=True)

FFwriter = animation.FFMpegWriter()
anim.save('basic_animation.mp4', writer = FFwriter, fps=30, extra_args=['-vcodec', 'libx264'])

这是回溯:

File "ani_debug.py", line 34, in <module>
  anim.save('basic_animation.mp4', writer = FFwriter, fps=30, extra_args=['-vcodec', 'libx264'])
File "/Users/Ben/Library/Enthought/Canopy_64bit/User/lib/python2.7/site- packages/matplotlib/animation.py", line 712, in save
  with writer.saving(self._fig, filename, dpi):
File "/Applications/Canopy.app/appdata/canopy-1.3.0.1715.macosx-x86_64/Canopy.app/Contents/lib/python2.7/contextlib.py", line 17, in __enter__
  return self.gen.next()
File "/Users/Ben/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/matplotlib/animation.py", line 169, in saving
  self.setup(*args)
File "/Users/Ben/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/matplotlib/animation.py", line 159, in setup
  self._run()
File "/Users/Ben/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/matplotlib/animation.py", line 186, in _run
  stdin=subprocess.PIPE)
File "/Applications/Canopy.app/appdata/canopy-1.3.0.1715.macosx-x86_64/Canopy.app/Contents/lib/python2.7/subprocess.py", line 709, in __init__
  errread, errwrite)
File "/Applications/Canopy.app/appdata/canopy-1.3.0.1715.macosx-x86_64/Canopy.app/Contents/lib/python2.7/subprocess.py", line 1326, in _execute_child
  raise child_exception
OSError: [Errno 13] Permission denied

我也尝试过使用Spyder的内置python,并收到了类似的回溯。有什么建议吗?


编辑:我意识到我没有给出正确的ffmpeg路径。显然,plt.rcParams['animation.ffmpeg_path']的工作方式与PYTHONPATH不同。必须使用plt.rcParams['animation.ffmpeg_path'] = '/opt/local/bin/ffmpeg'准确地告诉动画模块ffmpeg的位置。

现在,我得到一个电影文件,将播放,但内容是完全混乱。我不知道我在看什么。

这是回溯:

Exception in Tkinter callback
Traceback (most recent call last):
  File "Tkinter.pyc", line 1470, in __call__
  File "Tkinter.pyc", line 531, in callit
  File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/backends/backend_tkagg.py", line 141, in _on_timer
    TimerBase._on_timer(self)
  File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/backend_bases.py", line 1203, in _on_timer
    ret = func(*args, **kwargs)
  File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 876, in _step
    still_going = Animation._step(self, *args)
  File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 735, in _step
    self._draw_next_frame(framedata, self._blit)
  File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 753, in _draw_next_frame
    self._pre_draw(framedata, blit)
  File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 766, in _pre_draw
    self._blit_clear(self._drawn_artists, self._blit_cache)
  File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 806, in _blit_clear
    a.figure.canvas.restore_region(bg_cache[a])
KeyError: <matplotlib.axes.AxesSubplot object at 0x104cfb150>

编辑: 不知为什么,现在一切都很好。我在家用电脑和工作电脑上试过一些东西,但是在我修复了ffmpeg路径问题之后,没有人能重新创建我得到的混乱的视频文件。


编辑: 啊哈!我找到了这个混蛋。有时我会导入一个包含plt.rcParams['savefig.bbox'] = 'tight'的模块。(我永远不会使用该模块,但rcParams会一直存在,直到重新启动python解释器。)该设置会导致视频全部乱码。我将在下面发布我的解决方案。


Tags: inpyselfappmatplotlibliblinecontents
3条回答

Stretch's answer之后,我发现传递给anim.save()的一些参数似乎没有达到预期的效果。特别是fps是5(默认值),而不是设置的30。通过将fps=30传递给animation.FFMpegWriter,它确实起作用。

所以:

FFwriter = animation.FFMpegWriter(fps=30)
anim.save('basic_animation.mp4', writer=FFwriter, extra_args=['-vcodec', 'libx264'])

请注意,视频现在为7秒长(200帧,每秒30帧),而不是40秒(200帧,每秒5帧)。还要注意,5 fps的默认值对应于FuncAnimation中的默认200 ms/帧间隔,严格地说,这里使用的20 ms动画间隔对应于50 fps。

对于那些努力获得更好视频质量的人,也可以将比特率(以kbps为单位的整数)传递给animation.FFMpegWriter,例如:

FFwriter = animation.FFMpegWriter(fps=30, bitrate=2000)

为了达到更好的质量,我尝试了各种额外的方法,但没有成功。

当我第一次(天真地)试图修改工作时,我遇到了一些麻烦 回答3的例子实时显示图形(以及保存电影)。

回答3的模子不太对(对我有用)

  1. plt.ion()#交互打开
  2. plt.draw()plt.show()在animate函数中,返回statent之前
  3. frames=20,interval=200来减缓图形的创建速度,但仍然可以制作4秒的电影

现在plot在创建时显示在一个窗口中, 但是输出的电影是乱七八糟的。

纠正步骤2:

  • 2a:plt.draw()内部动画功能
  • 2b:plt.show()在动画函数之后

现在这部电影重播了。

结果发现有两个问题。

问题1:到ffmpeg的路径错误。我想我需要提供到ffmpeg所在目录的路径,但我需要提供到ffmpeg二进制文件的所有路径。

问题2:在测试代码生成视频之前,我有时会导入设置为plt.rcParams['savefig.bbox'] = 'tight'的模块。(我没有考虑太多,因为我没有使用该模块,但是rcParams会一直存在,直到您重新启动python解释器。)这个plt.rcParams['savefig.bbox'] = 'tight'会导致视频文件保存而没有任何错误,但是当您尝试播放视频时,所有帧都会出现混乱。虽然我花了整整一个晚上才找到这个,但事实证明这是a known issue

这是一个更新的解决方案,创建一个视频文件,我与一个不错的,翻译,正弦波。

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
plt.rcParams['animation.ffmpeg_path'] = '/opt/local/bin/ffmpeg'

fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)

def init():
    line.set_data([], [])
    return line,

def animate(i):
    x = np.linspace(0, 2, 1000)
    y = np.sin(2 * np.pi * (x - 0.01 * i))
    line.set_data(x, y)
    return line,

anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True)

FFwriter = animation.FFMpegWriter()
anim.save('basic_animation.mp4', writer = FFwriter, fps=30, extra_args=['-vcodec', 'libx264'])

相关问题 更多 >