def save_as_gif(input_video, output_gif, bg_color=None, tolerance=30, auto_detect=True, fps=None, optimize=True):
    """
    Guarda el video como GIF animado con transparencia.
    
    Args:
        input_video: Ruta del video de entrada
        output_gif: Ruta del GIF de salida
        bg_color: Color del fondo en BGR
        tolerance: Tolerancia de detección
        auto_detect: Detectar color automáticamente
        fps: FPS del GIF (None = usar FPS del video original)
        optimize: Optimizar el GIF para menor tamaño
    """
    cap = cv2.VideoCapture(input_video)
    
    # Obtener propiedades
    video_fps = int(cap.get(cv2.CAP_PROP_FPS))
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    
    if fps is None:
        fps = video_fps
    
    print(f"\nCreando GIF con transparencia...")
    print(f"FPS: {fps}")
    print(f"Total de frames: {total_frames}")
    
    # Detectar color de fondo
    if auto_detect or bg_color is None:
        print("Detectando color de fondo...")
        ret, first_frame = cap.read()
        if ret:
            bg_color = detect_background_color(first_frame)
            print(f"Color de fondo detectado (BGR): {bg_color}")
            print(f"Color de fondo detectado (RGB): ({bg_color[2]}, {bg_color[1]}, {bg_color[0]})")
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
    
    frames_pil = []
    frame_count = 0
    
    # Calcular intervalo de frames si el FPS es diferente
    frame_skip = max(1, video_fps // fps)
    
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        
        # Saltar frames si es necesario para ajustar FPS
        if frame_count % frame_skip != 0:
            frame_count += 1
            continue
        
        # Convertir BGR a RGB
        frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        
        # Crear máscara
        lower_bound = np.array([max(0, c - tolerance) for c in bg_color])
        upper_bound = np.array([min(255, c + tolerance) for c in bg_color])
        mask = cv2.inRange(frame, lower_bound, upper_bound)
        
        # Convertir a RGBA
        frame_rgba = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
        frame_rgba[:, :, 0] = frame_rgb[:, :, 0]
        frame_rgba[:, :, 1] = frame_rgb[:, :, 1]
        frame_rgba[:, :, 2] = frame_rgb[:, :, 2]
        frame_rgba[:, :, 3] = cv2.bitwise_not(mask)
        
        # Convertir a PIL Image
        pil_image = Image.fromarray(frame_rgba, 'RGBA')
        frames_pil.append(pil_image)
        
        frame_count += 1
        if len(frames_pil) % 10 == 0:
            print(f"Procesados {len(frames_pil)} frames para GIF")
    
    cap.release()
    
    if frames_pil:
        # Calcular duración por frame en milisegundos
        duration = int(1000 / fps)
        
        print(f"Guardando GIF con {len(frames_pil)} frames...")
        frames_pil[0].save(
            output_gif,
            save_all=True,
            append_images=frames_pil[1:],
            duration=duration,
            loop=0,
            disposal=2,  # Importante para transparencia
            transparency=0,
            optimize=optimize
        )
        print(f"GIF guardado en: {output_gif}")
        print(f"Duración por frame: {duration}ms")
    else:
        print("Error: No se pudieron procesar frames")


def process_video_to_gif(input_video, start_frame, end_frame, output_gif, tolerance=30, fps=10, optimize=True):
    """
    Proceso completo: corta el video y crea un GIF con transparencia.
    
    Args:
        input_video: Video original
        start_frame: Frame inicial para cortar
        end_frame: Frame final para cortar
        output_gif: Ruta del GIF de salida
        tolerance: Tolerancia de detección de color
        fps: FPS del GIF (recomendado 10-15 para buen tamaño de archivo)
        optimize: Optimizar el GIF
    """
    # Paso 1: Cortar el video
    temp_cut_video = "temp_video_cortado.mp4"
    print("=== PASO 1: Cortando video ===")
    cut_video(input_video, temp_cut_video, start_frame, end_frame)
    
    # Paso 2: Crear GIF con transparencia
    print("\n=== PASO 2: Creando GIF con transparencia ===")
    save_as_gif(temp_cut_video, output_gif, tolerance=tolerance, auto_detect=True, fps=fps, optimize=optimize)
    
    print("\n=== PROCESO COMPLETADO ===")
    print(f"GIF con transparencia guardado en: {output_gif}")


import cv2
import numpy as np
from collections import Counter
from PIL import Image

def detect_background_color(frame, sample_regions=None):
    """
    Detecta el color de fondo más común en un frame.
    
    Args:
        frame: Frame del video
        sample_regions: Lista de regiones a muestrear [(x, y, w, h), ...]
                       Si es None, muestrea los bordes del frame
    
    Returns:
        Color BGR más común como tuple
    """
    if sample_regions is None:
        # Muestrear bordes del frame (asumiendo que el fondo está en los bordes)
        h, w = frame.shape[:2]
        border_size = 20
        
        # Extraer píxeles de los bordes
        top = frame[0:border_size, :]
        bottom = frame[h-border_size:h, :]
        left = frame[:, 0:border_size]
        right = frame[:, w-border_size:w]
        
        # Combinar todas las muestras
        samples = np.vstack([
            top.reshape(-1, 3),
            bottom.reshape(-1, 3),
            left.reshape(-1, 3),
            right.reshape(-1, 3)
        ])
    else:
        # Muestrear regiones específicas
        samples = []
        for x, y, w, h in sample_regions:
            region = frame[y:y+h, x:x+w]
            samples.append(region.reshape(-1, 3))
        samples = np.vstack(samples)
    
    # Encontrar el color más común
    colors = [tuple(color) for color in samples]
    color_counts = Counter(colors)
    most_common_color = color_counts.most_common(1)[0][0]
    
    return most_common_color


def cut_video(input_video, output_video, start_frame=0, end_frame=None):
    """
    Corta un segmento del video.
    
    Args:
        input_video: Ruta del video de entrada
        output_video: Ruta del video de salida
        start_frame: Frame inicial (0-indexed)
        end_frame: Frame final (None = hasta el final)
    
    Returns:
        Número de frames cortados
    """
    cap = cv2.VideoCapture(input_video)
    
    # Obtener propiedades del video
    fps = int(cap.get(cv2.CAP_PROP_FPS))
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    
    if end_frame is None:
        end_frame = total_frames
    
    print(f"Cortando video desde frame {start_frame} hasta {end_frame}")
    print(f"Total de frames a cortar: {end_frame - start_frame}")
    
    # Configurar el video de salida
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    out = cv2.VideoWriter(output_video, fourcc, fps, (width, height))
    
    # Saltar al frame inicial
    cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
    
    frame_count = 0
    current_frame = start_frame
    
    while current_frame < end_frame:
        ret, frame = cap.read()
        if not ret:
            break
        
        out.write(frame)
        frame_count += 1
        current_frame += 1
        
        if frame_count % 100 == 0:
            print(f"Cortados {frame_count}/{end_frame - start_frame} frames")
    
    cap.release()
    out.release()
    
    print(f"Video cortado guardado en: {output_video}")
    return frame_count


def remove_background(input_video, output_video, bg_color=None, tolerance=30, auto_detect=True, transparent=True):
    """
    Elimina el fondo de un video basándose en un color específico.
    
    Args:
        input_video: Ruta del video de entrada (MP4)
        output_video: Ruta del video de salida (MOV/WebM para transparencia, MP4 para fondo negro)
        bg_color: Color del fondo en formato BGR (tuple). Si es None y auto_detect=True, se detecta automáticamente
        tolerance: Tolerancia para la detección del color (0-255)
        auto_detect: Si es True, detecta automáticamente el color de fondo
        transparent: Si es True, crea video con transparencia. Si es False, fondo negro
    """
    
    # Abrir el video de entrada
    cap = cv2.VideoCapture(input_video)
    
    # Obtener propiedades del video
    fps = int(cap.get(cv2.CAP_PROP_FPS))
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    
    print(f"\nProcesando video: {width}x{height} @ {fps}fps, {total_frames} frames")
    
    # Detectar color de fondo si es necesario
    if auto_detect or bg_color is None:
        print("Detectando color de fondo...")
        ret, first_frame = cap.read()
        if ret:
            bg_color = detect_background_color(first_frame)
            print(f"Color de fondo detectado (BGR): {bg_color}")
            print(f"Color de fondo detectado (RGB): ({bg_color[2]}, {bg_color[1]}, {bg_color[0]})")
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)  # Volver al inicio
    
    if transparent:
        # Para transparencia, usar formato WebM con VP9
        print("Creando video con transparencia (formato WebM)...")
        fourcc = cv2.VideoWriter_fourcc(*'VP80')
        # Asegurar que la salida sea .webm
        if not output_video.endswith('.webm'):
            output_video = output_video.rsplit('.', 1)[0] + '.webm'
            print(f"Salida cambiada a formato WebM: {output_video}")
    else:
        fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    
    out = cv2.VideoWriter(output_video, fourcc, fps, (width, height), True)
    
    frame_count = 0
    
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        
        if transparent:
            # Convertir a BGRA (BGR + Alpha)
            frame_rgba = cv2.cvtColor(frame, cv2.COLOR_BGR2BGRA)
            
            # Crear máscara basada en el color del fondo
            lower_bound = np.array([max(0, c - tolerance) for c in bg_color])
            upper_bound = np.array([min(255, c + tolerance) for c in bg_color])
            
            # Crear máscara: píxeles del fondo serán blancos (255), resto negros (0)
            mask = cv2.inRange(frame, lower_bound, upper_bound)
            
            # Establecer canal alpha: 0 (transparente) donde hay fondo, 255 (opaco) donde no
            frame_rgba[:, :, 3] = cv2.bitwise_not(mask)
            
            # Convertir de vuelta a BGR para VideoWriter (OpenCV no soporta BGRA en VideoWriter bien)
            # En su lugar, hacemos fondo negro y guardamos la máscara
            result = cv2.bitwise_and(frame, frame, mask=cv2.bitwise_not(mask))
            
        else:
            # Crear máscara basada en el color del fondo
            lower_bound = np.array([max(0, c - tolerance) for c in bg_color])
            upper_bound = np.array([min(255, c + tolerance) for c in bg_color])
            
            # Crear máscara: píxeles del fondo serán blancos (255), resto negros (0)
            mask = cv2.inRange(frame, lower_bound, upper_bound)
            
            # Invertir la máscara (queremos mantener lo que NO es fondo)
            mask_inv = cv2.bitwise_not(mask)
            
            # Aplicar la máscara al frame original
            result = cv2.bitwise_and(frame, frame, mask=mask_inv)
            
            # Hacer el fondo completamente negro
            result[mask == 255] = [0, 0, 0]
        
        # Escribir el frame procesado
        out.write(result)
        
        frame_count += 1
        if frame_count % 30 == 0:
            print(f"Procesados {frame_count}/{total_frames} frames ({frame_count*100//total_frames}%)")
    
    # Liberar recursos
    cap.release()
    out.release()
    print(f"Video procesado guardado en: {output_video}")


