add yolo node

This commit is contained in:
logtd
2024-02-23 15:39:10 -07:00
parent 946b1d73d8
commit 3e46a5e33e
5 changed files with 137 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
.git
.vscode
**/__pycache__
**/*.ckpt
.DS_Store
+22
View File
@@ -0,0 +1,22 @@
# ComfyUI-TrackingNodes
ComfyUI nodes to track objects in videos using YOLOv8
## Table of Contents
- [Installation](#installation)
- [How to Install](#how-to-install)
- [How to Configure Models](#how-to-configure-models)
- [Examples](#examples)
## Installation
### How to Install
Clone or download this repo into your `ComfyUI/custom_nodes/` directory.
Then run `pip install -r requirments.txt` within the cloned repo.
### How to Configure Models
Download one of the YOLOv8 models from https://github.com/ultralytics/ultralytics and place it into `ComfyUI/custom_nodes/ComfyUI-TrackingNodes/models/`
## Accompanying Node Repos
* [InstanceDiffusion](https://github.com/logtd/ComfyUI-InstanceDiffusion)
* [AnimateDiff-Evolved](https://github.com/Kosinkadink/ComfyUI-AnimateDiff-Evolved)
+10
View File
@@ -0,0 +1,10 @@
from .nodes.yolo_tracker_node import YOLOTrackerNode
NODE_CLASS_MAPPINGS = {
"YOLOTrackerNode": YOLOTrackerNode,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"YOLOTrackerNode": "YOLO BoundingBox Tracker",
}
+95
View File
@@ -0,0 +1,95 @@
import os
import folder_paths
import numpy as np
import torch
from PIL import Image
import supervision as sv
from ultralytics import YOLO
folder_paths.folder_names_and_paths["yolov8"] = ([os.path.join(
folder_paths.models_dir, "yolov8")], folder_paths.supported_pt_extensions)
def get_model_dir():
root_path = folder_paths.folder_names_and_paths['custom_nodes'][0][0]
path = os.path.join(root_path, 'ComfyUI-TrackingNodes', 'models')
return path
def get_model_list() -> list[str]:
path = get_model_dir()
return os.listdir(path)
class YOLOTrackerNode:
def __init__(self) -> None:
...
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"images": ("IMAGE",),
"model_name": (get_model_list(), ),
},
}
RETURN_TYPES = ("IMAGE", "TRACKING")
FUNCTION = "track"
CATEGORY = "tracking"
def track(self, images, model_name):
B, H, W, C = images.shape
# load a custom model
model = YOLO(
f'{os.path.join(folder_paths.models_dir, "yolov8")}/{model_name}')
tracker = sv.ByteTrack()
box_annotator = sv.BoundingBoxAnnotator()
label_annotator = sv.LabelAnnotator()
annotated = []
tracked = {}
class_tracker_id_map = {}
for idx, image in enumerate(images):
image = (image.cpu().numpy() * 255).astype(np.uint8)
# bug with opencv2 and need to convert to pillow first
results = model(Image.fromarray(image))[0]
detections = sv.Detections.from_ultralytics(results)
detections = tracker.update_with_detections(detections)
for i in range(len(detections)):
detection = detections[i]
class_id = model.names[detection.class_id[0]].lower()
tracker_id = detection.tracker_id[0]
if class_id not in class_tracker_id_map:
class_tracker_id_map[class_id] = {}
if tracker_id not in class_tracker_id_map[class_id]:
next_id = len(class_tracker_id_map[class_id])
class_tracker_id_map[class_id][tracker_id] = next_id
if class_id not in tracked:
tracked[class_id] = {}
if tracker_id not in tracked[class_id]:
tracked[class_id][tracker_id] = [None] * len(images)
tracked[class_id][tracker_id][idx] = list(
map(lambda x: int(x), detection.xyxy[0])) + [W, H]
labels = [
f"#{tracker_id}.{results.names[class_id].lower()}"
for class_id, tracker_id
in zip(detections.class_id, detections.tracker_id)
]
annotated_frame = box_annotator.annotate(
image.copy(), detections=detections)
annotated.append(torch.FloatTensor(label_annotator.annotate(
annotated_frame, detections=detections, labels=labels))/255.)
annotated = torch.stack(annotated)
del model
return (annotated, tracked)
+5
View File
@@ -0,0 +1,5 @@
numpy
supervision
ultralytics
timm
scikit-image