乐于分享
好东西不私藏

【动手学YOLO】序列(七):计算机视觉AI工具库(Supervision库)案例:目标跟踪项目实践之车辆越线统计与跟踪

【动手学YOLO】序列(七):计算机视觉AI工具库(Supervision库)案例:目标跟踪项目实践之车辆越线统计与跟踪

本文摘自《动手学YOLO技术原理与项目实践》第五章,目前已在当当、京东等网站上架
书中全部数据及源代码均可从gitee网站
https://gitee.com/jiabiao1602/yolo11_object_detection)下载
我们继续使用YOLO11和ByteTrack,以跟踪繁忙高速公路上车辆的进出情况。我们的目标是构建一个高效系统,能够实时检测和跟踪车辆,同时准确统计它们的移动情况。我们可以使用Supervision库的

LineZoneLineZoneAnnotator类,轻松统计穿越预定义线条的对象数量。

LineZone类是一个用于越线检测的重要工具。它提供了一系列方法来定义越线区域、检测对象穿越情况,并统计相关信息。参数描述如表5-2所示。

表5-2 LineZone类参数描述

名称
类型
描述
in_count
int
从外部穿越到内部跨越线条的对象数量
out_count
int
从内部穿越到外部跨越线条的对象数量
in_count_per_class
Dict[int, int]
从外部穿越到内部,每个类别的对象数量
out_count_per_class
Dict[int, int]
从内部穿越到外部,每个类别的对象数量

LineZone的主要方法:

  • trigger(self, detections):越线检测方法。此方法接受一个检测到的对象列表(通常是从目标检测模型输出的结果),并返回两个列表:crossed_incrossed_outcrossed_in包含从外部穿越到内部的对象,而crossed_out包含从内部穿越到外部的对象。这使得LineZone能够实时地跟踪和统计对象的越线情况。
  • reset(self):此方法可用于重置LineZone的内部状态,例如清除之前的越线记录等。这在执行新的检测任务时可能非常有用。

sv.LineZoneAnnotator类是用于在图像上绘制越线检测区域(LineZone)并标注检测到的对象数量,其参数描述如表5-3所示。

表5-3 LineZoneAnnotator类参数描述

名称
类型
描述
thickness
int
线条粗细。
color
Color
线条颜色。
text_thickness
int
文本粗细。
text_color
Color
文本颜色。
text_scale
float
文本缩放比例。
text_offset
float
文本距离线条的远近。
text_padding
int
文本框中文本周围的空白空间。
custom_in_text
Optional[str]
用其他内容替换“in”。
custom_out_text
Optional[str]
用其他内容替换“out”。
display_in_count
bool
传入False以隐藏“in”计数。
display_out_count
bool
传入False以隐藏“out”计数。
display_text_box
bool
传入False以隐藏文本背景框。
text_orient_to_line
bool
使文本方向与线条方向一致。建议设置为True。
text_centered
bool
传入False以禁用文本居中。当标签遮挡重要内容时很有用。

LineZoneAnnotator的主要方法为annotate(frame, line_counter),用于在给定的图像帧上使用提供的线条区域(LineZone)绘制线条,并可能包括相关的计数和文本信息。其中,参数frame为要在其上绘制线条的图像,参数line_counter为线条区域对象,用于绘制线条。

本案例中我们将使用vehicles.mp4视频文件,可通过以下代码下载到本地。

from supervision.assets import download_assets, VideoAssets
download_assets(VideoAssets.VEHICLES)

运行以下代码以查看视频信息。

from ultralytics import YOLO
import supervision as sv
import cv2
import numpy as np
from datetime import timedelta
import os

# 查看视频信息
video_path = ('./videos/vehicles.mp4')
get_video_info(video_path)

输出结果为:

Video Resolution: (3840, 2160)
FPS: 25
Length: 0:00:22

视频的分辨率为3840×2160,帧率为25,时长为22秒。

下面代码的主要功能是从视频文件中读取帧,使用YOLO模型进行目标检测,并在检测结果的基础上对帧进行标注(包括边界框、标签和计数线)。

# 定义视频文件路径
video_path = ('./videos/vehicles.mp4')

# 使用视频路径获取视频信息
sv.VideoInfo.from_video_path(video_path)

# 获取视频帧生成器
generator = sv.get_video_frames_generator(video_path)
# 提取第一帧
frame = next(generator)

# 加载YOLO模型
model = YOLO("./weights/yolo11x.pt")
# 使用模型对帧进行推理,获取结果
results = model(frame, verbose=False)[0]
# 从推理结果中提取检测信息
detections = sv.Detections.from_ultralytics(results)

# 根据检测结果生成标签
labels = [
f"{results.names[class_id]}{confidence:0.2f}"
for class_id, confidence
in zip(detections.class_id, detections.confidence)
]

# 创建边界框注释器
bounding_box_annotator = sv.BoxAnnotator(thickness=4)
# 创建标签注释器
label_annotator = sv.LabelAnnotator(text_thickness=4, text_scale=2)

# 对帧进行注释
annotated_frame = frame.copy()
annotated_frame = bounding_box_annotator.annotate(annotated_frame, detections)
annotated_frame = label_annotator.annotate(annotated_frame, detections, labels)
# 显示注释后的帧

