Files
Cherokee d6d208081b feat: add SelectActorPreview node, identity temporal constraints, and preview images to disk
- Add SelectActorPreview node to load per-actor preview images as ComfyUI IMAGE tensors
- Fix SelectActorPreview return value: must return (tensor,) tuple, not bare tensor,
  to prevent ComfyUI's merge_result_data from misinterpreting batch dimension as
  output count (root cause of 1920-image bug)
- Change VideoActorExtractor third output from IMAGE tensor to INT actor_count
- Save top-5 preview JPGs per actor to {output_dir}/previews/ instead of
  building a large preview tensor in memory
- Unify InsightFace model path to ComfyUI/models/video-actor-extract/buffalo_l/
- Add temporal gap penalty with grace gap to identity clustering
- Add temporal boost with Gaussian decay and spatial blocker check
- Add dual-signal track splitting (centroid displacement + bbox area ratio)
- Add spatial centroid proximity tiebreaker for identity merging
- Add debris mask filtering (min_mask_area=20000) in MaskTracker
- Clean up unused imports across modified files
- Add AGENTS.md project guidelines and test infrastructure
2026-04-29 09:34:33 +08:00

77 lines
2.2 KiB
Python

"""
ComfyUI-VideoActorExtract
Extract individual actors from video with green screen background.
"""
import os
import sys
# Add plugin directory to Python path
plugin_dir = os.path.dirname(os.path.abspath(__file__))
if plugin_dir not in sys.path:
sys.path.insert(0, plugin_dir)
# Use importlib to avoid namespace conflicts with ComfyUI's own 'nodes' module
import importlib.util
def _load_module(name, path):
spec = importlib.util.spec_from_file_location(name, path)
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
spec.loader.exec_module(module)
return module
# Load core modules first
core_config = _load_module(
"vae_core_config", os.path.join(plugin_dir, "core", "config.py")
)
vae_video_reader = _load_module(
"vae_video_reader", os.path.join(plugin_dir, "core", "video_reader.py")
)
# Load pipeline modules
vae_detector = _load_module(
"vae_detector", os.path.join(plugin_dir, "pipeline", "detector.py")
)
vae_tracker = _load_module(
"vae_tracker", os.path.join(plugin_dir, "pipeline", "tracker.py")
)
vae_identity = _load_module(
"vae_identity", os.path.join(plugin_dir, "pipeline", "identity.py")
)
vae_cropper = _load_module(
"vae_cropper", os.path.join(plugin_dir, "pipeline", "cropper.py")
)
vae_merger = _load_module(
"vae_merger", os.path.join(plugin_dir, "pipeline", "merger.py")
)
vae_segmenter = _load_module(
"vae_segmenter", os.path.join(plugin_dir, "pipeline", "segmenter.py")
)
# Load main node
vae_actor_extractor = _load_module(
"vae_actor_extractor", os.path.join(plugin_dir, "nodes", "actor_extractor.py")
)
vae_select_preview = _load_module(
"vae_select_preview", os.path.join(plugin_dir, "nodes", "select_preview.py")
)
NODE_CLASS_MAPPINGS = {}
NODE_DISPLAY_NAME_MAPPINGS = {}
# Register nodes from all node modules
for mod in [vae_actor_extractor, vae_select_preview]:
if hasattr(mod, "NODE_CLASS_MAPPINGS"):
NODE_CLASS_MAPPINGS.update(mod.NODE_CLASS_MAPPINGS)
if hasattr(mod, "NODE_DISPLAY_NAME_MAPPINGS"):
NODE_DISPLAY_NAME_MAPPINGS.update(mod.NODE_DISPLAY_NAME_MAPPINGS)
WEB_DIRECTORY = "./js"
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
print("[VideoActorExtract] Plugin loaded successfully!")