outpaint orbit
This commit is contained in:
141
tour-comfy/orbit_poc.py
Executable file
141
tour-comfy/orbit_poc.py
Executable file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
orbit_poc.py — 2.5D actor orbit preview proof-of-concept.
|
||||
|
||||
Usage:
|
||||
python orbit_poc.py --input img1.png img2.png ... --output ./output
|
||||
python orbit_poc.py --input ./filmstrip_images/ --output ./output --mode swing --frames 36
|
||||
|
||||
Output:
|
||||
./output/orbit_frames/frame_NNN.png
|
||||
./output/orbit_preview.mp4
|
||||
./output/debug/selected_frame.png
|
||||
./output/debug/actor_rgba.png
|
||||
./output/debug/mask.png
|
||||
./output/debug/depth.png
|
||||
./output/debug/depth_colorized.png
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
# Ensure tour-comfy is on the path when running from project root
|
||||
_here = os.path.dirname(os.path.abspath(__file__))
|
||||
if _here not in sys.path:
|
||||
sys.path.insert(0, _here)
|
||||
|
||||
from orbit_module import run_orbit_pipeline
|
||||
|
||||
|
||||
_IMAGE_EXTS = {".png", ".jpg", ".jpeg", ".webp", ".bmp", ".tiff", ".tif"}
|
||||
|
||||
|
||||
def _collect_inputs(raw_inputs: list) -> list:
|
||||
"""Expand dirs and glob patterns; return sorted list of image paths."""
|
||||
paths = []
|
||||
for item in raw_inputs:
|
||||
if os.path.isdir(item):
|
||||
for fname in sorted(os.listdir(item)):
|
||||
if os.path.splitext(fname)[1].lower() in _IMAGE_EXTS:
|
||||
paths.append(os.path.join(item, fname))
|
||||
elif "*" in item or "?" in item:
|
||||
paths.extend(sorted(glob.glob(item)))
|
||||
elif os.path.isfile(item):
|
||||
paths.append(item)
|
||||
else:
|
||||
print(f"[warn] not found: {item}", file=sys.stderr)
|
||||
return paths
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate a 2.5D orbit preview (depth-card parallax) from actor images."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--input", "-i", nargs="+", required=True,
|
||||
metavar="PATH",
|
||||
help="Input image paths, glob patterns, or directories",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output", "-o", default="./output",
|
||||
metavar="DIR",
|
||||
help="Output directory (default: ./output)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--frames", "-f", type=int, default=36,
|
||||
help="Number of animation frames (default: 36)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--fps", type=int, default=24,
|
||||
help="Output video framerate (default: 24)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--parallax", "-p", type=float, default=0.08,
|
||||
help="Parallax strength 0–1, fraction of image width (default: 0.08)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--angle", "-a", type=float, default=35.0,
|
||||
help="Maximum orbit angle in degrees for swing mode (default: 35)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--mode", "-m", choices=["swing", "orbit"], default="swing",
|
||||
help="'swing' = left↔right loop (default), 'orbit' = full 360°",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-debug", action="store_true",
|
||||
help="Skip writing debug output files",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
image_paths = _collect_inputs(args.input)
|
||||
if not image_paths:
|
||||
print("[error] No input images found.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print(f"[orbit] {len(image_paths)} input image(s)")
|
||||
for p in image_paths[:5]:
|
||||
print(f" {p}")
|
||||
if len(image_paths) > 5:
|
||||
print(f" ... ({len(image_paths) - 5} more)")
|
||||
|
||||
print(f"[orbit] output dir : {os.path.abspath(args.output)}")
|
||||
print(f"[orbit] frames={args.frames} fps={args.fps} mode={args.mode} "
|
||||
f"parallax={args.parallax} angle±{args.angle}°")
|
||||
|
||||
# Use the first image as the primary input (CLI can pass multiple; first = best choice)
|
||||
primary = image_paths[0]
|
||||
if len(image_paths) > 1:
|
||||
print(f"[orbit] using first image as primary: {primary}")
|
||||
print(f" (pass a single image or the specific frame you want)")
|
||||
|
||||
t0 = time.perf_counter()
|
||||
result = run_orbit_pipeline(
|
||||
image_path=primary,
|
||||
output_dir=args.output,
|
||||
n_frames=args.frames,
|
||||
parallax_strength=args.parallax,
|
||||
mode=args.mode,
|
||||
fps=args.fps,
|
||||
max_angle_deg=args.angle,
|
||||
debug=not args.no_debug,
|
||||
)
|
||||
elapsed = time.perf_counter() - t0
|
||||
|
||||
print(f"\n[orbit] done in {elapsed:.1f}s")
|
||||
print(f" actor : {result['actor_path']}")
|
||||
print(f" has alpha : {result['has_alpha']}")
|
||||
print(f" has bg plate : {result['has_bg']}")
|
||||
print(f" frames dir : {result['frames_dir']} ({result['n_frames']} PNGs)")
|
||||
print(f" video : {result['video_path']}")
|
||||
if not args.no_debug:
|
||||
print(f" debug dir : {result['debug_dir']}")
|
||||
if not result['has_alpha']:
|
||||
print(f"\n TIP: Use 'No BG' on this image first for a much better orbit effect.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user