youtube/remotion/werkzeuge/freistellen.py
Pascal Scholz 0b326e6e9c Folge 2 „Pino ist müde“ komplett in Remotion (ohne Ton, ohne Higgsfield)
Szenen aus der Figuren-Bibliothek: freigestellte Standbilder mit
Posenwechsel, freigestellte Clips (WebM mit Alpha in /shared), Orte als
vorberechnete Aquarell-SVGs, Untertitel statt Stimmen. Zeitplan aus den
Sprechzeilen, damit ElevenLabs-Aufnahmen später nur die Dauer setzen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 02:09:06 +00:00

37 lines
1.6 KiB
Python

# Standbilder freistellen (rembg), Leinwand bleibt erhalten.
# python3 werkzeuge/freistellen.py <zielordner> bild1.png bild2.png ...
# Freistellen ohne Zuschneiden (gleiche Leinwand -> Posen deckungsgleich)
import sys, os, time
import numpy as np
from PIL import Image, ImageFilter
from scipy import ndimage
from rembg import remove, new_session
s = new_session("isnet-general-use")
out_dir = sys.argv[1]
for src in sys.argv[2:]:
dst = os.path.join(out_dir, os.path.basename(src)[:-4] + ".png")
if os.path.exists(dst): continue
t = time.time()
im = Image.open(src).convert("RGB")
m = np.asarray(remove(im, session=s, only_mask=True)).astype(float)
hard = m > 110
lab, n = ndimage.label(hard)
if n == 0: print("LEER", src); continue
sizes = ndimage.sum(hard, lab, range(1, n + 1))
keep = np.zeros_like(hard)
for i, sz in enumerate(sizes): # alle großen Teile (Laterne, Bommel) behalten
if sz > 0.02 * sizes.max(): keep |= lab == i + 1
hard = keep
holes = ndimage.binary_fill_holes(hard) & ~hard
hl, hn = ndimage.label(holes)
for i in range(1, hn + 1):
if (hl == i).sum() < 400: hard |= hl == i
rgb = np.asarray(im).astype(float)
paper = (rgb.min(-1) > 228) & (rgb.max(-1) - rgb.min(-1) < 18)
plab, pn = ndimage.label(paper & hard)
for i in range(1, pn + 1):
if (plab == i).sum() > 600: hard &= ~(plab == i)
hard = ndimage.binary_erosion(hard, iterations=2)
a = Image.fromarray((hard * 255).astype("uint8")).filter(ImageFilter.GaussianBlur(0.8))
o = im.convert("RGBA"); o.putalpha(a); o.save(dst)
print(os.path.basename(dst), round(time.time() - t, 1), flush=True)