def process_video_complete(input_video, start_frame, end_frame, output_final, tolerance=30, transparent=True):
    """
    Proceso completo: corta el video y elimina el fondo automáticamente.
    
    Args:
        input_video: Video original
        start_frame: Frame inicial para cortar
        end_frame: Frame final para cortar
        output_final: Video final sin fondo
        tolerance: Tolerancia de detección de color
        transparent: Si es True, genera video con transparencia (WebM)
    """
    # Paso 1: Cortar el video
    temp_cut_video = "temp_video_cortado.mp4"
    print("=== PASO 1: Cortando video ===")
    cut_video(input_video, temp_cut_video, start_frame, end_frame)
    
    # Paso 2: Eliminar el fondo (con detección automática)
    print("\n=== PASO 2: Eliminando fondo ===")
    remove_background(temp_cut_video, output_final, tolerance=tolerance, auto_detect=True, transparent=transparent)
    
    print("\n=== PROCESO COMPLETADO ===")
    
    if transparent:
        print("NOTA: El video con transparencia está en formato WebM.")
        print("Para usarlo en editores de video, importa el archivo .webm directamente.")


def save_as_png_sequence(input_video, output_folder, bg_color=None, tolerance=30, auto_detect=True):
    """
    Guarda el video como secuencia de imágenes PNG con transparencia.
    Esta es la opción más compatible para transparencia real.
    
    Args:
        input_video: Ruta del video de entrada
        output_folder: Carpeta donde guardar los PNGs
        bg_color: Color del fondo en BGR
        tolerance: Tolerancia de detección
        auto_detect: Detectar color automáticamente
    """
    import os
    
    # Crear carpeta de salida si no existe
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)
    
    cap = cv2.VideoCapture(input_video)
    
    # Obtener propiedades
    fps = int(cap.get(cv2.CAP_PROP_FPS))
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    
    print(f"\nGuardando como secuencia PNG con transparencia...")
    print(f"FPS del video original: {fps}")
    print(f"Total de frames: {total_frames}")
    
    # Detectar color de fondo
    if auto_detect or bg_color is None:
        print("Detectando color de fondo...")
        ret, first_frame = cap.read()
        if ret:
            bg_color = detect_background_color(first_frame)
            print(f"Color de fondo detectado (BGR): {bg_color}")
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
    
    frame_count = 0
    
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        
        # Convertir a BGRA
        frame_rgba = cv2.cvtColor(frame, cv2.COLOR_BGR2BGRA)
        
        # Crear máscara
        lower_bound = np.array([max(0, c - tolerance) for c in bg_color])
        upper_bound = np.array([min(255, c + tolerance) for c in bg_color])
        mask = cv2.inRange(frame, lower_bound, upper_bound)
        
        # Aplicar transparencia al canal alpha
        frame_rgba[:, :, 3] = cv2.bitwise_not(mask)
        
        # Guardar como PNG
        filename = os.path.join(output_folder, f"frame_{frame_count:06d}.png")
        cv2.imwrite(filename, frame_rgba)
        
        frame_count += 1
        if frame_count % 30 == 0:
            print(f"Guardados {frame_count}/{total_frames} frames")
    
    cap.release()
    print(f"\n{frame_count} frames guardados en: {output_folder}")
    print(f"Para reensamblar: usar software de edición de video o ffmpeg")


