Datawhale AI 夏令营---task1笔记
Datawhale是一个专注于数据科学与AI领域的开源组织,汇集了众多领域院校和知名企业的优秀学习者,聚合了一群有开源精神和探索精神的团队成员。 本期(第五期)是本次夏令营活动的最后一期,本次的活动是伴随着“2024“大运河杯”数据开发应用创新大赛——城市治理”活动一起进行开展进行的。
一、赛题内容
1、赛题目标
利用图像处理和计算机视觉技术 开发一套智能识别系统,自动检测和分类摄像头捕获的视频中,城市管理中的违规行为
2、社会价值
通过对摄像头捕获的视频进行分析,自动准确识别违规行为,并及时向管理部门发出告警,以实现更高效的城市管理。
3、赛事资源分析
初赛提供城管视频监控数据与对应违规行为标注。违规行为包括垃圾桶满溢、机动车违停、非机动车违停等。视频数据为mp4格式,标注文件为json格式,每个视频对应一个json文件。
- frame_id:违规行为出现的帧编号
- event_id:违规行为ID
- category:违规行为类别
- bbox:检测到的违规行为矩形框的坐标,[xmin,ymin,xmax,ymax]形式
4、评分规则
使用F1score、MOTA指标来评估模型预测结果。
对每个json文件得到两个指标的加权求和,最终得分为所有文件得分取均值。
注1:若真实目标框与预测框IOU大于0.5,则判定目标正确识别。若MOTA指标为负,则该类别精度得分为0。
注2:若该视频中没有某个类别的目标,则此类别计算均值时,忽略该视频。
二、baseline代码解析
按照手册指示,在终端中执行下面代码,从而得到数据集和代码等文件内容
apt install git-lfs
git lfs install
git clone https://www.modelscope.cn/datasets/Datawhale/AI_Camp5_baseline_CV.git
baseline解析如下:
1、导入所需要的库
import os, sys # 导入操作系统和系统级操作库
import cv2, glob, json # 导入计算机视觉、文件路径匹配和JSON处理库
import numpy as np # 导入数值计算库
import pandas as pd # 导入数据处理和分析库
import matplotlib.pyplot as plt # 导入数据可视化库
2、安装必须的解压工具
!apt install zip unzip -y # 安装zip和unzip用于处理压缩文件
!apt install unar -y # 安装unar用于解压.zip文件
3、 下载和解压数据集
!wget "https://comp-public-prod.obs.cn-east-3.myhuaweicloud.com/dataset/2024/%E8%AE%AD%E7%BB%83%E9%9B%86%28%E6%9C%89%E6%A0%87%E6%B3%A8%E7%AC%AC%E4%B8%80%E6%89%B9%29.zip?AccessKeyId=583AINLNMLDRFK7CC1YM&Expires=1739168844&Signature=9iONBSJORCS8UNr2m/VZnc7yYno%3D" -O 训练集\(有标注第一批\).zip # 下载训练集压缩文件
!unar -q 训练集\(有标注第一批\).zip # 使用“unar”解压训练集文件
4、下载和解压测试集
!wget "https://comp-public-prod.obs.cn-east-3.myhuaweicloud.com/dataset/2024/%E6%B5%8B%E8%AF%95%E9%9B%86.zip?AccessKeyId=583AINLNMLDRFK7CC1YM&Expires=1739168909&Signature=CRsB54VqOtrzIdUHC3ay0l2ZGNw%3D" -O 测试集.zip # 下载测试集压缩文件
!unar -q 测试集.zip # 使用“unar”解压测试集文件
5、加载和查看标注文件
- 加载一个标注文件
45.json
,读取JSON格式的数据。 - 输出标注数据的第一个条目和标注条目的总数量。
train_anno = json.load(open('训练集(有标注第一批)/标注/45.json', encoding='utf-8')) # 加载训练集中的标注文件
train_anno[0], len(train_anno) # 输出标注数据的第一个条目和总数
6、读取并查看标注文件
pd.read_json('训练集(有标注第一批)/标注/45.json') # 使用Pandas读取标注文件,以表格形式查看
7、记载并读取视频帧
video_path = '训练集(有标注第一批)/视频/45.mp4' # 指定视频文件路径
cap = cv2.VideoCapture(video_path) # 打开视频文件
while True:
ret, frame = cap.read() # 读取视频的第一帧
if not ret:
break # 如果没有读取到帧则跳出循环
break # 只读取一帧后跳出循环
8、查看视频帧的尺寸
frame.shape # 查看视频帧的尺寸(高度、宽度、通道数)
9、获取视频的总帧数
int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 获取视频的总帧数
10、在帧上绘制边界框
bbox = [746, 494, 988, 786] # 定义边界框的坐标
pt1 = (bbox[0], bbox[1]) # 边界框左上角坐标
pt2 = (bbox[2], bbox[3]) # 边界框右下角坐标
color = (0, 255, 0) # 颜色为绿色
thickness = 2 # 线条粗细为2
cv2.rectangle(frame, pt1, pt2, color, thickness) # 在帧上绘制边界框
11、显示处理后的帧
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 将帧从BGR颜色空间转换为RGB
plt.imshow(frame) # 使用matplotlib显示处理后的帧
12、创建用于YOLO数据集的文件夹结构
if not os.path.exists('yolo-dataset/'): # 如果目录不存在则创建yolo-dataset文件夹
os.mkdir('yolo-dataset/')
if not os.path.exists('yolo-dataset/train'): # 如果目录不存在则创建train文件夹
os.mkdir('yolo-dataset/train')
if not os.path.exists('yolo-dataset/val'): # 如果目录不存在则创建val文件夹
os.mkdir('yolo-dataset/val')
13、生成YOLO配置文件
dir_path = os.path.abspath('./') + '/' # 获取当前目录的绝对路径
# 生成YOLO配置文件yolo.yaml
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: 非机动车违停 # 类别0
1: 机动车违停 # 类别1
2: 垃圾桶满溢 # 类别2
3: 违法经营 # 类别3
''')
14、获取训练数据的文件路径列表
train_annos = glob.glob('训练集(有标注第一批)/标注/*.json') # 获取所有标注文件的路径
train_videos = glob.glob('训练集(有标注第一批)/视频/*.mp4') # 获取所有视频文件的路径
train_annos.sort(); train_videos.sort() # 对标注文件和视频文件路径进行排序
15、定义类别标签
category_labels = ["非机动车违停", "机动车违停", "垃圾桶满溢", "违法经营"]
16、生成YOLO训练集
# 生成YOLO训练集
for anno_path, video_path in zip(train_annos[:5], train_videos[:5]): # 遍历前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) # 获取类别的索引
x_min, y_min, x_max, y_max = bbox # 解压边界框坐标
x_center = (x_min + x_max) / 2 / img_width # 计算中心点x坐标
y_center = (y_min + y_max) / 2 / img_height # 计算中心点y坐标
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') # 将标注信息写入txt文件
frame_idx += 1 # 处理下一帧
17、生成YOLO验证集
# 生成YOLO验证集
for anno_path, video_path in zip(train_annos[-3:], train_videos[-3:]): # 遍历最后3个标注文件和视频文件
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/val/' + anno_path.split('/')[-1][:-5] + '_' + str(frame_idx) + '.jpg', frame) # 保存当前帧图像
if len(frame_anno) != 0: # 如果当前帧有标注信息
with open('./yolo-dataset/val/' + 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 # 解压边界框坐标
x_center = (x_min + x_max) / 2 / img_width # 计算中心点x坐标
y_center = (y_min + y_max) / 2 / img_height # 计算中心点y坐标
width = (x_max - x_min) / img_width # 计算边界框宽度
height = (y_max - y_min) / img_height # 计算边界框高度
up.write(f'{category_idx} {x_center} {y_center} {width} {height}\n') # 将标注信息写入txt文件
frame_idx += 1 # 处理下一帧
18、下载YOLOv8模型权重
!wget http://mirror.coggle.club/yolo/yolov8n-v8.2.0.pt -O yolov8n.pt # 下载YOLOv8预训练模型权重
19、相关设置(设置字体,设置CUDA设备,忽略警告信息)
!mkdir -p ~/.config/Ultralytics/ # 创建Ultralytics配置文件夹
!wget http://mirror.coggle.club/yolo/Arial.ttf -O ~/.config/Ultralytics/Arial.ttf # 下载Arial字体文件到Ultralytics目录
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0" # 设置使用的CUDA设备(GPU)
import warnings
warnings.filterwarnings('ignore') # 忽略警告信息
20、训练YOLO模型
使用下载的YOLOv8模型权重,基于生成的训练集数据进行模型训练,训练2个epoch,图像输入尺寸为1080,批量大小为16。
from ultralytics import YOLO
model = YOLO("yolov8n.pt") # 加载YOLOv8模型
results = model.train(data="yolo-dataset/yolo.yaml", epochs=2, imgsz=1080, batch=16) # 训练模型,指定数据集、训练轮数、输入尺寸和批量大小
21、创建结果保存文件夹
category_labels = ["非机动车违停", "机动车违停", "垃圾桶满溢", "违法经营"] # 再次定义类别标签
if not os.path.exists('result/'): # 如果result文件夹不存在则创建
os.mkdir('result')
22、使用训练好的YOLO模型对测试集视频进行目标检测
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 # 获取边界框
masks = result.masks # 获取分割掩码
keypoints = result.keypoints # 获取关键点
probs = result.probs # 获取分类概率
obb = result.obb # 获取定向边界框
if len(boxes.cls) == 0:
continue # 如果没有检测到任何物体,跳过当前帧
xywh = boxes.xyxy.data.cpu().numpy().round() # 获取边界框坐标并转换为numpy数组
cls = boxes.cls.data.cpu().numpy().round() # 获取类别索引并转换为numpy数组
conf = boxes.conf.data.cpu().numpy() # 获取置信度并转换为numpy数组
for i, (ci, xy, confi) in enumerate(zip(cls, xywh, conf)): # 遍历每个检测到的物体
submit_json.append(
{
'frame_id': idx, # 帧ID
'event_id': i+1, # 事件ID
'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文件
json.dump(submit_json, up, indent=4, ensure_ascii=False)
23、清理和压缩结果文件
!\rm result/.ipynb_checkpoints/ -rf # 删除不必要的文件夹
!\rm result.zip # 删除旧的压缩文件
!zip -r result.zip result/ # 将结果文件夹压缩成ZIP文件
24、总结概括:
baseline的代码实现了一个完整的目标检测流程,从环境准备、数据加载与预处理、到模型训练与推理,以及最终的结果保存。首先,代码安装了必要的工具,并从指定的 URL 下载了训练集和测试集的压缩文件,随后解压这些文件以便使用。接着,代码通过
cv2
读取视频文件并提取视频帧,同时使用
pandas
读取 JSON 格式的标注文件,从中提取出目标的类别和边界框等信息。
在数据预处理阶段,代码将视频帧保存为图像文件,并基于标注信息生成与之对应的 YOLO 格式标注文件。这些图像和标注文件被分别组织并保存到训练集和验证集的目录中,为模型训练做准备。随后,代码下载了 YOLOv8 的预训练模型权重,并使用准备好的数据集进行模型训练。训练过程生成了经过优化的模型权重文件。
训练完成后,代码使用训练好的 YOLO 模型对测试集中的视频进行推理,对每一帧进行目标检测,并将检测结果(包括目标类别、边界框位置、置信度等)保存为 JSON 文件。最后,代码对生成的检测结果进行整理,删除不必要的文件,并将结果打包为一个压缩文件,便于后续的处理和提交。整个流程自成一体,涵盖了从数据获取到结果输出的完整过程,适用于YOLOv8的目标检测任务。
三、初次测试结果
四、进阶尝试
版权归原作者 小萌新加速中 所有, 如有侵权,请联系我们删除。