在manim中增加外部视频文件,真得做到随心所欲

前言

      manim 动画是在场景中加入:文本、数学公式、坐标及函数图等动画对象,再附上背景音乐已是高大上了。但最近有个需求是在场景中指定的地方嵌入外部视频文件,可以说是动画中的动画,当时以为manim具备这个功能,但查了帮助文档和资料,都没有找到,怎么办呢,实际需求却是存在的。想了好大一会,于是决定自已来实现这个功能,思路是把原始视频音频和视频先分离开,视频文件中的每一Frame都用MObject来包装,最后再加上分离的音频文件,终于实现了这个需求。下面是我的具体实现。

先上效果:

1、先安装视频处理的包

      前提条件是已经安装了 manim

pip install opencv-python movipy

2、具体实现,自已新建一个VideoUtil.py文件,在该文件中加入代码。我直接上代码

from manim import Animation,ImageMobject
from manim.typing import Vector3D
import numpy as np
import os
from PIL import Image
import cv2
from moviepy import VideoFileClip

class VideoCustomUtil:
    """
        videoCustomUtil = VideoCustomUtil("./assets/videos/biba.mp4", sample_inter=3)
            video_img_objs, r_time = videoCustomUtil.create_animations(position=DOWN + LEFT * 4.85)
            audio_file = videoCustomUtil.audio_file
            if audio_file is not None:
                self.add_sound(audio_file)

            for video_img_obj in video_img_objs:
                video_img_obj.scale(0.5)
                animal = Animation(video_img_obj)
                self.play(animal, run_time=r_time)

    Parameters
    video_file is video file path
    sample_inter is sample interval default is 3
    scene is scene that animation to play Scene
    """

    def __init__(self, video_file,sample_inter=1):
        self.video_file = video_file
        self.audio_file = None
        self.sample_inter = sample_inter
        self.video_w = None
        self.video_h = None
        self.video_duration = None

    def create_animations(self, position=None):
        #-----create manim animations------------------
        #param postion is mobject's position in Scene

        v_w,v_h,duration, fps, audio_file_name = self.get_video_info()
        file_folder = "./assets/images/temp/"
        self.create_folder(file_folder)
        cap = cv2.VideoCapture(self.video_file)
        i = -1;
        video_img_objs: list[ImageMobject] = []
        while cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break

            i = i + 1
            if i % self.sample_inter != 0 :
                continue

            temp_file = file_folder + "temp_cv2.png"
            cv2.imwrite(temp_file, frame)
            image_array = np.array(Image.open(temp_file))
            img_obj = ImageMobject(image_array)
            video_img_objs.append(img_obj)
            if os.path.exists(temp_file):
                os.unlink(temp_file)

        cap.release()

        #------start ready animations------------------------------
        for video_img_obj in video_img_objs:
            video_img_obj.move_to(position)
            # animal = Animation(video_img_obj)
            # self.scene.play(animal, run_time=self.sample_inter/fps)
        return video_img_objs,self.sample_inter/fps


    def get_video_info(self):
        video_clip = VideoFileClip(self.video_file)
        duration = video_clip.duration
        v_w = video_clip.w
        v_h = video_clip.h
        fps = video_clip.fps
        audio = video_clip.audio
        audio_file_name = self.video_file + ".mp3"

        if os.path.exists(audio_file_name):
            os.unlink(audio_file_name)

        audio.write_audiofile(audio_file_name)
        self.audio_file = audio_file_name
        self.video_w = v_w
        self.video_h = v_h
        self.video_duration = duration
        return v_w,v_h,duration, fps, audio_file_name

    def create_folder(self,folder_path):
        if not os.path.exists(folder_path):
            os.makedirs(folder_path)
        else:
            print(f"Folder '{folder_path}' already exists.")

    def create_image_obj(self, image_file:str = None, position:Vector3D = None):
        """
            image_array = np.array(Image.open("./assets/images/hs.png"))
            img_obj = ImageMobject(image_array)
            img_obj.move_to(DOWN + LEFT * 6.3, aligned_edge=LEFT)
            fade_in_animation5 = FadeIn(img_obj)
            self.play(fade_in_animation5, run_time=2)

        :param image_file:
        :param position:
        :return:
        """
        image_array = np.array(Image.open(image_file))
        img_obj = ImageMobject(image_array)
        img_obj.move_to(position)
        return img_obj

讲一下这个总体思路:先用movepy把原始视频文件中的视频与音频分开,音频保存成mp3文件,再用opencv对这个视频文件按帧读取,每读取一帧用MObject进行包装,所有的帧就都成了MObject,这样就可以在manim的Scene中加入动画了。

3、测试,直接上代码

# -*- coding=utf-8 -*-
from manim import *
import numpy as np
import os
from PIL import Image


from ppt.utils.VideoUtil import VideoCustomUtil

