赛题内容
场景描述: 这是一个城市管理领域的赛题,具体来说是在城市监控视频中自动检测和分类各种违规行为的智能识别系统开发竞赛。
赛题目的: 这个赛题旨在解决城市治理中由于人力不足和效率低下导致的传统管理模式难以应对的问题。具体地,它要求开发一套能够自动检测城市中诸如机动车违停、非机动车违停、占道经营等违规行为的智能系统。该系统通过分析摄像头捕获的视频流来识别这些违规行为,并及时通知相关部门采取措施,从而提高城市管理的效率和质量。
YOLO 简要了解
YOLO框架(You Only Look Once)与RCNN系列算法不一样,是以不同的方式处理对象检测。它将整个图像放在一个实例中,并预测这些框的边界框坐标和及所属类别概率。使用YOLO算法最大优的点是速度极快,每秒可处理45帧,也能够理解一般的对象表示。
YOLOv1的核心思想就是利用整张图作为网络的输入,直接在输出层回归bounding box的位置和bounding box所属的类别。
将一幅图像分成SxS个网格(grid cell),如果某个object的中心落在这个网格中,则这个网格就负责预测这个object。
YOLO基本流程
输入图像预处理
- 图像尺寸标准化:将输入图像调整为固定大小(例如,YOLO v1 使用的是448x448像素)。
- 图像归一化:通常对像素值进行归一化处理,使其范围在0到1之间。
网络架构
- 卷积神经网络 (CNN):YOLO 使用深度卷积神经网络来提取图像中的特征。早期版本使用类似于 GoogLeNet 或 Darknet 的架构,而后续版本则不断优化网络结构。
输出预测
- 网格划分:将图像划分为一个 SxS 的网格。每个网格负责预测出现在该网格内的物体。
- 边界框预测:每个网格单元预测 B 个边界框(bounding boxes)及其置信度分数。
- 边界框坐标:每个边界框由中心点坐标 (cx, cy) 和宽度 w、高度 h 组成。这些值相对于整个图像的尺寸进行归一化。
- 置信度分数:代表边界框内存在物体的概率,同时也考虑了预测框与真实框之间的交并比 (IoU)。
- 类别概率:对于每个边界框,预测一个条件类别概率分布,即在框内有物体的情况下,该物体属于某个类别的概率。
后处理
- 阈值筛选:通过设置一个阈值来过滤掉低置信度的边界框。
- 非极大值抑制 (NMS):为了去除多余的边界框,使用 NMS 算法来选择最有可能表示同一物体的边界框。这个过程基于 IoU 的阈值来决定哪些预测框应该被保留。
训练过程
- 损失函数:YOLO 使用一个综合的损失函数来优化边界框坐标、置信度得分和类别概率。
- 坐标损失:计算预测框与真实框之间的坐标差异。
- 置信度损失:计算预测的置信度得分与实际的 IoU 值之间的差异。
- 类别损失:计算预测类别概率分布与实际类别的差异。
示例
假设在一个 7x7 的网格中,每个网格预测 2 个边界框,并且有 20 个类别,那么输出张量的大小将是 7x7x(2*(4+1)+20) = 7x7x30。其中 4 表示边界框的坐标 (cx, cy, w, h),1 表示置信度分数,20 表示类别概率。
这就是 YOLO 的基本原理和步骤。不同的版本在这些基础上进行了优化和改进,比如增加了残差连接、使用了更复杂的网络架构或者引入了数据增强技巧等。
问题思考
如果检测目标被网络分成好几部分,算法又是如何操作的?
处理目标跨越多个网格单元的情况:
-
目标分割:当目标过大时,它可能跨越多个网格单元。每个网格单元负责检测其内部的物体,因此大的目标可能会被分割成多个部分。
-
最大置信度原则:YOLO 通过每个网格单元预测的最大置信度来确定哪个网格单元负责检测特定的目标。这意味着,即使一个大的目标跨越了多个网格,只有一个网格单元会负责预测该目标。
-
非极大值抑制 (NMS):在后处理阶段,YOLO 使用 NMS 来合并重叠的边界框。即使一个大的目标被分割成多个部分,NMS 也会尝试合并这些部分以形成一个完整的边界框
举个例子,假设有一个大的汽车横跨了两个相邻的网格单元。在这种情况下,每个网格单元都会试图预测出现在其内部的部分。其中一个网格单元可能会预测汽车的一部分,而另一个网格单元也可能预测另一部分。在后处理阶段,非极大值抑制 (NMS) 会检查所有预测的边界框,并合并那些具有高重叠度的边界框,从而形成一个包围整个汽车的边界框。
Baseline
baseline使用的模型是 yolov8n 模型。
YOLOv8 系列:
- YOLOv8n:轻量级版本,适用于实时应用和资源受限的设备。
- YOLOv8s:小型版本,比 YOLOv8n 更大,提供更好的检测精度。
- YOLOv8m:中型版本,提供更好的精度和速度之间的平衡。
- YOLOv8l:大型版本,具有更高的检测精度,但速度相对较慢。
- YOLOv8x:超大型版本,提供最高的检测精度,但速度和模型大小也相应增加。
代码精读:
# 读取训练集中的视频和对应的标注文件
for anno_path, video_path in zip(train_annos[:5], train_videos[:5])
print(video_path)
# 从标注文件中加载数据
anno_df = pd.read_json(anno_path)
# 打开视频文件
cap = cv2.VideoCapture(video_path)
# 初始化帧索引
frame_idx = 0
# 读取视频的所有画面
while True:
# 读取下一帧
ret, frame = cap.read()
# 如果无法读取帧(已到视频末尾),则跳出循环
if not ret:
break
# 获取当前帧的高度和宽度
img_height, img_width = frame.shape[:2]
# 提取当前帧的标注信息
frame_anno = anno_df[anno_df['frame_id'] == frame_idx]
# 将当前帧保存为图片文件
cv2.imwrite('./yolo-dataset/train/' + anno_path.split('/')[-1][:-5] + '_' + str(frame_idx) + '.jpg', frame)
# 如果当前帧存在标注信息
if len(frame_anno) != 0:
# 创建对应的YOLO标注文件
with open('./yolo-dataset/train/' + anno_path.split('/')[-1][:-5] + '_' + str(frame_idx) + '.txt', 'w') as up:
# 遍历每个标注
for category, bbox in zip(frame_anno['category'].values, frame_anno['bbox'].values):
# 查找类别索引
category_idx = category_labels.index(category)
# 解析边界框坐标
x_min, y_min, x_max, y_max = bbox
# 计算YOLO格式的标注值:中心点坐标(x, y)和边界框宽高(w, h),都归一化到0-1范围内
x_center = (x_min + x_max) / 2 / img_width
y_center = (y_min + y_max) / 2 / img_height
width = (x_max - x_min) / img_width
height = (y_max - y_min) / img_height
# 检查中心点坐标是否超出范围
if x_center > 1:
print(bbox)
# 写入标注文件
up.write(f'{category_idx} {x_center} {y_center} {width} {height}\n')
# 更新帧索引
frame_idx += 1
从一组训练视频中读取每一帧,并将其保存为图片文件。同时,如果该帧有标注信息,则会将标注转换成YOLO格式并保存到相应的文本文件中。
from ultralytics import YOLO
# 加载预训练的YOLO模型
model = YOLO("runs/detect/train/weights/best.pt")
# 遍历测试集中的所有视频文件
for path in glob.glob('测试集/*.mp4'):
# 初始化一个列表用于存储预测结果
submit_json = []
# 使用模型对视频进行预测
results = model(path, conf=0.05, imgsz=1080, verbose=False)
# 遍历每个预测结果
for idx, result in enumerate(results):
# 获取边界框信息
boxes = result.boxes # 包含边界框信息的对象
# 如果没有检测到任何物体,则跳过当前帧
if len(boxes.cls) == 0:
continue
# 转换边界框坐标为xyxy格式,并进行四舍五入
xywh = boxes.xyxy.data.cpu().numpy().round()
# 获取类别标签
cls = boxes.cls.data.cpu().numpy().round()
# 获取置信度
conf = boxes.conf.data.cpu().numpy()
# 遍历每个检测结果
for i, (ci, xy, confi) in enumerate(zip(cls, xywh, conf)):
# 构建一个字典来存储当前检测的结果
submit_json.append(
{
'frame_id': idx, # 当前帧的索引
'event_id': i + 1, # 当前事件(检测结果)的索引
'category': category_labels[int(ci)], # 类别标签
'bbox': [int(x) for x in xy], # 边界框坐标
"confidence": float(confi) # 置信度
}
)
# 将预测结果保存为JSON文件
with open('./result/' + path.split('/')[-1][:-4] + '.json', 'w', encoding='utf-8') as up:
json.dump(submit_json, up, indent=4, ensure_ascii=False)
使用YOLO模型对测试集中的视频进行目标检测,并将检测结果以JSON格式保存。具体步骤包括:
- 加载预先训练好的YOLO模型。
- 遍历测试集中的视频文件。
- 对每个视频进行预测,提取边界框、类别标签和置信度等信息。
- 如果某帧没有检测到任何物体,则跳过该帧。
- 将每帧的检测结果保存到一个列表中。
- 最终将检测结果以JSON格式保存到指定路径下的文件中。