【问题标题】:Matplotlib.animation: how to remove white marginMatplotlib.animation:如何去除白边
【发布时间】:2013-03-30 17:30:22
【问题描述】:

我尝试使用 matplotlib 电影编写器生成电影。如果我这样做,我总是会在视频周围出现白边。有谁知道如何删除该边距?

来自http://matplotlib.org/examples/animation/moviewriter.html的调整示例

# This example uses a MovieWriter directly to grab individual frames and
# write them to a file. This avoids any event loop integration, but has
# the advantage of working with even the Agg backend. This is not recommended
# for use in an interactive setting.
# -*- noplot -*-

import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.animation as manimation

FFMpegWriter = manimation.writers['ffmpeg']
metadata = dict(title='Movie Test', artist='Matplotlib',
        comment='Movie support!')
writer = FFMpegWriter(fps=15, metadata=metadata, extra_args=['-vcodec', 'libx264'])

fig = plt.figure()
ax = plt.subplot(111)
plt.axis('off')
fig.subplots_adjust(left=None, bottom=None, right=None, wspace=None, hspace=None)
ax.set_frame_on(False)
ax.set_xticks([])
ax.set_yticks([])
plt.axis('off')

with writer.saving(fig, "writer_test.mp4", 100):
    for i in range(100):
        mat = np.random.random((100,100))
        ax.imshow(mat,interpolation='nearest')
        writer.grab_frame()

