123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- import cv2
- import numpy as np
- from ultralytics import YOLO
- import supervision as sv
- from supervision.detection.core import Detections
- class PlayerDetector:
- def __init__(self, model_path=None, confidence=0.5, iou_threshold=0.45):
- """
- 初始化球员检测器
-
- Args:
- model_path: YOLO模型路径,如果为None则使用预训练模型
- confidence: 检测置信度阈值
- iou_threshold: NMS IOU阈值
- """
- self.confidence_threshold = confidence
- self.iou_threshold = iou_threshold
-
- if model_path:
- self.model = YOLO(model_path)
- else:
- # 使用预训练的YOLOv8模型
- print("加载YOLOv8预训练模型")
- self.model = YOLO("yolov8n.pt")
-
- # 人员检测类别ID (COCO数据集中的person类别为0)
- self.person_class_id = 0
-
- # 初始化监督库的标注工具
- self.box_annotator = sv.BoxAnnotator(
- thickness=2,
- text_thickness=2,
- text_scale=0.5
- )
-
- def detect(self, frame):
- """
- 检测帧中的球员
-
- Args:
- frame: 输入的视频帧
-
- Returns:
- 检测到的人物边界框列表 [x1, y1, x2, y2, confidence]
- """
- # 使用YOLO模型进行检测,可以调整参数来提高精度
- results = self.model(
- frame,
- verbose=False,
- conf=self.confidence_threshold,
- iou=self.iou_threshold,
- classes=[self.person_class_id] # 只检测人员
- )[0]
-
- # 提取人员检测结果
- detections = []
-
- for r in results.boxes.data.cpu().numpy():
- x1, y1, x2, y2, conf, class_id = r
-
- # 已经在YOLO调用时过滤了类别,这里再次确认是否为人员
- if int(class_id) == self.person_class_id and conf > self.confidence_threshold:
- # 添加一些额外的过滤,比如尺寸过滤(可选)
- box_width = x2 - x1
- box_height = y2 - y1
- box_area = box_width * box_height
- img_area = frame.shape[0] * frame.shape[1]
-
- # 过滤掉太小或太大的检测框
- area_ratio = box_area / img_area
- if 0.0005 < area_ratio < 0.2: # 根据实际场景调整这些值
- detections.append([x1, y1, x2, y2, conf])
-
- return np.array(detections) if detections else np.empty((0, 5))
-
- def visualize(self, frame, detections):
- """
- 可视化检测结果
-
- Args:
- frame: 原始视频帧
- detections: 检测结果
-
- Returns:
- 标注后的视频帧
- """
- # 复制原始帧以避免修改
- annotated_frame = frame.copy()
-
- # 使用supervision库进行可视化(更好的可视化效果)
- if len(detections) > 0:
- # 转换为supervision的Detections格式
- sv_detections = Detections(
- xyxy=detections[:, :4],
- confidence=detections[:, 4],
- class_id=np.zeros(len(detections), dtype=int) # 全部是人员类别
- )
-
- # 添加标签
- labels = [f"{conf:.2f}" for conf in detections[:, 4]]
-
- # 绘制检测框和标签
- annotated_frame = self.box_annotator.annotate(
- scene=annotated_frame,
- detections=sv_detections,
- labels=labels
- )
-
- return annotated_frame
-
- return annotated_frame
-
- def detect_with_supervision(self, frame):
- """
- 使用Supervision库进行检测和结果格式化,提供更标准的输出
-
- Args:
- frame: 输入的视频帧
-
- Returns:
- Supervision库的Detections对象
- """
- # 使用YOLO模型进行检测
- results = self.model(frame, verbose=False, conf=self.confidence_threshold, classes=[self.person_class_id])[0]
-
- # 转换为supervision的Detections格式
- detections = sv.Detections.from_ultralytics(results)
-
- # 过滤出人员类别
- mask = np.array([int(cls) == self.person_class_id for cls in detections.class_id], dtype=bool)
- detections = detections[mask]
-
- return detections
|