运行task1baseline
![](https://i-blog.csdnimg.cn/direct/d71a51758e9a4c1a94969b7be9519c1d.png)
![](https://i-blog.csdnimg.cn/direct/55aa36a1cdd3480da2c42293daf85958.png)
如上图左边是运行后生成的文件,第一行代码是下载相关python三方库 opencv-python、pandas、matplotlib、ultralytics
第二行代码是导入相关库
第三行代码是下载压缩文件zip、解压文件unzip和unar,
下图是下载虚拟机的相关文件
然后是下载训练集与测试集的数据资料共计2.8G
![](https://i-blog.csdnimg.cn/direct/c1e160958d234178985d4160d70a98ec.png)
数据读取
train_anno = json.load(open('训练集(有标注第一批)/标注/45.json', encoding='utf-8')) #加载一个JSON文件,并访问该文件中的数据
train_anno[0], len(train_anno) # 访问 train_anno 中的第一个元素,使用 len() 函数计算 train_anno 的长度。对于列表,返回元素的数量;对于字典,返回键值对的数量
![](https://i-blog.csdnimg.cn/direct/5342819a880e43eaa70beca656a7ab76.png)
pd.read_json('训练集(有标注第一批)/标注/45.json') # 使用了 pandas 库中的 read_json 方法来读取一个 JSON 文件
video_path = '训练集(有标注第一批)/视频/45.mp4'
cap = cv2.VideoCapture(video_path) #cv2.VideoCapture 方法创建一个 VideoCapture 对象,并将视频文件路径作为参数传递给构造函数。cap 对象用于与视频文件进行交互,读取视频帧。
while True: # 循环语句
# 读取下一帧
ret, frame = cap.read() # 调用 cap.read() 方法读取视频中的下一帧。cap.read() 方法返回一个元组,第一个元素 ret 是布尔值,表示读取是否成功;第二个元素 frame 是读取到的图像帧,通常是一个 NumPy 数组。
if not ret: # 检查 ret 的值。如果 ret 为 False,则表示已经到达视频的末尾,无法再读取新的帧。
break # 如果 ret 为 False,则执行 break 语句,跳出 while 循环。
break # 这个 break 语句会立即终止循环,无论 ret 的值是什么。这意味着在读取第一帧之后就会退出循环
frame.shape #视频帧是 1080x1920 的彩色图像
# (1080, 1920, 3)
# 获取视频文件中的总帧数,并将其转换为整数类型
int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
# 读取到frame
bbox = [746, 494, 988, 786] # 这四个值分别代表矩形框的左上角坐标 (746, 494) 和右下角坐标 (988, 786)
# pt1 和 pt2 分别定义了矩形框的两个对角点坐标。
pt1 = (bbox[0], bbox[1]) # pt1 是左上角的坐标 (746, 494)。
pt2 = (bbox[2], bbox[3]) # pt2 是右下角的坐标 (988, 786)
color = (0, 255, 0) # 定义了绘制矩形框的颜色,绿色
thickness = 2 # 定义了矩形框边界的线条粗细
cv2.rectangle(frame, pt1, pt2, color, thickness) # cv2.rectangle 方法在图像 frame 上绘制一个矩形框
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # cv2.cvtColor 方法将图像 frame 从 BGR 色彩空间转换为 RGB 色彩空间
# OpenCV 默认使用 BGR 色彩空间,而 Matplotlib 默认使用 RGB 色彩空间
plt.imshow(frame) # 使用 Matplotlib 的 imshow 方法显示图像 frame
数据转换
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: 违法经营
''')
# 对 train_annos 和 train_videos 两个列表中的元素进行排序
train_annos = glob.glob('训练集(有标注第一批)/标注/*.json')
train_videos = glob.glob('训练集(有标注第一批)/视频/*.mp4')
train_annos.sort(); train_videos.sort();
category_labels = ["非机动车违停", "机动车违停", "垃圾桶满溢", "违法经营"]
for anno_path, video_path in zip(train_annos[:5], train_videos[:5]):
print(video_path)
anno_df = pd.read_json(anno_path) # pandas 库中的 read_json 函数读取标注文件(JSON 格式),并将数据加载到一个 DataFrame 中,方便后续处理。
cap = cv2.VideoCapture(video_path) # 使用 cv2.VideoCapture 创建一个视频捕获对象,用于读取视频文件。
frame_idx = 0 # 初始化一个变量 frame_idx 用于记录当前帧的索引。
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] # 从标注 DataFrame 中筛选出当前帧的标注信息。假设标注文件中的 frame_id 列包含了对应帧的索引。
# 将当前帧保存为图片文件。文件名由标注文件名(去掉 .json 扩展名)和帧索引组成,保存在 ./yolo-dataset/train/ 目录下
cv2.imwrite('./yolo-dataset/train/' + anno_path.split('/')[-1][:-5] + '_' + str(frame_idx) + '.jpg', frame)
# 如果当前帧有标注信息,则打开一个标签文件用于写入。文件名与图片文件名相同,但扩展名为 .txt
if len(frame_anno) != 0:
with open('./yolo-dataset/train/' + anno_path.split('/')[-1][:-5] + '_' + str(frame_idx) + '.txt', 'w') as up:
# 遍历当前帧的所有标注信息,将标注框的坐标转换为 YOLO 格式所需的归一化坐标,并写入标签文件。
for category, bbox in zip(frame_anno['category'].values, frame_anno['bbox'].values):
# category_idx 为类别索引,通过查找 category_labels 列表获得。
category_idx = category_labels.index(category)
# bbox 包含标注框的四个坐标点,通过计算获得中心点坐标、宽度和高度。
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
# 如果 x_center 大于 1,则打印 bbox 用于调试
if x_center > 1:
print(bbox)
# 将转换后的坐标写入标签文件
up.write(f'{category_idx} {x_center} {y_center} {width} {height}\n')
# 更新帧索引,以便读取下一帧
frame_idx += 1
然后下载YOLO的yolov8n.pt和Arial.ttf
# 导入os模块
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
# 导入 Python 的 warnings 模块
import warnings
warnings.filterwarnings('ignore')
# 从 ultralytics 库中导入 YOLO 类
from ultralytics import YOLO
# 创建一个 YOLO 模型实例,加载预训练的 yolov8n.pt 模型
model = YOLO("yolov8n.pt")
# 使用 model.train() 方法来训练模型
results = model.train(data="yolo-dataset/yolo.yaml", epochs=2, imgsz=1080, batch=16)
category_labels = ["非机动车违停", "机动车违停", "垃圾桶满溢", "违法经营"]
# 检查当前目录下是否存在名为 'result/' 的目录.如果不存在则创建一个名为 'result/' 的目录
if not os.path.exists('result/'):
os.mkdir('result')
from ultralytics import YOLO
model = YOLO("runs/detect/train/weights/best.pt")
import glob
for path in glob.glob('测试集/*.mp4'):
# 初始化一个空列表 submit_json,用于存储每个视频文件的检测结果。
submit_json = []
# 使用 model 对视频文件 path 进行目标检测
# 设置置信度阈值为 0.05,低于这个阈值的检测结果将被过滤掉
# 设置是否在控制台输出详细的检测信息,默认为 False。
results = model(path, conf=0.05, imgsz=1080, verbose=False)
# 使用 enumerate 函数遍历检测结果中的每一帧,idx 是当前帧的索引,result 是该帧的检测结果
for idx, result in enumerate(results):
boxes = result.boxes # 包含边界框信息的对象
masks = result.masks # 包含分割掩码信息的对象
keypoints = result.keypoints # 包含关键点信息的对象
probs = result.probs # 包含分类概率信息的对象
obb = result.obb # 包含定向边界框信息的对象
# 检查 boxes.cls 的长度,如果为 0,则表示当前帧没有检测到任何目标,跳过当前帧继续处理下一个帧。
if len(boxes.cls) == 0:
continue
# 提取边界框的坐标信息 xywh、类别索引 cls 和置信度 conf。
xywh = boxes.xyxy.data.cpu().numpy().round() # xywh 是一个包含边界框坐标的 NumPy 数组。
cls = boxes.cls.data.cpu().numpy().round() # cls 是一个包含类别索引的 NumPy 数组。
conf = boxes.conf.data.cpu().numpy() # conf 是一个包含置信度的 NumPy 数组。
# 遍历每个检测结果,ci 是类别索引,xy 是边界框坐标,confi 是置信度。
for i, (ci, xy, confi) in enumerate(zip(cls, xywh, conf)):
# 检测结果以字典的形式添加到 submit_json 列表中。
submit_json.append(
{
'frame_id': idx, # 当前帧的索引。
'event_id': i+1, # 当前检测事件的 ID,从 1 开始计数。
'category': category_labels[int(ci)], # 类别名称,通过 category_labels 列表获取。
'bbox': list([int(x) for x in xy]), # 边界框坐标,转换为整数。
"confidence": float(confi) # 置信度,转换为浮点数。
}
)
# 将 submit_json 列表写入 JSON 文件。
# path.split('/')[-1][:-4]:获取视频文件名(去掉 .mp4 扩展名)。
# ./result/:指定保存结果的目录。
with open('./result/' + path.split('/')[-1][:-4] + '.json', 'w', encoding='utf-8') as up:
# 将列表写入 JSON 文件,indent=4 用于美化输出,ensure_ascii=False 用于保留非 ASCII 字符。
json.dump(submit_json, up, indent=4, ensure_ascii=False)
最后就是保存结果并压缩result到result.zip,然后下载到本地
![](https://i-blog.csdnimg.cn/direct/38bd32660dab4bf59b502bc1c7b74b05.png)
提分方法
这个本人不确定这个方法是不是正确的哈
就是可以修改在第十六段代码的,yolov8n.pt的模型,或者修改epochs=2的参数
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=2, imgsz=1080, batch=16)
将改为epochs=4后的分数提升很大,有0.055269507247802
或者训练时训练所有的训练集数据。