Spaces:
Running
Running
File size: 8,966 Bytes
963b1a5 3f0cc27 8182d33 3f0cc27 963b1a5 bcf0a9f 963b1a5 ad5b4b7 963b1a5 bcf0a9f ca501e3 963b1a5 8182d33 963b1a5 ca501e3 963b1a5 ca501e3 963b1a5 ad5b4b7 963b1a5 3fe375f ca501e3 963b1a5 ad5b4b7 963b1a5 8182d33 963b1a5 8182d33 963b1a5 8182d33 963b1a5 ad5b4b7 963b1a5 8182d33 963b1a5 8182d33 963b1a5 ad5b4b7 963b1a5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
import os
import sys
import time
import subprocess
import argparse
import multiprocessing as mp
# Don't import FILM module globally - we'll import the specific function when needed
mp.set_start_method("spawn", force=True) # see if buggy
def parse_arguments():
parser = argparse.ArgumentParser(
description="Orchestrate DiffMorpher || LCM-LoRa || LCM, and FILM for smooth morphing between two images.")
# ------------------- DIFFMORPHER ARGS -------------------
parser.add_argument(
"--model_path", type=str, default="stabilityai/stable-diffusion-2-1-base",
help="Pretrained model to use for DiffMorpher (default: %(default)s)"
)
parser.add_argument(
"--image_path_0", type=str, required=True,
help="Path of the first image"
)
parser.add_argument(
"--prompt_0", type=str, default="",
help="Prompt describing the first image (default: %(default)s)"
)
parser.add_argument(
"--image_path_1", type=str, required=True,
help="Path of the second image"
)
parser.add_argument(
"--prompt_1", type=str, default="",
help="Prompt describing the second image (default: %(default)s)"
)
parser.add_argument(
"--output_path", type=str, default="./results",
help="Output folder for DiffMorpher keyframes/gif (default: %(default)s)"
)
parser.add_argument(
"--save_lora_dir", type=str, default="./lora",
help="Directory to save LoRA outputs (default: %(default)s)"
)
parser.add_argument(
"--load_lora_path_0", type=str, default="",
help="Path to LoRA checkpoint for image 0 (default: %(default)s)"
)
parser.add_argument(
"--load_lora_path_1", type=str, default="",
help="Path to LoRA checkpoint for image 1 (default: %(default)s)"
)
parser.add_argument(
"--use_adain", action="store_true",
help="Use AdaIN in DiffMorpher pipeline"
)
parser.add_argument(
"--use_reschedule", action="store_true",
help="Use reschedule sampling in DiffMorpher"
)
parser.add_argument(
"--lamb", type=float, default=0.6,
help="Lambda for self-attention replacement in DiffMorpher (default: %(default)s)"
)
parser.add_argument(
"--fix_lora_value", type=float, default=None,
help="Fix LoRA value in DiffMorpher (default: LoRA interpolation)"
)
parser.add_argument(
"--save_inter", action="store_true",
help="Save intermediate frames as individual images (e.g. .png) in DiffMorpher"
)
parser.add_argument(
"--num_frames", type=int, default=16,
help="Number of keyframes to generate (default: %(default)s)"
)
parser.add_argument(
"--fps", type=int, default=30,
help="FPS for the output video (default: %(default)s)"
)
parser.add_argument(
"--no_lora", action="store_true",
help="Disable LoRA usage in DiffMorpher"
)
parser.add_argument(
"--use_lcm", action="store_true",
help="Enable LCM-LoRA acceleration for faster sampling"
)
# ------------------- FILM ARGS -------------------
parser.add_argument(
"--use_film", action="store_true",
help="Flag to indicate whether to run FILM after generating keyframes"
)
parser.add_argument(
"--film_input_folder", type=str, default="",
help="Folder containing keyframes for FILM. If empty, will use DiffMorpher output folder."
)
parser.add_argument(
"--film_output_folder", type=str, default="./FILM_Results",
help="Folder where FILM's final interpolated video is saved (default: %(default)s)"
)
parser.add_argument(
"--film_num_recursions", type=int, default=3,
help="Number of recursive interpolations to perform in FILM (default: %(default)s)"
)
return parser.parse_args()
def run_diffmorpher(args):
"""
Calls DiffMorpher's main.py via subprocess using the CLI arguments.
Expects `Image-Morpher/` to be a submodule in the current repo.
"""
diffmorpher_script = os.path.join("Image-Morpher", "main.py")
cmd = [
sys.executable, diffmorpher_script,
"--model_path", args.model_path,
"--image_path_0", args.image_path_0,
"--prompt_0", args.prompt_0,
"--image_path_1", args.image_path_1,
"--prompt_1", args.prompt_1,
"--output_path", args.output_path,
"--save_lora_dir", args.save_lora_dir,
"--lamb", str(args.lamb),
"--num_frames", str(args.num_frames)
]
if args.load_lora_path_0:
cmd += ["--load_lora_path_0", args.load_lora_path_0]
if args.load_lora_path_1:
cmd += ["--load_lora_path_1", args.load_lora_path_1]
if args.use_adain:
cmd.append("--use_adain")
if args.use_reschedule:
cmd.append("--use_reschedule")
if args.fix_lora_value is not None:
cmd += ["--fix_lora_value", str(args.fix_lora_value)]
if args.no_lora:
cmd.append("--no_lora")
# ---- Always add --save_inter to ensure keyframes are saved ----
cmd.append("--save_inter")
# ---- Add LCM-LoRA flag if set ----
if args.use_lcm:
cmd.append("--use_lcm")
print("[INFO] Running DiffMorpher with command:")
print(" ".join(cmd))
start = time.time()
subprocess.run(cmd, check=True)
end = time.time()
print(f"[INFO] DiffMorpher completed in {end - start:.2f} seconds.")
def create_simple_video_from_keyframes(keyframes_folder, output_folder, fps):
"""
If the user does NOT want FILM, we still make a basic video from keyframes.
Assumes frames are saved as .png or .jpg in keyframes_folder.
"""
import cv2
from glob import glob
from datetime import datetime
os.makedirs(output_folder, exist_ok=True)
images = sorted(glob(os.path.join(keyframes_folder, "*.png")))
if not images:
images = sorted(glob(os.path.join(keyframes_folder, "*.jpg")))
if not images:
print(f"[WARN] No .png or .jpg frames found in {keyframes_folder}.")
return
# Prepare video writer
first_frame = cv2.imread(images[0])
height, width, _ = first_frame.shape
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
out_video_path = os.path.join(output_folder, f"simple_morph_{timestamp}.mp4")
out = cv2.VideoWriter(out_video_path, fourcc, fps, (width, height))
for img_path in images:
frame = cv2.imread(img_path)
out.write(frame)
out.release()
print(f"[INFO] Basic morphing video saved at: {out_video_path}")
def run_film_interpolation(input_folder, output_folder, fps, num_recursions):
"""
Import and run FILM processing only when needed.
This function is called only if args.use_film is True.
"""
# Import the process_keyframes function from FILM.py only when needed
from FILM import process_keyframes
# Now run the FILM processing
return process_keyframes(
input_folder=input_folder,
output_folder=output_folder,
fps=fps,
num_recursions=num_recursions
)
def main():
args = parse_arguments()
overall_start_time = time.time()
# 1) Run DiffMorpher to generate keyframes
run_diffmorpher(args)
# 2) Determine the folder containing the keyframes
# If user didn't explicitly give `--film_input_folder`, use `args.output_path`
keyframes_folder = args.film_input_folder if args.film_input_folder else args.output_path
# 3) If user wants to use FILM, perform high-quality interpolation on the keyframes
if args.use_film:
print("[INFO] Running FILM to enhance the keyframes...")
start_film_time = time.time()
# Call the wrapper function that imports FILM only when needed
success = run_film_interpolation(
input_folder=keyframes_folder,
output_folder=args.film_output_folder,
fps=args.fps,
num_recursions=args.film_num_recursions
)
end_film_time = time.time()
if success:
print(f"[INFO] FILM interpolation completed in {end_film_time - start_film_time:.2f} seconds.")
else:
print("[ERROR] FILM interpolation failed. See above for details.")
else:
# 4) If user does NOT want FILM, create a simple .mp4 from the keyframes
print("[INFO] Skipping FILM interpolation. Creating a basic video from DiffMorpher keyframes...")
create_simple_video_from_keyframes(
keyframes_folder=keyframes_folder,
output_folder=args.film_output_folder,
fps=args.fps
)
# 5) Print total execution time
overall_end_time = time.time()
print(f"[INFO] Entire pipeline completed in {overall_end_time - overall_start_time:.2f} seconds.")
if __name__ == "__main__":
main() |