class FlyLevelPPT_2(Scene):
    def setBackground(self):
        self.camera.background_color = (68, 84, 106)

    def construct(self):
        config.tex_template = TexTemplate()
        config.tex_template.add_to_preamble(r"\usepackage{ctex}")
        self.setBackground()
        self.clear()

        # ------to do start----------------------
        tx1,tx2,tx3,tx4 = self.addTxt_1()
        self.wait(2)
        #self.add_image()
        #self.wait(2)
        self.add_video_1()

    def add_image(self, mobject: VMobject = None):
        pass

    def addTxt_1(self, mobject: VMobject = None):
        tx1 = MathTex(
            "除了幂函数,最常用的函数就是",
            "三角函数",
            ",三角函数有一个非常重要的特点就",
            arg_separator="",
            tex_template=config.tex_template,
            font_size=32
        )
        tx1[1].color = ManimColor("#f6f208")
        tx1.move_to(UP * 3.5 + LEFT * 5.6, aligned_edge=LEFT)
        fade_in_animation1 = FadeIn(tx1)
        self.play(fade_in_animation1, run_time=2)
        self.wait(2)

        tx2 = MathTex(
            "是",
            "周期性",
            ",而许多事物的发展变化都呈现出",
            "周期性",
            ",如发动机活塞的运动,交流电",
            arg_separator="",
            tex_template=config.tex_template,
            font_size=32
        )
        tx2[1].color = ManimColor("#f6f208")
        tx2[3].color = ManimColor("#f6f208")
        tx2.move_to(UP * 3.0 + LEFT * 6.3, aligned_edge=LEFT)
        fade_in_animation2 = FadeIn(tx2)
        self.play(fade_in_animation2, run_time=2)
        self.wait(2)

        tx3 = MathTex(
            "的电流电压变化,信号的周期变化等。因此我们自然会想到能不能将这些",
            "周期函数",
            arg_separator="",
            tex_template=config.tex_template,
            font_size=32
        )
        tx3[1].color = ManimColor("#f6f208")
        tx3.move_to(UP * 2.5 + LEFT * 6.3, aligned_edge=LEFT)
        fade_in_animation3 = FadeIn(tx3)
        self.play(fade_in_animation3, run_time=2)
        self.wait(2)

        tx4 = MathTex(
            "用",
             "三角函数",
            "来展开呢?答案是肯定的。",
            arg_separator="",
            tex_template=config.tex_template,
            font_size=32
        )
        tx4[1].color = ManimColor("#f6f208")
        tx4.move_to(UP * 2.0 + LEFT * 6.3, aligned_edge=LEFT)
        fade_in_animation4 = FadeIn(tx4)
        self.play(fade_in_animation4, run_time=2)
        return tx1,tx2,tx3,tx4

    def add_video_1(self, video_obj: VMobject=None):
        videoCustomUtil = VideoCustomUtil("./assets/videos/biba.mp4", sample_inter=3)
        video_img_objs, r_time = videoCustomUtil.create_animations(position=DOWN + LEFT * 4.85)
        audio_file = videoCustomUtil.audio_file
        if audio_file is not None:
            self.add_sound(audio_file)

        for video_img_obj in video_img_objs:
            video_img_obj.scale(0.5)
            animal = Animation(video_img_obj)
            self.play(animal, run_time=r_time)


if __name__ == "__main__":
    module_name = os.path.basename(__file__)
    print(module_name)
    scene_name = "FlyLevelPPT_2"
    os.system(f"manim --disable_caching -pqh {module_name} {scene_name}")

到此为止,全部完成了。

超声随心所欲Vista版数据库文件是超声随心所欲软件在Vista操作系统上所使用的数据库文件。数据库文件是用于存储和管理大量数据的文件,它能够提供高效的数据检索和存储功能,使得软件能够更加快速地响应用户的操作。 超声随心所欲Vista版数据库文件通常使用一种被广泛采用的数据库管理系统来创建和管理,比如常见的SQL Server或者Access。这些数据库管理系统能够提供强大的数据管理和操作能力,使得用户能够方便地进行数据的添加、修改和删除等操作。 超声随心所欲Vista版数据库文件中包括了软件所需的各种数据信息,比如病人的基本信息、医生的诊断结果、检查报告等。这些数据信息被组织和存储在数据库中的表格中,每个表格对应一个特定的数据类型。用户可以通过软件提供的界面,进行数据的查询和修改等操作,以满足不同的需求。 超声随心所欲Vista版数据库文件的优势在于支持Vista操作系统的特性和功能,能够很好地适应Vista系统的特点。这样用户在使用该软件进行超声检查和诊断时,便可以充分利用Vista系统的优势和便利性,提高工作效率和准确性。 总之,超声随心所欲Vista版数据库文件是一种针对Vista操作系统开发的数据库文件,它能够高效地存储和管理超声随心所欲软件所需的各类数据信息,为用户提供方便快捷的数据操作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值