MoviePy 数据动态可视化 图像转动态图或者视频
来源:互联网 发布:汤珈铖 知乎 编辑:程序博客网 时间:2024/05/20 02:27
转载自: 点击打开链接
Data Animations With Python and MoviePy
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.
MoviePy lets you define custom animations with a functionmake_frame(t)
, which returns the video frame corresponding to timet
(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 animate vector graphics (with the library Gizeh), and ray-traced 3D scenes (generated by POV-Ray). This post covers the scientific libraries Mayavi, Vispy, Matplotlib, Numpy, and Scikit-image.
Animations with Mayavi
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 aMayavi example:
Animations with Vispy
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 Matplotlib 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, seehere 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 (Numpy 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 bythis blog post 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 libraryScikit-image:
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 ImageIO, 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 simplywrite()
for streamed data.
Cheers, and happy GIFing !
- MoviePy 数据动态可视化 图像转动态图或者视频
- TensorFlow 图像数据预处理及可视化
- TensorFlow 图像数据预处理及可视化
- TensorFlow 图像数据预处理及可视化
- Caffe学习 图像识别与数据可视化
- matplotlib模块数据可视化-figure图像
- TensorFlow 图像数据预处理及可视化
- TensorFlow 图像数据预处理及可视化
- 动态规划——递归转动态规划三部曲
- Silverlight:动态读取图片或者视频
- Python数据可视化图像库MatPlotLib基本图像操作
- 图像视频数据集网站
- 【原创】ORM-可视化动态数据建模
- 作死之旅: 数据动态可视化
- 扇形图-可视化数据
- 数据可视化-折线图
- 绕对象中心点或者中间轴转动
- 视频图像动态前景分割(待续)
- 自定义绘制圆形和弧形进度条
- 说说如何使用 HTML5 实现拖放功能(使用原生 API)
- Spring Bean 容器
- docker的五种网络模式总结
- Eclipse Debug 界面应用详解——Eclipse Debug不为人知的秘密
- MoviePy 数据动态可视化 图像转动态图或者视频
- NCO3.0连接SAP报错处理Could not load file or assembly 'sapnco' or one of its dependencies
- 在 MVVM 中使用 RACSubject 可以非常方便地实现统一的错误处理逻辑
- POJ3522 Slim Span(kruskal)
- 7-spring源码3.2.18解读+spring技术内幕(关于BeanDefinition的注册)
- Java项目跨域问题解决方案总结
- codeforces821 C(栈操作)
- malloc/free用法
- 内存释放和作用域销毁