Python中3D+Temporal 可视化
接我的第一篇博客,python中需要安装Mayavi和Moviepy两个第三方库。其中Mayavi,直接用pip 首先安装VTK、traits和PyQt,我是用的是PyQt5.python下安装东西,实在没太多技术含量,在以后的博客里,只会对那些较为难的问题会做详细记录,简单问题会整合在同一篇文章中。
Mayaci官网链接: http://docs.enthought.com/mayavi/mayavi/
Moviepy官网链接: http://zulko.github.io/moviepy/
利用Mayavi动画修饰器——Animat
不同于我第一篇博客中,使用体绘制的方法,这里使用到的是面绘制的方法,作为代码示例。废话不多说直接上代码。
vol = volumes_data[:, :, :, 0] # 我自己的4D数据,请自己设置
# 面绘制的函数,详细解释在后面
volume_1_scene = mlab.contour3d(vol, contours = 10, opacity=0.8, colormap='jet',color = (0,1,0), figure = fig2)
volume_2_scene = mlab.contour3d(vol, contours = 10, opacity=0.8, colormap='jet',color = (1,0,0), figure = fig2)
# 使用Mayavi的自带的动画显示效果
@mlab.animate(delay=500)
def anim():
f = mlab.gcf()
for scene_cnt in range(0, samples-1):
print('Updating scene... the number is ', scene_cnt)
vol_former = volumes_data[:,:,:,scene_cnt]
vol_latter = volumes_data[:,:,:,scene_cnt]+1
volume_1_scene.mlab_source.set(scalars = vol_former)
volume_2_scene.mlab_source.set(scalars = np.abs(vol_latter-vol_former))
yield
anim()
mlab.show()
容我对上面的代码一一解释
mlab.contour3d(vol, contours = 10, opacity=0.8, colormap='jet',color = (0,1,0), figure = fig2)
其中,vol是一个三维np.array类型的数组。opacity控制的是透明度。colormap选择图像显示颜色类型,类似于用RGB还是Gray,这里是jet。color是显示这幅图像的颜色。figure选择显示的figure。除了前两个参数,其他全都是由缺省值的。
最重要的是动画修饰器。
类似于上面的代码,你需要自己定义这样一个动画修饰器。最重要的一点是,set功能,用这样一个mlab_source.set()函数,就可以在不关闭这个Scene的前提下,更新显示的值,scalars代表的是标量属性。另外当,更新的数组的size改变时,需要使用resize替代set。
还有很重要的一点是,Mayavi是默认hold on功能的。 当不使用新的figure或者scene时,Mayavi会把所有要显示的东西显示在同一个场景中的。
利用Mayavi和Moviepy动态显示,并生成gif
代码如下:
import moviepy.editor as mpy
duration = 19 # duration of the animation in seconds (it will loop)
# MAKE A FIGURE WITH MAYAVI
vol = mlab.contour3d(volumes_data[:,:,:,0], contours = 10, opacity=0.8, colormap='jet', figure = fig3)
def make_frame(t):
x = volumes_data[:, :, :, int(t * 100/5/2)]
vol.mlab_source.set(scalars=x)
print(int(t * 100 /5/2))
return mlab.screenshot(antialiased=True)
animation = mpy.VideoClip(make_frame, duration=duration).resize(0.5) # 一定要resize,否则会出错
animation.write_gif("4Dfmri.gif",fps=10) # 需要通过控制duration和fps的大小来,操控显示
这个问题其实没有全部解决。-_-||
首先,我遇到个很神奇的问题,使用Mayavi的screenshot函数,会触发一个很神奇的问题。这个问题的解决十分暴力,打开报错的figure.py文件把报错的位置注释掉。(注释掉会有什么问题,我也不清楚,后续还会去看下)
ValueError: cannot reshape array of size 12 into shape (0,0,3)
解释下,以上的代码,首先需要设置这个获取帧的函数,即make_frame这个函数。这个t在每次循环中,都会增长0.05,其实这里是以秒为单位的,因为moviepy中默认以real-time进行显示。提示下,t的类型是float64.
resize(0.5),其实改变的是每一帧的分辨率,理论上不去设置,不会改变每帧的分辨率。但在具体的实验过程中,不加reszie会报错,具体原因还在排查。
另外,还有问题。在最后一行代码中,Moviepy官网和stack overflow上都说,这个函数会把生成的gif,保存到Python的默认环境下,但我找遍了整个银盘都未找到,这个问题急需解决。