MoviePy 数据动态可视化 图像转动态图或者视频
发布日期:2021-11-21 04:41:35 浏览次数:48 分类:技术文章

本文共 12757 字,大约阅读时间需要 42 分钟。

转载自:

Data Animations With Python and MoviePy

Nov 29th, 2014 |

Python has some great data visualization librairies, but few can render GIFs or video animations. This post shows how to use MoviePy as a generic animation plugin for any other library.

lets you define custom animations with a functionmake_frame(t), which returns the video frame corresponding to time t (in seconds):

123456789101112
from moviepy.editor import VideoClipdef make_frame(t):    """ returns an image of the frame at time t """    # ... create the frame with any library    return frame_for_time_t # (Height x Width x 3) Numpy arrayanimation = VideoClip(make_frame, duration=3) # 3-second clip# For the export, many options/formats/optimizations are supportedanimation.write_videofile("my_animation.mp4", fps=24) # export as videoanimation.write_gif("my_animation.gif", fps=24) # export as GIF (slow)

In previous posts I used this method to (with the library Gizeh), and (generated by POV-Ray). This post covers the scientific libraries Mayavi, Vispy, Matplotlib, Numpy, and Scikit-image.

Animations with Mayavi

is a Python module for interactive 3D data visualization with a simple interface. In this first example we animate a surface whose elevation depends on the timet:

12345678910111213141516171819202122
import numpy as npimport mayavi.mlab as mlabimport  moviepy.editor as mpyduration= 2 # duration of the animation in seconds (it will loop)# MAKE A FIGURE WITH MAYAVIfig_myv = mlab.figure(size=(220,220), bgcolor=(1,1,1))X, Y = np.linspace(-2,2,200), np.linspace(-2,2,200)XX, YY = np.meshgrid(X,Y)ZZ = lambda d: np.sinc(XX**2+YY**2)+np.sin(XX+d)# ANIMATE THE FIGURE WITH MOVIEPY, WRITE AN ANIMATED GIFdef make_frame(t):    mlab.clf() # clear the figure (to reset the colors)    mlab.mesh(YY,XX,ZZ(2*np.pi*t/duration), figure=fig_myv)    return mlab.screenshot(antialiased=True)animation = mpy.VideoClip(make_frame, duration=duration)animation.write_gif("sinc.gif", fps=20)

Another example with a wireframe mesh whose coordinates and view angle depend on the time :

12345678910111213141516171819202122232425262728
import numpy as npimport mayavi.mlab as mlabimport  moviepy.editor as mpyduration = 2 # duration of the animation in seconds (it will loop)# MAKE A FIGURE WITH MAYAVIfig = mlab.figure(size=(500, 500), bgcolor=(1,1,1))u = np.linspace(0,2*np.pi,100)xx,yy,zz = np.cos(u), np.sin(3*u), np.sin(u) # Pointsl = mlab.plot3d(xx,yy,zz, representation="wireframe", tube_sides=5,                line_width=.5, tube_radius=0.2, figure=fig)# ANIMATE THE FIGURE WITH MOVIEPY, WRITE AN ANIMATED GIFdef make_frame(t):    """ Generates and returns the frame for time t. """    y = np.sin(3*u)*(0.2+0.5*np.cos(2*np.pi*t/duration))    l.mlab_source.set(y = y) # change y-coordinates of the mesh    mlab.view(azimuth= 360*t/duration, distance=9) # camera angle    return mlab.screenshot(antialiased=True) # return a RGB imageanimation = mpy.VideoClip(make_frame, duration=duration).resize(0.5)# Video generation takes 10 seconds, GIF generation takes 25sanimation.write_videofile("wireframe.mp4", fps=20)animation.write_gif("wireframe.gif", fps=20)

As Mayavi relies on the powerful ITK visualization engine it can also process complex datasets. Here is an animation derived from a:

Animations with Vispy

is another interactive 3D data visualization library, based on OpenGL. As for Mayavi, we first create a figure and a mesh, that we animate with MoviePy.

12345678910111213141516171819202122232425262728
from moviepy.editor import VideoClipimport numpy as npfrom vispy import app, scenefrom vispy.gloo.util import _screenshotcanvas = scene.SceneCanvas(keys='interactive')view = canvas.central_widget.add_view()view.set_camera('turntable', mode='perspective', up='z', distance=2,                azimuth=30., elevation=65.)xx, yy = np.arange(-1,1,.02),np.arange(-1,1,.02)X,Y = np.meshgrid(xx,yy)R = np.sqrt(X**2+Y**2)Z = lambda t : 0.1*np.sin(10*R-2*np.pi*t)surface = scene.visuals.SurfacePlot(x= xx-0.1, y=yy+0.2, z= Z(0),                        shading='smooth', color=(0.5, 0.5, 1, 1))view.add(surface)canvas.show()# ANIMATE WITH MOVIEPYdef make_frame(t):    surface.set_data(z = Z(t)) # Update the mathematical surface    canvas.on_draw(None) # Update the image on Vispy's canvas    return _screenshot((0,0,canvas.size[0],canvas.size[1]))[:,:,:3]animation = VideoClip(make_frame, duration=1).resize(width=350)animation.write_gif('sinc_vispy.gif', fps=20, opt='OptimizePlus')

