import argparse import os os.environ['CUDA_HOME'] = '/usr/local/cuda' os.environ['PATH'] = os.environ['PATH'] + ':/usr/local/cuda/bin' from datetime import datetime import cv2 import gradio as gr import spaces import numpy as np import torch from diffusers.image_processor import VaeImageProcessor from huggingface_hub import snapshot_download from PIL import Image torch.jit.script = lambda f: f from model.cloth_masker import AutoMasker, vis_mask from model.pipeline import CatVTONPipeline, CatVTONPix2PixPipeline from model.flux.pipeline_flux_tryon import FluxTryOnPipeline from utils import init_weight_dtype, resize_and_crop, resize_and_padding def parse_args(): parser = argparse.ArgumentParser(description="Simple example of a training script.") parser.add_argument( "--base_model_path", type=str, default="booksforcharlie/stable-diffusion-inpainting", help=( "The path to the base model to use for evaluation. This can be a local path or a model identifier from the Model Hub." ), ) parser.add_argument( "--p2p_base_model_path", type=str, default="timbrooks/instruct-pix2pix", help=( "The path to the base model to use for evaluation. This can be a local path or a model identifier from the Model Hub." ), ) parser.add_argument( "--resume_path", type=str, default="zhengchong/CatVTON", help=( "The Path to the checkpoint of trained tryon model." ), ) parser.add_argument( "--output_dir", type=str, default="resource/demo/output", help="The output directory where the model predictions will be written.", ) parser.add_argument( "--width", type=int, default=768, help=( "The resolution for input images, all the images in the train/validation dataset will be resized to this" " resolution" ), ) parser.add_argument( "--height", type=int, default=1024, help=( "The resolution for input images, all the images in the train/validation dataset will be resized to this" " resolution" ), ) parser.add_argument( "--repaint", action="store_true", help="Whether to repaint the result image with the original background." ) parser.add_argument( "--allow_tf32", action="store_true", default=True, help=( "Whether or not to allow TF32 on Ampere GPUs. Can be used to speed up training. For more information, see" " https://pytorch.org/docs/stable/notes/cuda.html#tensorfloat-32-tf32-on-ampere-devices" ), ) parser.add_argument( "--mixed_precision", type=str, default="bf16", choices=["no", "fp16", "bf16"], help=( "Whether to use mixed precision. Choose between fp16 and bf16 (bfloat16). Bf16 requires PyTorch >=" " 1.10.and an Nvidia Ampere GPU. Default to the value of accelerate config of the current system or the" " flag passed with the `accelerate.launch` command. Use this argument to override the accelerate config." ), ) args = parser.parse_args() env_local_rank = int(os.environ.get("LOCAL_RANK", -1)) if env_local_rank != -1 and env_local_rank != args.local_rank: args.local_rank = env_local_rank return args def image_grid(imgs, rows, cols): assert len(imgs) == rows * cols w, h = imgs[0].size grid = Image.new("RGB", size=(cols * w, rows * h)) for i, img in enumerate(imgs): grid.paste(img, box=(i % cols * w, i // cols * h)) return grid args = parse_args() # Mask-based CatVTON catvton_repo = "zhengchong/CatVTON" repo_path = snapshot_download(repo_id=catvton_repo) # Pipeline pipeline = CatVTONPipeline( base_ckpt=args.base_model_path, attn_ckpt=repo_path, attn_ckpt_version="mix", weight_dtype=init_weight_dtype(args.mixed_precision), use_tf32=args.allow_tf32, device='cuda' ) # AutoMasker mask_processor = VaeImageProcessor(vae_scale_factor=8, do_normalize=False, do_binarize=True, do_convert_grayscale=True) automasker = AutoMasker( densepose_ckpt=os.path.join(repo_path, "DensePose"), schp_ckpt=os.path.join(repo_path, "SCHP"), device='cuda', ) # Flux-based CatVTON access_token = os.getenv("HUGGING_FACE_HUB_TOKEN") flux_repo = "black-forest-labs/FLUX.1-Fill-dev" pipeline_flux = FluxTryOnPipeline.from_pretrained(flux_repo, use_auth_token=access_token) pipeline_flux.load_lora_weights( os.path.join(repo_path, "flux-lora"), weight_name='pytorch_lora_weights.safetensors' ) pipeline_flux.to("cuda", init_weight_dtype(args.mixed_precision)) def print_image_info(img): # Basic attributes info = { "Filename": img.filename, "Format": img.format, "Mode": img.mode, "Size": img.size, "Width": img.width, "Height": img.height, "DPI": img.info.get('dpi', "N/A"), "Is Animated": getattr(img, "is_animated", False), "Frames": getattr(img, "n_frames", 1) } print("----- Image Information -----") for key, value in info.items(): print(f"{key}: {value}") def extract_frames(video_path): # Open the video file cap = cv2.VideoCapture(video_path) frames = [] success, frame = cap.read() while success: # Convert frame from BGR (OpenCV default) to RGB frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # Convert the numpy array (frame) to a PIL Image pil_frame = Image.fromarray(frame_rgb) frames.append(pil_frame) success, frame = cap.read() cap.release() return frames #process_video_frames @spaces.GPU(duration=120) def process_video_frames( video, cloth_image, cloth_type, num_inference_steps, guidance_scale, seed, show_type ): """ Process each frame of the video through the flux pipeline Args: video (str): Path to the input video file cloth_image (str): Path to the cloth image ... (other parameters from original function) Returns: list: Processed frames """ # Extract frames from video frames = extract_frames(video) processed_frames = [] print(f"processed_frames {len(processed_frames)}") for person_image in frames: result_image = proc_function_vidfl( person_image, cloth_image, cloth_type, num_inference_steps, guidance_scale, seed, show_type ) print_image_info(result_image) yield result_image processed_frames.append(result_image) yield processed_frames @spaces.GPU(duration=120) def proc_function_vidfl( person_image, cloth_image, cloth_type, num_inference_steps, guidance_scale, seed, show_type ): # Set random seed generator = None if seed != -1: generator = torch.Generator(device='cuda').manual_seed(seed) # Process input images #person_image = Image.open(person_image).convert("RGB") #cloth_image = Image.open(cloth_image).convert("RGB") # Adjust image sizes person_image = resize_and_crop(person_image, (args.width, args.height)) cloth_image = resize_and_padding(cloth_image, (args.width, args.height)) # Process mask mask = automasker( person_image, cloth_type )['mask'] mask = mask_processor.blur(mask, blur_factor=9) # Inference result_image = pipeline_flux( image=person_image, condition_image=cloth_image, mask_image=mask, width=args.width, height=args.height, num_inference_steps=num_inference_steps, guidance_scale=guidance_scale, generator=generator ).images[0] return result_image @spaces.GPU(duration=120) def submit_function_flux( person_image, cloth_image, cloth_type, num_inference_steps, guidance_scale, seed, show_type ): # Process image editor input person_image, mask = person_image["background"], person_image["layers"][0] mask = Image.open(mask).convert("L") if len(np.unique(np.array(mask))) == 1: mask = None else: mask = np.array(mask) mask[mask > 0] = 255 mask = Image.fromarray(mask) # Set random seed generator = None if seed != -1: generator = torch.Generator(device='cuda').manual_seed(seed) # Process input images person_image = Image.open(person_image).convert("RGB") cloth_image = Image.open(cloth_image).convert("RGB") # Adjust image sizes person_image = resize_and_crop(person_image, (args.width, args.height)) cloth_image = resize_and_padding(cloth_image, (args.width, args.height)) # Process mask if mask is not None: mask = resize_and_crop(mask, (args.width, args.height)) else: mask = automasker( person_image, cloth_type )['mask'] mask = mask_processor.blur(mask, blur_factor=9) # Inference result_image = pipeline_flux( image=person_image, condition_image=cloth_image, mask_image=mask, width=args.width, height=args.height, num_inference_steps=num_inference_steps, guidance_scale=guidance_scale, generator=generator ).images[0] # Post-processing masked_person = vis_mask(person_image, mask) # Return result based on show type if show_type == "result only": return result_image else: width, height = person_image.size if show_type == "input & result": condition_width = width // 2 conditions = image_grid([person_image, cloth_image], 2, 1) else: condition_width = width // 3 conditions = image_grid([person_image, masked_person, cloth_image], 3, 1) conditions = conditions.resize((condition_width, height), Image.NEAREST) new_result_image = Image.new("RGB", (width + condition_width + 5, height)) new_result_image.paste(conditions, (0, 0)) new_result_image.paste(result_image, (condition_width + 5, 0)) return new_result_image, result_image def person_example_fn(image_path): return image_path HEADER = """