【动手学YOLO】序列(七):计算机视觉AI工具库(Supervision库)案例:目标跟踪项目实践之车辆越线统计与跟踪
LineZone及LineZoneAnnotator类,轻松统计穿越预定义线条的对象数量。
LineZone类是一个用于越线检测的重要工具。它提供了一系列方法来定义越线区域、检测对象穿越情况,并统计相关信息。参数描述如表5-2所示。
表5-2 LineZone类参数描述
|
|
|
|
|---|---|---|
in_count |
|
|
out_count |
|
|
in_count_per_class |
|
|
out_count_per_class |
|
|
LineZone的主要方法:
-
trigger(self, detections):越线检测方法。此方法接受一个检测到的对象列表(通常是从目标检测模型输出的结果),并返回两个列表:crossed_in和crossed_out。crossed_in包含从外部穿越到内部的对象,而crossed_out包含从内部穿越到外部的对象。这使得LineZone能够实时地跟踪和统计对象的越线情况。 -
reset(self):此方法可用于重置LineZone的内部状态,例如清除之前的越线记录等。这在执行新的检测任务时可能非常有用。
sv.LineZoneAnnotator类是用于在图像上绘制越线检测区域(LineZone)并标注检测到的对象数量,其参数描述如表5-3所示。
表5-3 LineZoneAnnotator类参数描述
|
|
|
|
|---|---|---|
thickness |
|
|
color |
|
|
text_thickness |
|
|
text_color |
|
|
text_scale |
|
|
text_offset |
|
|
text_padding |
|
|
custom_in_text |
|
|
custom_out_text |
|
|
display_in_count |
|
|
display_out_count |
|
|
display_text_box |
|
|
text_orient_to_line |
|
|
text_centered |
|
|
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(50, 1500)
LINE_END = sv.Point(3840-50, 1500)
# 创建线区域对象
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, (12, 12))
代码的具体功能如下:
-
加载视频并获取信息:定义视频路径,获取视频信息和帧生成器。 -
加载模型并推理:加载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
)
代码的具体功能如下:
-
初始化:设置追踪器、边界框注释器、标签注释器和轨迹注释器。 -
回调函数 callback: -
处理每一帧视频,提取检测信息并更新追踪信息。 -
生成包含追踪ID、类别和置信度的标签列表。 -
在帧上绘制轨迹、边界框和标签。 -
触发线区域检测,并在帧上绘制线区域。 -
视频处理:调用 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库)安装及使用

夜雨聆风