一、赛事背景
本赛题最终目标是开发一套智能识别系统,能够自动检测和分类城市管理中的违规行为。该系统应利用先进的图像处理和计算机视觉技术,通过对摄像头捕获的视频进行分析,自动准确识别违规行为,并及时向管理部门发出告警,以实现更高效的城市管理。
初赛任务是根据给定的城管视频监控数据集,进行城市违规行为的检测。违规行为主要包括垃圾桶满溢、机动车违停、非机动车违停等。设计算法实现从视频中分析并标记出违规行为,提供违规行为发生的时间和位置信息。
赛事链接:MARS大数据服务平台
Baseline链接:Datawhale
云服务器推荐:厚德云
完整代码详见:https://www.modelscope.cn/datasets/Datawhale/AI_Camp5_baseline_CV.git
二、赛题Baseline
2.1数据读取
从大赛官网MARS大数据服务平台下载训练集和测试集并解压,读取并可视化无标注的数据集,例如用 json.load 或 pd.read_json 读取json数据,使用 cap.read() 从视频捕获设备或视频文件中读取下一帧。
pd.read_json('训练集(有标注第一批)/标注/45.json')
video_path = '训练集(有标注第一批)/视频/45.mp4'
cap = cv2.VideoCapture(video_path)
while True:
# 读取下一帧
ret, frame = cap.read()
if not ret:
break
break
bbox = [746, 494, 988, 786]
pt1 = (bbox[0], bbox[1])
pt2 = (bbox[2], bbox[3])
color = (0, 255, 0)
thickness = 2 # 线条粗细
cv2.rectangle(frame, pt1, pt2, color, thickness)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
plt.imshow(frame)
2.2数据转换
2.2.1 划分数据集
将训练集和验证集单独存放在不同文件夹中,在yolo.yaml里写入写入数据集的路径。
if not os.path.exists('yolo-dataset/'):
os.mkdir('yolo-dataset/')
if not os.path.exists('yolo-dataset/train'):
os.mkdir('yolo-dataset/train')
if not os.path.exists('yolo-dataset/val'):
os.mkdir('yolo-dataset/val')
dir_path = os.path.abspath('./') + '/'
# 需要按照你的修改path
with open('yolo-dataset/yolo.yaml', 'w', encoding='utf-8') as up:
up.write(f'''
path: {dir_path}/yolo-dataset/
train: train/
val: val/
names:
0: 非机动车违停
1: 机动车违停
2: 垃圾桶满溢
3: 违法经营
''')
分类标签为四类,分别为"非机动车违停", "机动车违停", "垃圾桶满溢", "违法经营"。
2.2.2 提取视频帧信息
处理视频数据集,从视频文件中提取帧,并将相应的注释信息写入到YOLO格式的标注文件中。
- YOLO使用的标注格式是每张图像一个文本文件,文件名与图像文件名相对应。文本文件中每一行对应一个边界框,格式为:
<class> <x_center> <y_center> <width> <height>
。 - 其中,
<class>
是类别索引,<x_center>
和<y_center>
是边界框中心点相对于图像宽度和高度的比例,<width>
和<height>
是边界框的宽度和高度相对于图像宽度和高度的比例。
# 读取训练集视频
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:
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)
# 计算yolo标注格式
x_min, y_min, x_max, y_max = bbox
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
2.2.3配置Ultralytics
配置ultralytics框架并下载YOLOv8权重文件。Ultralytics是一个开源的计算机视觉和深度学习框架,旨在简化训练、评估和部署视觉模型的过程。该框架提供了一系列流行的视觉模型,包括YOLOv5、YOLOv4、YOLOv3、YOLOv3-tiny、YOLOv5-tiny、EfficientDet、PAN、PP-YOLO等,并提供了训练、评估和推理的工具和实用程序。
!wget http://mirror.coggle.club/yolo/yolov8n-v8.2.0.pt -O yolov8n.pt
!mkdir -p ~/.config/Ultralytics/
!wget http://mirror.coggle.club/yolo/Arial.ttf -O ~/.config/Ultralytics/Arial.ttf
2.3模型训练
使用ultralytics框架加载YOLOv8模型进行训练。
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
import warnings
warnings.filterwarnings('ignore')
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
results = model.train(data="yolo-dataset/yolo.yaml", epochs=50, imgsz=1080, batch=16)
-
box_loss
是边界框回归损失,用于评估预测的边界框与真实边界框之间的差异。 -
cls_loss
是分类损失,用于评估类别预测的准确性。 -
dfl_loss
是防御性损失,用于提高模型的泛化能力。
经过几个训练周期后,模型的边界框损失、分类损失和防御性损失都有所下降,这表明模型在训练过程中学习了如何更好地预测边界框和分类,同时,模型的 mAP50 和 mAP50-95 指标也有所提高,这表明模型的整体性能有所提升,我们可以在此基础上加大模型训练的轮数(epoch)和批次(batch)来观察loss指标和MAP指标的变化趋势,从而选择最优的模型进行验证和提交。
2.4模型验证
加载刚刚训练保存的最好权重到网络中,使用YOLO模型对视频进行检测,设置置信度阈值为0.05,图像大小为1080像素,从result
中提取边界框、掩码、关键点、概率和方向框等数据,将边界框数据转换为xywh
格式,并将其转为numpy数组,对于frame_id、event_id、category、bbox、confidence构建字典并保存为json格式的数据。
from ultralytics import YOLO
model = YOLO("runs/detect/train/weights/best.pt")
import glob
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 # Boxes object for bounding box outputs
masks = result.masks # Masks object for segmentation masks outputs
keypoints = result.keypoints # Keypoints object for pose outputs
probs = result.probs # Probs object for classification outputs
obb = result.obb # Oriented boxes object for OBB outputs
if len(boxes.cls) == 0:
continue
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': list([int(x) for x in xy]),
"confidence": float(confi)
}
)
with open('./result/' + path.split('/')[-1][:-4] + '.json', 'w', encoding='utf-8') as up:
json.dump(submit_json, up, indent=4, ensure_ascii=False)
完整Baseline代码下载:https://www.modelscope.cn/datasets/Datawhale/AI_Camp5_baseline_CV.git
apt install git-lfs
git lfs install
git clone https://www.modelscope.cn/datasets/Datawhale/AI_Camp5_baseline_CV.git
三、提分tips
- 适当增加epoch和batch参数,注意不要过拟合
- 微调超参数
- 数据集增强