mirror of
https://github.com/kuhyx/testsAndMisc-archive.git
synced 2026-07-04 17:03:08 +02:00
Split 16+ files. 27 files still need splitting. See session notes.
117 lines
3.2 KiB
Python
117 lines
3.2 KiB
Python
"""Shared constants and helper functions for Q23 segmentation video."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import os
|
|
from pathlib import Path
|
|
|
|
import numpy as np
|
|
|
|
os.environ["FFMPEG_BINARY"] = "/usr/bin/ffmpeg"
|
|
|
|
from moviepy import (
|
|
ColorClip,
|
|
CompositeVideoClip,
|
|
TextClip,
|
|
VideoClip,
|
|
)
|
|
from moviepy.video.fx import FadeIn, FadeOut
|
|
|
|
# ── Constants ─────────────────────────────────────────────────────
|
|
W, H = 1280, 720
|
|
FPS = 24
|
|
STEP_DUR = 7.0
|
|
HEADER_DUR = 4.0
|
|
FONT_B = "/usr/share/fonts/TTF/DejaVuSans-Bold.ttf"
|
|
FONT_R = "/usr/share/fonts/TTF/DejaVuSans.ttf"
|
|
OUTPUT_DIR = Path(__file__).resolve().parent / "videos"
|
|
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
OUTPUT = str(OUTPUT_DIR / "q23_segmentation.mp4")
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
BG_COLOR = (15, 20, 35)
|
|
rng = np.random.default_rng(42)
|
|
|
|
|
|
def _tc(**kwargs: object) -> TextClip:
|
|
"""TextClip wrapper that adds enough bottom margin to prevent clipping."""
|
|
fs = kwargs.get("font_size", 24)
|
|
m = int(fs) // 3 + 2
|
|
kwargs["margin"] = (0, m)
|
|
return TextClip(**kwargs)
|
|
|
|
|
|
def _make_header(
|
|
title: str, subtitle: str, duration: float = HEADER_DUR
|
|
) -> CompositeVideoClip:
|
|
bg = ColorClip(size=(W, H), color=BG_COLOR).with_duration(duration)
|
|
t = (
|
|
_tc(
|
|
text=title,
|
|
font_size=48,
|
|
color="white",
|
|
font=FONT_B,
|
|
)
|
|
.with_duration(duration)
|
|
.with_position(("center", 260))
|
|
)
|
|
s = (
|
|
_tc(
|
|
text=subtitle,
|
|
font_size=24,
|
|
color="#90CAF9",
|
|
font=FONT_R,
|
|
)
|
|
.with_duration(duration)
|
|
.with_position(("center", 340))
|
|
)
|
|
return CompositeVideoClip([bg, t, s], size=(W, H)).with_effects(
|
|
[FadeIn(0.5), FadeOut(0.5)]
|
|
)
|
|
|
|
|
|
def _text_slide(
|
|
lines: list[tuple[str, int, str, str, tuple[str | int, str | int]]],
|
|
duration: float = STEP_DUR,
|
|
) -> CompositeVideoClip:
|
|
"""Create a slide with multiple text elements."""
|
|
bg = ColorClip(size=(W, H), color=BG_COLOR).with_duration(duration)
|
|
clips: list[VideoClip] = [bg]
|
|
for text, font_size, color, font, pos in lines:
|
|
tc = (
|
|
_tc(
|
|
text=text,
|
|
font_size=font_size,
|
|
color=color,
|
|
font=font,
|
|
)
|
|
.with_duration(duration)
|
|
.with_position(pos)
|
|
)
|
|
clips.append(tc)
|
|
return CompositeVideoClip(clips, size=(W, H)).with_effects(
|
|
[FadeIn(0.3), FadeOut(0.3)]
|
|
)
|
|
|
|
|
|
def _compose_slide(
|
|
base_clip: VideoClip,
|
|
labels: list[tuple[str, int, str, str, tuple[int, int]]],
|
|
duration: float,
|
|
) -> CompositeVideoClip:
|
|
"""Overlay text labels on an animated base clip."""
|
|
text_clips: list[VideoClip] = [base_clip]
|
|
for text, fs, color, font, pos in labels:
|
|
tc = (
|
|
_tc(text=text, font_size=fs, color=color, font=font)
|
|
.with_duration(duration)
|
|
.with_position(pos)
|
|
)
|
|
text_clips.append(tc)
|
|
return CompositeVideoClip(text_clips, size=(W, H)).with_effects(
|
|
[FadeIn(0.3), FadeOut(0.3)]
|
|
)
|