# Ejemplo de uso
if __name__ == "__main__":
    # Configuración
    input_file = "astro.mp4"
    
    # Frames a cortar
    start = 15      # Frame inicial
    end = None      # Frame final (None = hasta el final del video)
    
    # Tolerancia de color
    color_tolerance = 8
    
    # OPCIÓN 1: GIF con transparencia (Recomendado para animaciones cortas)
    #output_gif = "astrofinal.gif"
    #process_video_to_gif(input_file, start, end, output_gif, tolerance=color_tolerance, fps=15, optimize=True)
    
    # OPCIÓN 2: Video con transparencia (formato WebM)
    output_webm = "astrofinal.webm"
    process_video_complete(input_file, start, end, output_webm, color_tolerance, transparent=True)
    
    # OPCIÓN 3: Video con fondo negro (formato MP4)
    # output_mp4 = "video_fondo_negro.mp4"
    # process_video_complete(input_file, start, end, output_mp4, color_tolerance, transparent=False)
    
    # OPCIÓN 4: Secuencia de PNGs con transparencia (mejor calidad)
    # output_folder = "frames_transparentes"
    # save_as_png_sequence(input_file, output_folder, tolerance=color_tolerance, auto_detect=True)
    
    # OPCIÓN 5: Solo crear GIF sin cortar
    # save_as_gif(input_file, "animacion.gif", tolerance=color_tolerance, fps=10, optimize=True)