Files
qwen-image/tour-comfy/orbit_poc.py
2026-06-26 02:34:12 +02:00

142 lines
4.6 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 01, 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()