-
-
Save uwezi/faec101ed5d7c20222b33eee4b6c7d63 to your computer and use it in GitHub Desktop.
import cv2 # needs opencv-python https://pypi.org/project/opencv-python/ | |
from PIL import Image, ImageOps | |
from dataclasses import dataclass | |
@dataclass | |
class VideoStatus: | |
time: float = 0 | |
videoObject: cv2.VideoCapture = None | |
def __deepcopy__(self, memo): | |
return self | |
class VideoMobject(ImageMobject): | |
''' | |
Following a discussion on Discord about animated GIF images. | |
Modified for videos | |
Parameters | |
---------- | |
filename | |
the filename of the video file | |
imageops | |
(optional) possibility to include a PIL.ImageOps operation, e.g. | |
PIL.ImageOps.mirror | |
speed | |
(optional) speed-up/slow-down the playback | |
loop | |
(optional) replay the video from the start in an endless loop | |
https://discord.com/channels/581738731934056449/1126245755607339250/1126245755607339250 | |
2023-07-06 Uwe Zimmermann & Abulafia | |
2024-03-09 Uwe Zimmermann | |
''' | |
def __init__(self, filename=None, imageops=None, speed=1.0, loop=False, **kwargs): | |
self.filename = filename | |
self.imageops = imageops | |
self.speed = speed | |
self.loop = loop | |
self._id = id(self) | |
self.status = VideoStatus() | |
self.status.videoObject = cv2.VideoCapture(filename) | |
self.status.videoObject.set(cv2.CAP_PROP_POS_FRAMES, 1) | |
ret, frame = self.status.videoObject.read() | |
if ret: | |
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) | |
img = Image.fromarray(frame) | |
if imageops != None: | |
img = imageops(img) | |
else: | |
img = Image.fromarray(np.uint8([[63, 0, 0, 0], | |
[0, 127, 0, 0], | |
[0, 0, 191, 0], | |
[0, 0, 0, 255] | |
])) | |
super().__init__(img, **kwargs) | |
if ret: | |
self.add_updater(self.videoUpdater) | |
def videoUpdater(self, mobj, dt): | |
if dt == 0: | |
return | |
status = self.status | |
status.time += 1000*dt*mobj.speed | |
self.status.videoObject.set(cv2.CAP_PROP_POS_MSEC, status.time) | |
ret, frame = self.status.videoObject.read() | |
if (ret == False) and self.loop: | |
status.time = 0 | |
self.status.videoObject.set(cv2.CAP_PROP_POS_MSEC, status.time) | |
ret, frame = self.status.videoObject.read() | |
if ret: | |
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # needed here? | |
img = Image.fromarray(frame) | |
if mobj.imageops != None: | |
img = mobj.imageops(img) | |
mobj.pixel_array = change_to_rgba_array( | |
np.asarray(img), mobj.pixel_array_dtype | |
) | |
class test(Scene): | |
def construct(self): | |
video1 = VideoMobject( | |
filename=r"D:\Programming\Python\manim\discord\media\videos\20240304_01\480p15\Countdown.mp4", | |
speed=1.0 | |
).scale_to_fit_width(5).to_corner(UL) | |
video2 = VideoMobject( | |
filename=r"D:\Programming\Python\manim\discord\media\videos\20240304_01\480p15\Countdown.mp4", | |
speed=3.0, | |
loop=True, | |
imageops=ImageOps.mirror | |
).scale_to_fit_width(5).to_corner(UR) | |
v1 = Group(video1, SurroundingRectangle(video1)) | |
v2 = Group(video2, SurroundingRectangle(video2)) | |
self.add(v1,v2) | |
self.wait(2) | |
self.play(v2.animate.shift(3*DL), run_time=6) | |
self.wait(2) |
How to play a GIF with alpha channel? I have no experience with OpenCV and I am a newbie in Manim.
How to play a GIF with alpha channel? I have no experience with OpenCV and I am a newbie in Manim.
For GIF images I have another code using PIL rather than OpenCV:
https://gist.github.com/uwezi/87a65edf71adbe7a6767a67f01434625/revisions
it should handle transparent GIF images just find.
Even though my individual GISTs don't have individual licenses attached you can see all my stuff on Github as MIT licensed
https://github.com/uwezi/manim-related?tab=MIT-1-ov-file#readme
Hi @uwezi, Why is this VideoMobject
class not included into manim official class?
Hi @uwezi, Why is this
VideoMobject
class not included into manim official class?
...because nobody has yet bothered to include it into the codebase - and I personally didn't have the time to bother...
Uwe.
Can you give me a license? Please, I want to use this. I am not a discord user.