# 定义计数线的起点和终点
LINE_START = sv.Point(501500)
LINE_END = sv.Point(3840-501500)

# 创建线区域对象
line_zone = sv.LineZone(start=LINE_START, end=LINE_END)

# 创建线区域注释器
line_zone_annotator = sv.LineZoneAnnotator(
    thickness=4,
    text_thickness=4,
    text_scale=2)

# 对帧进行线区域注释
annotated_frame = frame.copy()
annotated_frame = line_zone_annotator.annotate(annotated_frame, line_counter=line_zone)
# 显示注释后的帧
sv.plot_image(annotated_frame, (1212))

代码的具体功能如下:

  • 加载视频并获取信息:定义视频路径,获取视频信息和帧生成器。
  • 加载模型并推理:加载YOLO模型,对第一帧进行推理,提取检测结果。
  • 生成标签:根据检测结果生成标签。
  • 创建注释器:创建边界框和标签注释器。
  • 注释帧:对帧进行边界框和标签注释。
  • 添加计数线:定义计数线的起点和终点,创建线区域对象和注释器。
  • 显示注释后的帧:对帧进行线区域注释并显示。

代码运行结果如图5-29所示。

图5-29 对帧进行注释(包括边界框、标签和计数线)

下面代码主要用于处理视频中的目标检测和追踪,并在每一帧上绘制边界框、标签和轨迹。

# 初始化追踪器
byte_tracker = sv.ByteTrack()

# 初始化边界框注释器,设置边界框的厚度
bounding_box_annotator = sv.BoxAnnotator(thickness=4)
# 初始化标签注释器,设置标签文本的厚度和比例
label_annotator = sv.LabelAnnotator(text_thickness=4, text_scale=2)
# 初始化轨迹注释器,设置轨迹的厚度
trace_annotator = sv.TraceAnnotator(thickness=4)

defcallback(frame: np.ndarray, index:int) -> np.ndarray:
"""
    回调函数,处理每一帧视频。

    参数:
        frame: 当前视频帧。
        index: 当前帧的索引。

    返回:
        处理后的视频帧。
    """

# 使用模型处理当前帧,获取结果
    results = model(frame, verbose=False)[0]
# 从结果中提取检测信息
    detections = sv.Detections.from_ultralytics(results)
# 使用字节追踪器更新检测信息
    detections = byte_tracker.update_with_detections(detections)

# 生成标签列表,包含每个检测对象的追踪ID、类别和置信度
    labels = [
f"#{tracker_id}{model.model.names[class_id]}{confidence:0.2f}"
for confidence, class_id, tracker_id
in zip(detections.confidence, detections.class_id, detections.tracker_id)
    ]

# 复制当前帧,用于绘制注释
    annotated_frame = frame.copy()
# 使用轨迹注释器在帧上绘制轨迹
    annotated_frame = trace_annotator.annotate(
        scene=annotated_frame,
        detections=detections)
# 使用边界框注释器在帧上绘制边界框
    annotated_frame = bounding_box_annotator.annotate(
        scene=annotated_frame,
        detections=detections)
# 使用标签注释器在帧上绘制标签
    annotated_frame = label_annotator.annotate(
        scene=annotated_frame,
        detections=detections,
        labels=labels)

# 触发线区域检测
    line_zone.trigger(detections)

# 更新进度条
    progress_bar(index)

# 返回绘制了线区域的帧
return  line_zone_annotator.annotate(annotated_frame, line_counter=line_zone)

# 设置目标视频路径
TARGET_VIDEO_PATH = "count-objects-crossing-the-line-result.mp4"

# 处理视频,将源视频路径、目标视频路径和回调函数作为参数
sv.process_video(
    source_path = video_path,
    target_path = TARGET_VIDEO_PATH,
    callback=callback
)

代码的具体功能如下:

  1. 初始化:设置追踪器、边界框注释器、标签注释器和轨迹注释器。
  2. 回调函数 callback
    • 处理每一帧视频,提取检测信息并更新追踪信息。
    • 生成包含追踪ID、类别和置信度的标签列表。
    • 在帧上绘制轨迹、边界框和标签。
    • 触发线区域检测,并在帧上绘制线区域。
  3. 视频处理:调用 process_video 函数处理源视频,并将结果保存到目标路径。

输出count-objects-crossing-the-line-result.mp4的视频文件截图如图5-30所示。

图5-30 通过计数线统计进出车辆数量

过往文章:

【动手学YOLO】序列(六):计算机视觉AI工具库(Supervision库)案例:目标跟踪项目实践

【动手学YOLO】序列(五):计算机视觉AI工具库(Supervision库)过滤目标检测结果

【动手学YOLO】序列(四):计算机视觉AI工具库(Supervision库)保存目标检测结果

【动手学YOLO】序列(三):计算机视觉AI工具库(Supervision库)视频处理的相关函数

【动手学YOLO】序列(二):计算机视觉AI工具库(Supervision库)标注目标检测结果

【动手学YOLO】序列(一):计算机视觉AI工具库(Supervision库)安装及使用