Skip to content

Instantly share code, notes, and snippets.

@AARP41298
Created October 3, 2025 00:16
Show Gist options
  • Select an option

  • Save AARP41298/103810325ee55611c9fb94d28c4a598f to your computer and use it in GitHub Desktop.

Select an option

Save AARP41298/103810325ee55611c9fb94d28c4a598f to your computer and use it in GitHub Desktop.
Collage from video
import cv2
from PIL import Image
import numpy as np
import argparse
from datetime import timedelta, datetime
def format_time(segundos: float) -> str:
td = timedelta(seconds=segundos)
h, m, s = str(td).split(':')
if '.' not in s:
s = s + '.000'
else:
secs, ms = s.split('.')
s = f"{secs}.{ms[:3]}"
return f"{int(h):02d}:{int(m):02d}:{s}"
def parse_time_to_seconds(time_str: str) -> float:
"""
Convierte 'mm:ss' o 'hh:mm:ss' a segundos float
"""
parts = time_str.strip().split(':')
parts = [float(p) for p in parts]
if len(parts) == 3:
h, m, s = parts
return h * 3600 + m * 60 + s
elif len(parts) == 2:
m, s = parts
return m * 60 + s
else:
raise ValueError("Formato de tiempo inválido, use mm:ss o hh:mm:ss")
def generar_collage(video_path, x, y, inicio=0, fin=100, salida='', timestamps=[]):
"""
video_path : ruta al video
x, y : columnas y filas del collage (x columnas, y filas)
inicio : porcentaje de inicio (0-100)
fin : porcentaje de fin (0-100)
salida : nombre del archivo de salida (si vacío se genera automático)
timestamps : lista de timestamps manuales en segundos
"""
if not salida:
now = datetime.now().strftime('%Y-%m-%d_%H-%M')
salida = f'collage_{now}.jpg'
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
raise Exception("No se pudo abrir el video")
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = cap.get(cv2.CAP_PROP_FPS)
duracion = total_frames / fps # segundos
total_capturas = x * y
porcentajes = np.linspace(inicio, fin, total_capturas)
segundos_auto = [duracion * (p / 100.0) for p in porcentajes]
# Reemplazar con timestamps manuales
if timestamps:
for ts in timestamps:
ts_seg = parse_time_to_seconds(ts)
# Encontrar índice más cercano
idx = min(range(len(segundos_auto)), key=lambda i: abs(segundos_auto[i]-ts_seg))
old_seg = segundos_auto[idx]
segundos_auto[idx] = ts_seg
print(f"> Reemplazado frame #{idx+1} {format_time(old_seg)} → {format_time(ts_seg)}")
frames = []
for idx, segundo in enumerate(segundos_auto, start=1):
frame_num = int(segundo * fps)
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_num)
ret, frame = cap.read()
if not ret:
continue
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frames.append(Image.fromarray(frame))
porcentaje = (segundo / duracion) * 100
print(f"#{idx} - {format_time(segundo)} - {porcentaje:.2f}%")
cap.release()
if not frames:
raise Exception("No se pudieron capturar frames")
ancho, alto = frames[0].size
collage = Image.new('RGB', (ancho * x, alto * y))
i = 0
for fila in range(y):
for col in range(x):
if i < len(frames):
collage.paste(frames[i], (col * ancho, fila * alto))
i += 1
collage.save(salida)
print(f"Collage guardado en {salida}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Generar collage de capturas de un video')
parser.add_argument('video', help='Ruta al video')
parser.add_argument('-x', type=int, required=True, help='Columnas del collage')
parser.add_argument('-y', type=int, required=True, help='Filas del collage')
parser.add_argument('-i', '--inicio', type=float, default=0, help='Porcentaje inicio (0-100)')
parser.add_argument('-f', '--fin', type=float, default=100, help='Porcentaje fin (0-100)')
parser.add_argument('-o', '--output', default='', help='Archivo de salida (opcional)')
parser.add_argument('-t', '--timestamps', type=str, default='',
help='Timestamps manuales separados por coma (ej. 01:35,03:10)')
args = parser.parse_args()
ts_list = [t for t in args.timestamps.split(',') if t.strip()] if args.timestamps else []
generar_collage(
args.video,
x=args.x,
y=args.y,
inicio=args.inicio,
fin=args.fin,
salida=args.output,
timestamps=ts_list
)
# py video_collage.py -x 4 -y 6 -t 01:35,03:47,02:34,02:44,03:20,03:34.50 'Gorillaz - El Mañana.webm'
# py video_collage.py -x 4 -y 6 's:/Daft Punk - Something About Us (Official Video).webm' -t 03:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment