如何将kivy转换成视频文件
How to convert kivy to a video file
我写了一个 kivy 应用程序来在 linux 服务器上渲染一些动画。
有什么好的方法可以直接把动画转成视频文件吗?
目前我尝试了Xvfb + ffmpeg 的方法。但是它有一些我想避免的问题,例如:
- ffmpeg 还会记录动画开始前的空白 x-windows 桌面。
您可以使用 kivy.uix.widget.Widget.export_to_png
以便在每一帧之后将 Widget 保存到图像文件中,然后使用 ffmpeg
或 cv2
库等工具构建影片,但这会减慢关闭动画,因为将数据保存到磁盘需要时间。所以这是另一种方法:
from functools import partial
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.animation import Animation
from kivy.graphics import Fbo, ClearColor, ClearBuffers, Scale, Translate
Builder.load_string('''
<MyWidget>:
Button:
size_hint: 0.4, 0.2
pos_hint: {'center_x' : 0.5, 'center_y' : 0.5}
text: 'click me'
on_press: root.click_me(args[0])
''')
class MyWidget(FloatLayout):
def click_me(self, button, *args):
anim = Animation(
size_hint = (0.8, 0.4)
)
textures = []
anim.bind(on_complete=partial(self.save_video, textures))
anim.bind(on_progress=partial(self.save_frame, textures))
anim.start(button)
# modified https://github.com/kivy/kivy/blob/master/kivy/uix/widget.py#L607
def save_frame(self, textures, *args):
if self.parent is not None:
canvas_parent_index = self.parent.canvas.indexof(self.canvas)
if canvas_parent_index > -1:
self.parent.canvas.remove(self.canvas)
fbo = Fbo(size=self.size, with_stencilbuffer=True)
with fbo:
ClearColor(0, 0, 0, 1)
ClearBuffers()
Scale(1, -1, 1)
Translate(-self.x, -self.y - self.height, 0)
fbo.add(self.canvas)
fbo.draw()
textures.append(fbo.texture) # append to array instead of saving to file
fbo.remove(self.canvas)
if self.parent is not None and canvas_parent_index > -1:
self.parent.canvas.insert(canvas_parent_index, self.canvas)
return True
def save_video(self, textures, *args):
for i, texture in enumerate(textures):
texture.save("frame{:03}.png".format(i), flipped=False)
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
我修改了 export_to_png
方法,因此它不会尝试将纹理保存到文件中,而是将其附加到列表中。然后当动画结束时,我将所有数据保存到单独的图像中。最好添加某种 "animation is saving..." 模态,因为在此期间应用程序的响应速度较慢。
我写了一个 kivy 应用程序来在 linux 服务器上渲染一些动画。 有什么好的方法可以直接把动画转成视频文件吗?
目前我尝试了Xvfb + ffmpeg 的方法。但是它有一些我想避免的问题,例如:
- ffmpeg 还会记录动画开始前的空白 x-windows 桌面。
您可以使用 kivy.uix.widget.Widget.export_to_png
以便在每一帧之后将 Widget 保存到图像文件中,然后使用 ffmpeg
或 cv2
库等工具构建影片,但这会减慢关闭动画,因为将数据保存到磁盘需要时间。所以这是另一种方法:
from functools import partial
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.animation import Animation
from kivy.graphics import Fbo, ClearColor, ClearBuffers, Scale, Translate
Builder.load_string('''
<MyWidget>:
Button:
size_hint: 0.4, 0.2
pos_hint: {'center_x' : 0.5, 'center_y' : 0.5}
text: 'click me'
on_press: root.click_me(args[0])
''')
class MyWidget(FloatLayout):
def click_me(self, button, *args):
anim = Animation(
size_hint = (0.8, 0.4)
)
textures = []
anim.bind(on_complete=partial(self.save_video, textures))
anim.bind(on_progress=partial(self.save_frame, textures))
anim.start(button)
# modified https://github.com/kivy/kivy/blob/master/kivy/uix/widget.py#L607
def save_frame(self, textures, *args):
if self.parent is not None:
canvas_parent_index = self.parent.canvas.indexof(self.canvas)
if canvas_parent_index > -1:
self.parent.canvas.remove(self.canvas)
fbo = Fbo(size=self.size, with_stencilbuffer=True)
with fbo:
ClearColor(0, 0, 0, 1)
ClearBuffers()
Scale(1, -1, 1)
Translate(-self.x, -self.y - self.height, 0)
fbo.add(self.canvas)
fbo.draw()
textures.append(fbo.texture) # append to array instead of saving to file
fbo.remove(self.canvas)
if self.parent is not None and canvas_parent_index > -1:
self.parent.canvas.insert(canvas_parent_index, self.canvas)
return True
def save_video(self, textures, *args):
for i, texture in enumerate(textures):
texture.save("frame{:03}.png".format(i), flipped=False)
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
我修改了 export_to_png
方法,因此它不会尝试将纹理保存到文件中,而是将其附加到列表中。然后当动画结束时,我将所有数据保存到单独的图像中。最好添加某种 "animation is saving..." 模态,因为在此期间应用程序的响应速度较慢。