【问题讨论】:

    标签: python animation video matplotlib


    【解决方案1】:

    None 作为参数传递给subplots_adjust 并不会像您认为的(doc) 那样做。这意味着“使用默认值”。要执行您想要的操作,请改用以下内容:

    fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=None, hspace=None)
    

    如果您重复使用 ImageAxes 对象,您还可以使您的代码更加高效

    mat = np.random.random((100,100))
    im = ax.imshow(mat,interpolation='nearest')
    with writer.saving(fig, "writer_test.mp4", 100):
        for i in range(100):
            mat = np.random.random((100,100))
            im.set_data(mat)
            writer.grab_frame()
    

    默认情况下imshow 将纵横比固定为相等,即您的像素是正方形的。您要么需要重新调整图形大小,使其与图像的纵横比相同:

    fig.set_size_inches(w, h, forward=True)
    

    或告诉imshow 使用任意纵横比

    im = ax.imshow(..., aspect='auto')
    

    【讨论】:

    • 使用subplots_adjust 只会删除顶部和底部的边距。我仍然在视频的左右两侧留有白边。不知何故我做不到im.set_cdata(mat)。我得到了错误:AttributeError: 'AxesImage' object has no attribute 'set_cdata'
    • 太棒了,解决了我的问题。没有余量,使用set_data 确实使整个过程更快!
    • 您的附加评论“如果您重新使用 ImageAxes 对象,您还可以使您的代码更有效率”真的帮助了我。由于此更改,程序在动画期间使用的内存更少。
    【解决方案2】:

    我整天搜索这个并最终在创建每个图像时使用@matehat 的这个解决方案。

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

    制作一个没有框架的图形:

    fig = plt.figure(frameon=False)
    fig.set_size_inches(w,h)
    

    使内容填满整个图形

    ax = plt.Axes(fig, [0., 0., 1., 1.])
    ax.set_axis_off()
    fig.add_axes(ax)
    

    绘制第一帧,假设您的电影存储在“imageStack”中:

    movieImage = ax.imshow(imageStack[0], aspect='auto')
    

    然后我写了一个动画函数:

    def animate(i):
        movieImage.set_array(imageStack[i])
        return movieImage
    
    anim = animation.FuncAnimation(fig,animate,frames=len(imageStack),interval=100)
    anim.save('myMovie.mp4',fps=20,extra_args=['-vcodec','libx264']
    

    效果很好!

    这是空白删除解决方案的链接:

    1:remove whitespace from image

    【讨论】:

    • 我建议准确指出帮助您和/或回答用户问题的部分,然后参考链接:)
    【解决方案3】:

    在最近的build of matplotlib 中,您似乎可以将参数传递给作者:

    def grab_frame(self, **savefig_kwargs):
            '''
            Grab the image information from the figure and save as a movie frame.
            All keyword arguments in savefig_kwargs are passed on to the 'savefig'
            command that saves the figure.
            '''
            verbose.report('MovieWriter.grab_frame: Grabbing frame.',
                           level='debug')
            try:
                # Tell the figure to save its data to the sink, using the
                # frame format and dpi.
                self.fig.savefig(self._frame_sink(), format=self.frame_format,
                    dpi=self.dpi, **savefig_kwargs)
            except RuntimeError:
                out, err = self._proc.communicate()
                verbose.report('MovieWriter -- Error running proc:\n%s\n%s' % (out,
                    err), level='helpful')
                raise
    

    如果是这种情况,您可以将bbox_inches="tight"pad_inches=0 传递给grab_frame -> savefig,这应该会删除大部分边框。然而,Ubuntu 上的最新版本仍然有这个代码:

    def grab_frame(self):
        '''
        Grab the image information from the figure and save as a movie frame.
        '''
        verbose.report('MovieWriter.grab_frame: Grabbing frame.',
                       level='debug')
        try:
            # Tell the figure to save its data to the sink, using the
            # frame format and dpi.
            self.fig.savefig(self._frame_sink(), format=self.frame_format,
                dpi=self.dpi)
        except RuntimeError:
            out, err = self._proc.communicate()
            verbose.report('MovieWriter -- Error running proc:\n%s\n%s' % (out,
                err), level='helpful')
            raise
    

    所以看起来功能正在被添加。抓住这个版本并试一试!

    【讨论】:

    • 我对@9​​87654326@ 的体验非常糟糕,因为抓取帧的像素大小和写入器的像素大小配置为不匹配并获得垃圾电影。如果要对此进行测试,请通过 rcparam 设置 bbox_inches 值。
    • @tcaswell 有趣,这听起来像是一个错误,应该报告。我无法在这台计算机上测试该版本,所以我试图从源头上得到答案。
    • 这不是错误,它只是需要固定帧大小(以像素为单位)的 mp4 与使用紧密边界框时生成不同大小图像的 mpl 之间的不良交互。更好地控制这一点(我认为)需要打破 mpl 在用户和渲染细节之间存在的一些很好的抽象障碍。
    • 我刚刚通过 pip 更新到 matplotlib 1.2.1。它还没有包括在内。我有点急于更新到 git HEAD,因为我需要绘图稳定。我会等待并尝试下一个版本。
    • @P.R.另一种方法是放弃 matplotlib 动画编写器并自己制作电影。这真的不是太难(尤其是如果您使用的是 Unix 发行版),您只需将电影按顺序生成为图像并在它们上运行类似ffmpeg 的东西。在那个级别,您将拥有完全的控制权。
    【解决方案4】:

    如果您“只是”想保存没有轴注释的矩阵的 matshow/imshow 渲染,那么 scikit-video (skvideo) 的最新开发人员版本也可能是相关的, - 如果您安装了 avconv。分布中的一个示例显示了由 numpy 函数构造的动态图像:https://github.com/aizvorski/scikit-video/blob/master/skvideo/examples/test_writer.py

    这是我对示例的修改:

    # Based on https://github.com/aizvorski/scikit-video/blob/master/skvideo/examples/test_writer.py
    from __future__ import print_function
    
    from skvideo.io import VideoWriter
    import numpy as np
    
    w, h = 640, 480
    
    checkerboard = np.tile(np.kron(np.array([[0, 1], [1, 0]]), np.ones((30, 30))), (30, 30))
    checkerboard = checkerboard[:h, :w]
    
    filename = 'checkerboard.mp4'
    wr = VideoWriter(filename, frameSize=(w, h), fps=8)
    
    wr.open()
    for frame_num in range(300):
        checkerboard = 1 - checkerboard
        image = np.tile(checkerboard[:, :, np.newaxis] * 255, (1, 1, 3))
        wr.write(image)
        print("frame %d" % (frame_num))
    
    wr.release()
    print("done")
    

    【讨论】:

      猜你喜欢
      • 2017-06-03
      • 1970-01-01
      • 2022-06-15
      • 2023-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-07
      • 1970-01-01
      相关资源
      最近更新 更多