Here are more advanced examples (derived from the Vispy gallery) where C code snippets are embedded in the Python code to fine-tune the 3D shaders:

Animations with Matplotlib

The 2D/3D plotting library already has an animation module, but I found that MoviePy produces lighter, better quality videos, while being up to two times faster (not sure why, see for more details). Here is how you animate Matplotlib with MoviePy:

123456789101112131415161718192021222324
import matplotlib.pyplot as pltimport numpy as npfrom moviepy.video.io.bindings import mplfig_to_npimageimport moviepy.editor as mpy# DRAW A FIGURE WITH MATPLOTLIBduration = 2fig_mpl, ax = plt.subplots(1,figsize=(5,3), facecolor='white')xx = np.linspace(-2,2,200) # the x vectorzz = lambda d: np.sinc(xx**2)+np.sin(xx+d) # the (changing) z vectorax.set_title("Elevation in y=0")ax.set_ylim(-1.5,2.5)line, = ax.plot(xx, zz(0), lw=3)# ANIMATE WITH MOVIEPY (UPDATE THE CURVE FOR EACH t). MAKE A GIF.def make_frame_mpl(t):    line.set_ydata( zz(2*np.pi*t/duration))  # <= Update the curve    return mplfig_to_npimage(fig_mpl) # RGB image of the figureanimation =mpy.VideoClip(make_frame_mpl, duration=duration)animation.write_gif("sinc_mpl.gif", fps=20)

Matplotlib has many beautiful themes and works well with numerical modules like Pandas or Scikit-Learn. Let us watch a SVM classifier getting a better understanding of the map as the number of training point increases.

1234567891011121314151617181920212223242526272829303132
import numpy as npimport matplotlib.pyplot as pltfrom sklearn import svm # sklearn = scikit-learnfrom sklearn.datasets import make_moonsfrom moviepy.editor import VideoClipfrom moviepy.video.io.bindings import mplfig_to_npimageX, Y = make_moons(50, noise=0.1, random_state=2) # semi-random datafig, ax = plt.subplots(1, figsize=(4, 4), facecolor=(1,1,1))fig.subplots_adjust(left=0, right=1, bottom=0)xx, yy = np.meshgrid(np.linspace(-2,3,500), np.linspace(-1,2,500))def make_frame(t):    ax.clear()    ax.axis('off')    ax.set_title("SVC classification", fontsize=16)    classifier = svm.SVC(gamma=2, C=1)    # the varying weights make the points appear one after the other    weights = np.minimum(1, np.maximum(0, t**2+10-np.arange(50)))    classifier.fit(X, Y, sample_weight=weights)    Z = classifier.decision_function(np.c_[xx.ravel(), yy.ravel()])    Z = Z.reshape(xx.shape)    ax.contourf(xx, yy, Z, cmap=plt.cm.bone, alpha=0.8,                vmin=-2.5, vmax=2.5, levels=np.linspace(-2,2,20))    ax.scatter(X[:,0], X[:,1], c=Y, s=50*weights, cmap=plt.cm.bone)    return mplfig_to_npimage(fig)animation = VideoClip(make_frame, duration = 7)animation.write_gif("svm.gif", fps=15)

Put simply, the background colors tell us where the classifier thinks the black points and white points belong. At the begining it has no real clue, but as more points appear it progressively understands that they are distributed along moon-shaped regions.

Animations with Numpy

If you are working with Numpy arrays ( is the central numerical library in Python), you don’t need any external plotting library, you can feed the arrays directly to MoviePy.

This is well illustrated by this simulation of a zombie outbreak in France (inspired by by Max Berggren). France is modelled as a grid (Numpy array) on which all the computations for dispersion and infection are done. At regular intervals, a few Numpy operations tranform the grid into a valid RGB image, and send it to MoviePy.

Putting animations together

What is better than an animation ? Two animations ! You can take advantage of MoviePy’s video composition capabilities to mix animations from different libraries:

