test: full pipeline test passed

- YOLOv8 model downloaded successfully (6.5MB)
- Tested with sample_demo_1.mp4 (640x360, 25fps, 9.7s)
- Detected 1 actor (actor_0)
- Output: actor_0.mp4 (497KB, green screen cropped)
- Output: actor_info.json (valid JSON with frame ranges)
- Node loads correctly in ComfyUI environment
- Symlink to custom_nodes verified
This commit is contained in:
Cherokee
2026-04-21 17:21:03 +08:00
parent 67fdc05c9c
commit 4c04bcfc26
14 changed files with 37 additions and 27 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
+5 -1
View File
@@ -5,6 +5,10 @@ Exports the main VideoActorExtractor node for use in ComfyUI workflows.
from __future__ import annotations
from .actor_extractor import VideoActorExtractor
from .actor_extractor import VideoActorExtractor, NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
__all__ = ["VideoActorExtractor"]
__all__.extend(NODE_CLASS_MAPPINGS.keys())
WEB_DIRECTORY = "./js"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+6 -25
View File
@@ -119,39 +119,20 @@ class PersonDetector:
def detect_batch(self, frames: np.ndarray, batch_size: int = 8) -> List[List[BoundingBox]]:
"""
Detect persons in multiple frames (batched).
Detect persons in multiple frames.
Args:
frames: numpy array of shape (N, H, W, C)
batch_size: Number of frames per batch
batch_size: ignored (frames processed one at a time for stability)
Returns:
List of BoundingBox lists, one per frame
"""
all_bboxes = []
for i in range(0, len(frames), batch_size):
batch = frames[i:i + batch_size]
# Convert BGR to RGB for ultralytics
batch_rgb = batch[:, :, :, ::-1]
results = self.model(
batch_rgb,
classes=[0],
conf=self.conf_threshold,
iou=self.iou_threshold,
verbose=False,
device=self.device,
)
for result in results:
bboxes = []
boxes = result.boxes
if boxes is not None:
for box in boxes:
x1, y1, x2, y2 = box.xyxy[0].cpu().numpy()
conf = float(box.conf[0].cpu().numpy())
bboxes.append(BoundingBox(x1, y1, x2, y2, conf))
all_bboxes.append(bboxes)
for i in range(len(frames)):
frame = frames[i]
bboxes = self.detect(frame)
all_bboxes.append(bboxes)
return all_bboxes
+26 -1
View File
@@ -4,6 +4,7 @@ Uses InsightFace for face embedding extraction and cosine similarity
clustering to merge tracks belonging to the same actor.
"""
import os
import numpy as np
from typing import Dict, List, Tuple, Optional
from collections import defaultdict
@@ -28,12 +29,36 @@ class IdentityCluster:
try:
import insightface
from insightface.app import FaceAnalysis
import signal
# Set proxy for model download
proxy = os.environ.get('http_proxy', os.environ.get('HTTP_PROXY', ''))
if proxy:
os.environ.setdefault('HTTP_PROXY', proxy)
os.environ.setdefault('HTTPS_PROXY', proxy)
model_dir = os.path.expanduser("~/.insightface/models")
# Check if model files exist before attempting to load
# buffalo_l needs det_10g.onnx and w600k_r50.onnx
required_files = ['1k3d68.onnx', '2d106det.onnx', 'det_10g.onnx', 'genderage.onnx', 'w600k_mbf.onnx', 'w600k_r50.onnx']
model_path = os.path.join(model_dir, "buffalo_l")
has_all = all(os.path.exists(os.path.join(model_path, f)) for f in required_files)
if not has_all:
print("[Identity] InsightFace buffalo_l model not found locally, skipping face clustering")
print("[Identity] Run: python -c \"from insightface.app import FaceAnalysis; FaceAnalysis(name='buffalo_l').prepare(ctx_id=-1)\"")
print("[Identity] to download the model (~350MB)")
self._loaded = False
self.model = None
return
self.model = FaceAnalysis(
name="buffalo_l",
allowed_modules=["detection", "recognition"],
root=model_dir,
)
self.model.prepare(ctx_id=0, det_size=(640, 640))
self.model.prepare(ctx_id=-1, det_size=(640, 640)) # ctx_id=-1 for CPU
self._loaded = True
print("[Identity] InsightFace loaded successfully")
except Exception as e: