将 3D 动画 mayavi 人物保存到内存文件(缓冲区)中
Saving a 3D animated mayavi figure into a in-memory file (buffer)
我想保存我用 mayavi 构建的动画 3D 人物的 gif 或 mp4。
当我用 2D 图形和 imagio 做类似的事情时,我可以将数据保存到缓冲区并将它们附加到 imagio writer。这非常快,省去了生成数千个中间 png 文件的麻烦。但是,我找不到将它们保存到缓冲区而不是文件的方法。
@mlab.animate(delay=10, ui=False)
def update_animation(Z, surface, writer):
# Sets nan pixels to white
surface.module_manager.scalar_lut_manager.lut.nan_color = 0, 0, 0, 0
surface.update_pipeline()
f = mlab.gcf()
# Sets background to white
f.scene.background = (1,1,1)
t = 2.0
while t <= Z.shape[0]:
f.scene.camera.azimuth(1)
f.scene.render()
surface.mlab_source.scalars = get_band(Z, int(t)-1)
t += 0.1
#mlab.savefig('tmp/' + str(t) + '.png') # this used to work, but generates thousands of png
with io.BytesIO() as buff: # so I want instead to try this strategy
mlab.savefig(buff, format='raw')
buff.seek(0)
data = numpy.frombuffer(buff.getvalue(), dtype=numpy.uint8)
w, h = fig.canvas.get_width_height()
im = data.reshape((int(h), int(w), -1))
writer.append_data(im)
yield
在主函数中:
# Z is a 3D np array built from reading a multiband raster with rasterio
with imageio.get_writer(output, mode='I') as writer:
surface = mlab.imshow(get_band(Z, 0), colormap='viridis')
a = update_animation(Z, surface, writer)
mlab.show()
但错误消息指出:
TypeError: expected str, bytes or os.PathLike object, not _io.BytesIO
Starting from Mayavi version 3.4.0, the mlab screenshot()
can be used to take a screenshot of the current figure, to integrate in a matplotlib plot.
所以其实完全可以绕过BytesIO
相关的代码,直接用writer.append_data(mlab.screenshot())
调用imagio writer:
# Z is a 3D np array built from reading a multiband raster with rasterio
with imageio.get_writer(output, mode='I') as writer:
surface = mlab.imshow(get_band(Z, 0), colormap='viridis')
lut_manager = mlab.scalarbar(orientation='vertical')
mlab.colorbar()
a = update_animation(Z, surface, writer)
mlab.show()
以及动画函数本身:
@mlab.animate(delay=10, ui=False)
def update_animation(Z, surface, writer):
# Sets nan pixels to white
surface.module_manager.scalar_lut_manager.lut.nan_color = 0, 0, 0, 0
surface.update_pipeline()
f = mlab.gcf()
t = 2.0
while t <= Z.shape[0]:
f.scene.camera.azimuth(1)
f.scene.render()
surface.mlab_source.scalars = get_band(Z, int(t)-1)
t += 0.1
writer.append_data(mlab.screenshot()) # here !
yield
我想保存我用 mayavi 构建的动画 3D 人物的 gif 或 mp4。
当我用 2D 图形和 imagio 做类似的事情时,我可以将数据保存到缓冲区并将它们附加到 imagio writer。这非常快,省去了生成数千个中间 png 文件的麻烦。但是,我找不到将它们保存到缓冲区而不是文件的方法。
@mlab.animate(delay=10, ui=False)
def update_animation(Z, surface, writer):
# Sets nan pixels to white
surface.module_manager.scalar_lut_manager.lut.nan_color = 0, 0, 0, 0
surface.update_pipeline()
f = mlab.gcf()
# Sets background to white
f.scene.background = (1,1,1)
t = 2.0
while t <= Z.shape[0]:
f.scene.camera.azimuth(1)
f.scene.render()
surface.mlab_source.scalars = get_band(Z, int(t)-1)
t += 0.1
#mlab.savefig('tmp/' + str(t) + '.png') # this used to work, but generates thousands of png
with io.BytesIO() as buff: # so I want instead to try this strategy
mlab.savefig(buff, format='raw')
buff.seek(0)
data = numpy.frombuffer(buff.getvalue(), dtype=numpy.uint8)
w, h = fig.canvas.get_width_height()
im = data.reshape((int(h), int(w), -1))
writer.append_data(im)
yield
在主函数中:
# Z is a 3D np array built from reading a multiband raster with rasterio
with imageio.get_writer(output, mode='I') as writer:
surface = mlab.imshow(get_band(Z, 0), colormap='viridis')
a = update_animation(Z, surface, writer)
mlab.show()
但错误消息指出:
TypeError: expected str, bytes or os.PathLike object, not _io.BytesIO
Starting from Mayavi version 3.4.0, the mlab
screenshot()
can be used to take a screenshot of the current figure, to integrate in a matplotlib plot.
所以其实完全可以绕过BytesIO
相关的代码,直接用writer.append_data(mlab.screenshot())
调用imagio writer:
# Z is a 3D np array built from reading a multiband raster with rasterio
with imageio.get_writer(output, mode='I') as writer:
surface = mlab.imshow(get_band(Z, 0), colormap='viridis')
lut_manager = mlab.scalarbar(orientation='vertical')
mlab.colorbar()
a = update_animation(Z, surface, writer)
mlab.show()
以及动画函数本身:
@mlab.animate(delay=10, ui=False)
def update_animation(Z, surface, writer):
# Sets nan pixels to white
surface.module_manager.scalar_lut_manager.lut.nan_color = 0, 0, 0, 0
surface.update_pipeline()
f = mlab.gcf()
t = 2.0
while t <= Z.shape[0]:
f.scene.camera.azimuth(1)
f.scene.render()
surface.mlab_source.scalars = get_band(Z, int(t)-1)
t += 0.1
writer.append_data(mlab.screenshot()) # here !
yield