123456
import moviepy.editor as mpy# We use the GIFs generated earlier to avoid recomputing the animations.clip_mayavi = mpy.VideoFileClip("sinc.gif")clip_mpl = mpy.VideoFileClip("sinc_mpl.gif").resize(height=clip_mayavi.h)animation = mpy.clips_array([[clip_mpl, clip_mayavi]])animation.write_gif("sinc_plot.gif", fps=20)

Or for something more artistic:

12345678
# Make the white color transparent in clip_mayaviclip_mayavi2 = (clip_mayavi.fx( mpy.vfx.mask_color, [255,255,255])                .set_opacity(.4) # whole clip is semi-transparent                .resize(height=0.85*clip_mpl.h)                .set_pos('center'))animation = mpy.CompositeVideoClip([clip_mpl, clip_mayavi2])animation.write_gif("sinc_plot2.gif", fps=20)

It may be a tad too flashy, but sometimes you must give your audience something they can tweet.

You can also annotate the animations, which is useful when comparing different filters or algorithms. Let’s display four image transformations from the library:

1234567891011121314151617181920212223242526
import moviepy.editor as mpyimport skimage.exposure as ske # rescaling, histogram eq.import skimage.filter as skf # gaussian blurclip = mpy.VideoFileClip("sinc.gif")gray = clip.fx(mpy.vfx.blackwhite).to_mask()def apply_effect(effect, title, **kw):    """ Returns a clip with the effect applied and a title"""    filtr = lambda im: effect(im, **kw)    new_clip = gray.fl_image(filtr).to_RGB()    txt = (mpy.TextClip(title, font="Purisa-Bold", fontsize=15)           .set_position(("center","top"))           .set_duration(clip.duration))    return mpy.CompositeVideoClip([new_clip,txt])# Apply 4 different effects to the original animationequalized = apply_effect(ske.equalize_hist, "Equalized")rescaled  = apply_effect(ske.rescale_intensity, "Rescaled")adjusted  = apply_effect(ske.adjust_log, "Adjusted")blurred   = apply_effect(skf.gaussian_filter, "Blurred", sigma=4)# Put the clips together on a 2x2 grid, and write to a file.finalclip = mpy.clips_array([[ equalized, adjusted ],                             [ blurred,   rescaled ]])final_clip.write_gif("test2x2.gif", fps=20)

If we replace CompositeVideoClip and clips_array by concatenate_videoclips we get a title-effect type animation:

12345678910111213141516171819202122232425
import moviepy.editor as mpyimport skimage.exposure as skeimport skimage.filter as skfclip = mpy.VideoFileClip("sinc.gif")gray = clip.fx(mpy.vfx.blackwhite).to_mask()def apply_effect(effect, label, **kw):    """ Returns a clip with the effect applied and a top label"""    filtr = lambda im: effect(im, **kw)    new_clip = gray.fl_image(filtr).to_RGB()    txt = (mpy.TextClip(label, font="Amiri-Bold", fontsize=25,                        bg_color='white', size=new_clip.size)           .set_position(("center"))           .set_duration(1))    return mpy.concatenate_videoclips([txt, new_clip])equalized = apply_effect(ske.equalize_hist, "Equalized")rescaled  = apply_effect(ske.rescale_intensity, "Rescaled")adjusted  = apply_effect(ske.adjust_log, "Adjusted")blurred   = apply_effect(skf.gaussian_filter, "Blurred", sigma=4)clips = [equalized, adjusted, blurred, rescaled]animation = mpy.concatenate_videoclips(clips)animation.write_gif("sinc_cat.gif", fps=15)

Finally, MoviePy will be particularly practical when dealing with video data, as it is its first job. For our last example we estimate the size of a growing bacterial population by thresholding the video frames and counting the white pixels. The third panel shows that the population size grows exponentially in time.

One library to animate them all ?

I hope to have given you enough recipes to impress your colleagues at your next presentation. Any other library could be animated with MoviePy, as long as its output can be converted to a Numpy array.

Some libraries have their own animation modules, but these are usually a pain to fix and maintain. Thanks to the many users who have tested it in very different contexts, MoviePy seems to have become stable (or people stopped reporting bugs), and can be adapted to many situations. There is still a lot to do, but it would be nice if authors started relying on it for video and GIF rendering, like Pandas and Scikit-Learn rely on Matplotlib for plotting.

For completeness, and because it may better fit your needs, I must mention , another Python library with video writing capabilities which focuses on providing a very simple interface to read or write any kind of image, video or volumetric data. For instance you useimwrite() to write any image, mimwrite() for any video/GIF,volwrite() for volumetric data, or simply write() for streamed data.

Cheers, and happy GIFing !

转载地址:https://blog.csdn.net/xiaojiajia007/article/details/75530630 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:RCNN, Fast-RCNN, Faster-RCNN的一些事
下一篇:keras load model 报错

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月15日 23时07分00秒