(4-9)目标跟踪:基于YOLOv8深度学习的目标检测(1)

本文详细介绍了如何使用YOLOv8模型进行汽车目标检测和跟踪,包括数据集准备、模型配置、目标检测和跟踪的实现步骤,以及数据集划分和YOLO格式转换的过程。
摘要由CSDN通过智能技术生成

4.9  基于深度学习的目标检测

使用YOLO、卷积神经网络(CNN)和循环神经网络(RNN)等机器学习或狠毒学习技术进行目标检测和跟踪。这些模型可以学习目标的特征,并在视频帧序列中进行目标跟踪。

实例4-8:基于YOLOv8的汽车追踪系统(codes/2/yolov8-for-car-tracking.ipynb

4.9.1  项目介绍

本项目是一个基于 YOLO 模型的目标检测和目标跟踪系统,本项目结合了目标检测和目标跟踪的任务,通过 YOLO 模型实现了对车辆的检测和跟踪。本项目使用的 YOLOv8 模型是YOLO 模型中的一版本,是一个常用的目标检测模型,通过训练和调整参数,可以适应不同的数据集和任务。整个流程展示了从数据准备到模型训练、推断和结果分析的完整项目流程。

本项目的主要实现步骤和功能如下所示:

  1. 数据集准备:项目开始时,使用了一个数据集,该数据集包含了视频中的车辆,并提供了每个帧中车辆的位置和类别标签。数据集通过解析 XML 格式的注释文件进行读取,包括每个帧的文件路径、宽度、高度以及每个车辆框的坐标和标签信息。
  2. 数据集转换为 YOLO 格式:为了适应 YOLO 模型的训练需求,数据集被转换为 YOLO 格式。这包括将车辆的位置信息转换为 YOLO 框的格式,并将数据集划分为训练、验证和测试集。
  3. 模型训练:使用 YOLO 模型进行目标检测和目标跟踪。项目中使用了 YOLOv8 模型,通过加载预训练权重进行模型初始化,并在准备好的数据集上进行了训练。模型训练的参数包括训练轮数、图像大小、批次大小等。
  4. 目标检测:使用训练好的 YOLO 模型对测试集中的图像进行目标检测。检测结果包括边界框和类别标签,将结果绘制在图像上。
  5. 目标跟踪:在整个测试集上使用 YOLO 模型进行目标跟踪。通过跟踪算法,每个目标在不同帧上被唯一标识,并在每一帧上进行目标跟踪。
  6. 后处理和结果分析:对跟踪结果进行后处理,确保每个跟踪ID被分配为一个最常见的类别。最后,通过在图像上绘制跟踪结果,进行结果可视化。

4.9.2  具体实现

实例文件yolov8-for-car-tracking.ipynb的具体实现流程如下所示。

(1)设置目标检测项目的配置参数,这些配置参数用于定义训练和评估目标检测模型的设置。具体实现代码如下所示。

# 数据集目录
DATASET_DIR = "input/cars-video-object-tracking"

# 验证集和测试集的百分比
VAL_PERCENT, TEST_PERCENT = 0.1, 0.05  # 根据这些值的乘以100,将数据集划分为训练、验证和测试集。TRAIN_PERCENT = 1 - (VAL_PERCENT + TEST_PERCENT)

# YOLO格式的数据集保存目录
YOLO_DATASET_DIR = "working/yolo_dataset"  # 用于保存以YOLO格式存储的数据集的目录

# YOLO模型的检查点名称
YOLO_CHECKPOINT = "yolov8s"

# 训练的轮数
EPOCHS = 8  # 训练轮数,一轮是对整个数据集的一次完整遍历。使用的轮数取决于数据集的大小。太多轮可能导致过拟合,可以通过监控训练过程中的验证损失来检测。太少轮可能导致欠拟合,可以通过损失的持续"急剧"下降来识别。

# 用于前向传播的图像大小
IMGSZ = 640  # 用于前向传播的图像的大小。较大的大小意味着对小细节的更多关注,因此在对象很小的图像中有更好的质量。大图像大小在训练期间需要大量计算资源。

# 每次迭代在一个GPU上的训练批次大小
TRAIN_BATCH_SIZE = 16  # 每次迭代在一个GPU上的训练批次大小。最好是2的幂次方(2、4、8)

# 名义批次的大小(由训练批次大小划分)
NOMINAL_BATCH_SIZE = 64  # 名义批次的大小(通过训练批次大小进行划分)

(2)定义两个字典,用于将目标检测任务中的类别标签(label)映射到整数标识(id)以及反向映射。这样的映射通常用于将类别标签转换为模型可以处理的格式,或者在评估模型时将模型输出的整数标识转换为易读的类别标签。

label2id = {"car": 0, "minivan": 1}
id2label = {v: k for k, v in label2id.items()}

对上述代码的具体说明如下:

  1. label2id:这是一个字典,将目标检测任务中的类别标签映射到整数标识。在这个例子中,"car" 对应的整数标识是 0,"minivan" 对应的整数标识是 1。这种映射通常在训练和评估模型时用于处理类别标签。
  2. id2label:这是 label2id 字典的反向映射。通过使用字典推导式,它将整数标识映射回原始的类别标签。例如,0 对应于 "car",1 对应于 "minivan"。这对于在模型的输出中将整数标识转换回类别标签是很有用的。

(3)解析目标检测数据集的注释文件(assumed to be in XML format),并将注释信息存储到一个字典中。

# 初始化一个空的字典用于存储注释信息
data = dict()

# 使用ElementTree库解析XML格式的注释文件
annotations = etree.parse(opj(DATASET_DIR, "annotations.xml")).getroot()

# 遍历所有的图像标注
for image in annotations.findall('image'):
    # 获取图像文件路径,并将文件扩展名改为大写(可能是为了匹配文件扩展名的大小写)
    filepath = opj(DATASET_DIR, image.attrib["name"]).replace(".png", ".PNG")
    
    # 获取图像的宽度和高度
    w_img, h_img = float(image.attrib['width']), float(image.attrib['height'])

    # 初始化一个列表用于存储每个图像的目标框信息
    boxes = []
    
    # 遍历图像中的每个目标框
    for box in image.findall('box'):
        # 获取目标框的标签(类别)
        label = box.attrib['label']
        
        # 计算目标框的归一化坐标(相对于图像宽度和高度)
        xtl, ytl = float(box.attrib["xtl"]) / w_img, float(box.attrib["ytl"]) / h_img
        xbr, ybr = float(box.attrib["xbr"]) / w_img, float(box.attrib["ybr"]) / h_img
        
        # 计算目标框的中心坐标和宽度、高度(YOLO格式)
        xc, yc = (xbr + xtl) / 2, (ybr + ytl) / 2
        yolo_box = [xc, yc, xbr - xtl, ybr - ytl]
        
        # 将目标框的信息存储为列表,并添加到当前图像的目标框列表中
        box_data = [label2id[label]] + yolo_box
        boxes.append(box_data)

    # 将当前图像的注释信息存储到数据字典中
    data[filepath] = boxes

(4)将数据集划分为训练集、验证集和测试集,划分过程是根据预先定义的百分比进行的,且考虑到了数据集中的时间序列关系。这样的划分方式可以根据时间序列将验证集和测试集选择为顺序帧,以更好地反映实际使用情境。

# 获取所有图像文件路径
paths = list(data.keys())

# 计算训练集的划分点
train_split = int((1 - (VAL_PERCENT + TEST_PERCENT)) * len(paths))

# 划分训练集和非训练集
train_paths, nontrain_paths = paths[:train_split], paths[train_split:]

# 计算验证集和测试集的划分点
nontrain_split = int((VAL_PERCENT / (VAL_PERCENT + TEST_PERCENT)) * len(nontrain_paths))

# 划分验证集和测试集
eval_paths, test_paths = nontrain_paths[:nontrain_split], nontrain_paths[nontrain_split:]

(5)打印输出训练集、验证集和测试集的数量,具体实现代码如下所示。

len(train_paths), len(eval_paths), len(test_paths)

执行后可以查看数据集在划分后的规模大小:

(255, 30, 16)

(6)将数据集的图像和相应的注释保存到 YOLO 数据集的文件夹中,这样将数据集整理为符合 YOLO 模型训练所需的文件结构,包括图像和相应的标签。

# 遍历训练集、验证集和测试集
for data_type, paths in [("train", train_paths), ("val", eval_paths), ("test", test_paths)]:
    # 定义图像和注释保存的路径
    images_path = opj(YOLO_DATASET_DIR, "images", data_type)
    annotations_path = opj(YOLO_DATASET_DIR, "labels", data_type)
    
    # 创建保存图像和注释的目录(如果不存在)
    os.makedirs(images_path, exist_ok=True)
    os.makedirs(annotations_path, exist_ok=True)
    
    # 遍历每个图像路径
    for path in tqdm(paths):
        # 获取图像的目标框信息
        boxes = data[path]
        
        # 获取图像文件名
        name = path.replace("\\", "/").split("/")[-1]
        
        # 将目标框信息转换为 YOLO 格式的注释内容
        annotation_content = "\n".join(map(lambda box: " ".join(map(str, box)), boxes))
        
        # 复制图像到相应的目录
        shutil.copy(path, opj(images_path, name))
        
        # 将注释内容写入对应的文本文件
        with open(opj(annotations_path, name.split(".")[0] + ".txt"), "w") as f:
            f.write(annotation_content)

执行后会输出:

100%
255/255 [00:14<00:00, 14.10it/s]
100%
30/30 [00:01<00:00, 17.18it/s]
100%
16/16 [00:01<00:00, 13.42it/s]

(7)创建 YOLO 模型训练所需的 dataset.yaml 配置文件,该文件包含了数据集的路径、训练、验证和测试集的子目录,以及类别的名称。

# 构建类别名称的字符串
names_content = "\n".join([f"  {label_id}: {label}" for label, label_id in label2id.items()])

# 构建 dataset.yaml 文件的内容
dataset_content = f"""
path: "{YOLO_DATASET_DIR}/"
train: "images/train"
val: "images/val"
test: "images/test"
names:
{names_content}
"""

# 将配置内容写入 dataset.yaml 文件
with open(opj(YOLO_DATASET_DIR, "dataset.yaml"), "w") as f:
    f.write(dataset_content)

对上述代码的具体说明如下 :

  1. names_content:通过遍历类别标签的字典 label2id,创建了一个字符串,其中包含了每个类别的名称和对应的整数标识。
  2. dataset_content:构建了 dataset.yaml 文件的内容,包括数据集的路径、训练、验证和测试集的子目录,以及类别名称。
  3. with open(...) 块:将配置内容写入 dataset.yaml 文件。

配置文件dataset.yaml是为 YOLO 模型提供数据集信息的配置文件,以便在训练时正确加载数据。

(8)根据指定的百分比将数据集分为训练集、验证集和测试集。划分过程考虑到了数据集中帧的时序关系。

# 获取所有图像文件路径
paths = list(data.keys())

# 计算训练集的划分点
train_split = int((1 - (VAL_PERCENT + TEST_PERCENT)) * len(paths))

# 划分训练集和非训练集
train_paths, nontrain_paths = paths[:train_split], paths[train_split:]

# 计算验证集和测试集的划分点
nontrain_split = int((VAL_PERCENT / (VAL_PERCENT + TEST_PERCENT)) * len(nontrain_paths))

# 划分验证集和测试集
eval_paths, test_paths = nontrain_paths[:nontrain_split], nontrain_paths[nontrain_split:]

(9)打印输出训练集、验证集和测试集的数量,具体实现代码如下所示。

len(train_paths), len(eval_paths), len(test_paths)

执行后会输出:

(255, 30, 16)

(10)将数据集的图像和相应的注释保存到 YOLO 数据集的文件夹中,目的是将数据集整理为符合 YOLO 模型训练所需的文件结构,包括图像和相应的标签。

# 遍历训练集、验证集和测试集
for data_type, paths in [("train", train_paths), ("val", eval_paths), ("test", test_paths)]:
    # 定义图像和注释保存的路径
    images_path = opj(YOLO_DATASET_DIR, "images", data_type)
    annotations_path = opj(YOLO_DATASET_DIR, "labels", data_type)
    
    # 创建保存图像和注释的目录(如果不存在)
    os.makedirs(images_path, exist_ok=True)
    os.makedirs(annotations_path, exist_ok=True)
    
    # 遍历每个图像路径
    for path in tqdm(paths):
        # 获取图像的目标框信息
        boxes = data[path]
        
        # 获取图像文件名
        name = path.replace("\\", "/").split("/")[-1]
        
        # 将目标框信息转换为 YOLO 格式的注释内容
        annotation_content = "\n".join(map(lambda box: " ".join(map(str, box)), boxes))
        
        # 复制图像到相应的目录
        shutil.copy(path, opj(images_path, name))
        
        # 将注释内容写入对应的文本文件
        with open(opj(annotations_path, name.split(".")[0] + ".txt"), "w") as f:
            f.write(annotation_content)

对上述代码的具体说明如下:

  1. data_type表示当前是训练集、验证集还是测试集。
  2. images_path 和 annotations_path用于定义保存图像和注释的文件夹路径。
  3. 首先,创建对应的文件夹(如果不存在)。然后遍历每个图像路径,获取图像的目标框信息。
  4. 最后将图像复制到相应的目录中,将目标框信息保存为 YOLO 格式的注释文件(.txt 文件)。

执行后会输出:

100%
255/255 [00:14<00:00, 14.10it/s]
100%
30/30 [00:01<00:00, 17.18it/s]
100%
16/16 [00:01<00:00, 13.42it/s]

(11)创建 YOLO 模型训练所需的 dataset.yaml 配置文件,该文件包含了数据集的路径、训练、验证和测试集的子目录,以及类别的名称。

# 构建类别名称的字符串
names_content = "\n".join([f"  {label_id}: {label}" for label, label_id in label2id.items()])

# 构建 dataset.yaml 文件的内容
dataset_content = f"""
path: "{YOLO_DATASET_DIR}/"
train: "images/train"
val: "images/val"
test: "images/test"
names:
{names_content}
"""

# 将配置内容写入 dataset.yaml 文件
with open(opj(YOLO_DATASET_DIR, "dataset.yaml"), "w") as f:
    f.write(dataset_content)

未完待续

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值