import torch
import torchvision.transforms as transforms
from torchvision.io import read_video, write_video
import numpy as np
from PIL import Image
from transformers import AutoModelForImageSegmentation
import sys

def process_frame(frame, model, transform_image):
    # 转换 Tensor 为 NumPy 数组
    if isinstance(frame, torch.Tensor):
        frame = frame.numpy()
    
    # 转换为 PIL Image
    frame_pil = Image.fromarray(frame)
    
    # 确保图像有 alpha 通道
    if frame_pil.mode != 'RGBA':
        frame_pil = frame_pil.convert('RGBA')
    
    # 转换为 RGB 进行变换
    frame_rgb = frame_pil.convert('RGB')
    
    # 应用变换
    input_image = transform_image(frame_rgb).unsqueeze(0).to("cuda")
    
    # 预测
    with torch.no_grad():
        preds = model(input_image)[-1].sigmoid().cpu()
    
    pred = preds[0].squeeze().numpy()
    pred_pil = transforms.ToPILImage()(torch.tensor(pred))
    
    # 调整预测图与原图尺寸一致
    pred_pil = pred_pil.resize(frame_pil.size, resample=Image.BILINEAR)
    
    # 将预测结果转换为 alpha 通道
    pred_alpha = np.array(pred_pil)
    
    # 确保 alpha 通道在 [0, 255]
    if pred_alpha.max() <= 1.0:
        pred_alpha = (pred_alpha * 255).astype(np.uint8)
    else:
        pred_alpha = pred_alpha.astype(np.uint8)
    
    # 将前景转换为 NumPy 数组
    fg_rgba = np.array(frame_pil)
    
    # 替换 alpha 通道
    fg_rgba[..., 3] = pred_alpha
    
    # 返回带有 alpha 通道的前景
    return fg_rgba

def composite_frames(foreground, background, alpha):
    """
    将前景叠加到背景上，使用 alpha 进行混合
    foreground: [H, W, 3] RGB
    background: [H, W, 3] RGB
    alpha: [H, W] 单通道
    """
    foreground = foreground.astype(float)
    background = background.astype(float)
    alpha = alpha.astype(float) / 255.0  # Normalize alpha to [0,1]
    
    # 扩展 alpha 到 3 个通道
    if alpha.ndim == 2:
        alpha = np.expand_dims(alpha, axis=2)
    
    # 合成
    composite = alpha * foreground + (1 - alpha) * background
    composite = composite.astype(np.uint8)
    return composite

def process_video(foreground_path, background_path, output_path, model, transform_image):
    # 读取前景和背景视频
    foreground_video, _, fg_info = read_video(foreground_path, pts_unit='sec')
    background_video, _, bg_info = read_video(background_path, pts_unit='sec')
    
    fg_fps = fg_info['video_fps']
    bg_fps = bg_info['video_fps']
    
    # 调整背景 FPS 以匹配前景 FPS
    if bg_fps < fg_fps:
        repeat_factor = int(np.ceil(fg_fps / bg_fps))
        background_video = background_video.repeat_interleave(repeat_factor, dim=0)
    elif bg_fps > fg_fps:
        skip_factor = int(np.ceil(bg_fps / fg_fps))
        background_video = background_video[::skip_factor]
    
    # 确保背景帧数不小于前景帧数
    bg_len = background_video.shape[0]
    fg_len = foreground_video.shape[0]
    if bg_len < fg_len:
        repeats = fg_len // bg_len + 1
        background_video = background_video.repeat(repeats, 1, 1, 1)
    background_video = background_video[:fg_len]
    
    frames = []
    
    for idx in range(fg_len):
        fg_frame = foreground_video[idx]
        bg_frame = background_video[idx]
        
        # 处理前景帧，获取带 alpha 的前景
        processed_fg = process_frame(fg_frame, model, transform_image)
        
        # 分离前景 RGB 和 Alpha
        fg_rgb = processed_fg[..., :3]
        alpha = processed_fg[..., 3]
        
        # 确保背景帧与前景帧尺寸一致
        bg_pil = Image.fromarray(bg_frame.numpy())
        fg_pil = Image.fromarray(fg_rgb)
        bg_resized = bg_pil.resize(fg_pil.size, resample=Image.BILINEAR)
        bg_array = np.array(bg_resized)
        
        # 合成前景和背景
        composite = composite_frames(fg_rgb, bg_array, alpha)  # [H, W, 3]
        frames.append(composite)
        
        if (idx + 1) % 50 == 0 or (idx + 1) == fg_len:
            print(f"已处理 {idx + 1}/{fg_len} 帧")
    
    # 将帧列表转换为 NumPy 数组
    frames_np = np.array(frames)  # Shape: [T, H, W, 3], dtype=uint8
    
    # 转换为 PyTorch 张量（保持 [T, H, W, C] 形状）
    frames_tensor = torch.from_numpy(frames_np)  # [T, H, W, 3]
    
    # 写入输出视频
    write_video(output_path, frames_tensor, fps=fg_fps, video_codec='libx264')
    print(f"视频已保存到 {output_path}")

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("用法: python script.py <foreground_video_path> <background_video_path> [output_video_path]")
        sys.exit(1)
    
    foreground_video_path = sys.argv[1]
    background_video_path = sys.argv[2]
    output_video_path = sys.argv[3] if len(sys.argv) > 3 else "output_video.mp4"
    
    # 模型设置
    print("加载图像分割模型...")
    model = AutoModelForImageSegmentation.from_pretrained("BiRefNet", trust_remote_code=True)
    model.to("cuda")
    model.eval()
    print("模型加载完成。")
    
    # 图像转换设置
    transform_image = transforms.Compose([
        transforms.Resize((1024, 1024)),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
    ])
    
    # 处理视频
    print("开始处理视频...")
    process_video(foreground_video_path, background_video_path, output_video_path, model, transform_image)     性能不好，请提高性能，优化BUG ，需要非常高的性能