YOLOv8 目标跟踪(OTB100 数据集)

本贴最后更新于 327 天前,其中的信息可能已经渤澥桑田

前言

基于 OTB100 数据集做目标跟踪,提供评价指标

chatGPT 写的代码,难看但是能用

参考:单目标跟踪数据集 | J. Xu (xujinzh.github.io)[YOLOv8] - YOLO 数据集格式介绍和案例-CSDN 博客

数据

YOLOv8

地址

image

YOLO 数据集的格式主要包括以下几部分(注意:除扩展名外,标注文件的名称必须和图像的名称保持一致哦):

  • 图像文件: 这是数据集中的图像文件,通常是 jpg 或 png 格式。

  • 标注文件: 这是一个文本文件,包含了每张图像中目标对象的类别和位置信息

    主要包含了以下内容:

    • 每个目标对象的类别编号

    • 目标对象在图像中的中心位置 (x,y)

    • 目标对象的宽度和高度 (w,h)

      image

      1) 列 1 - 目标类别 id , 列 2 - 目标中心位置 x, 列 3 - 目标中心位置 y, 列 4 - 目标宽度 w,列 5 - 目标高度 h。

      2)x,y,w,h 是小于 1 的浮点数,因为是经过对图像进行了归一化处理得到的值,也就是目标的真实的 x,w 值除以图像的宽度,y,h 除以图像的高度。

  • 类别文件: 这是一个文本文件,包含了数据集中所有目标对象的类别信息。

    备注:一行代表一个类别,行号代表类别 id,比如 normal 是类别名称,它在第四行,那么它的类别 id 为 3(索引从 0 开始),比如上面的显示的图像的标注文件,有 2 个类别为 normal 的目标。

    image

OTB100

image

OTB 数据集是单目标跟踪最早数据集。分为 OTB-2013(51 个视频)、OTB-2015 (在 OTB-2013 上增加视频,共 98 个视频,又名 OTB-100),其中 OTB-100 前 49 个视频又名 OTB-50. 虽然 OTB-100 只有 98 个视频,但是,其中两个视频 Skating2 和 Jogging 分别针对两个目标进行标注,可分别看作 2 个视频。因此,称为 OTB-100. 其中 Skating2 在 OTB-50 中,因此 OTB-50 事实上也包含 50 个标注视频。

官方数据集下载地址:OTB Dataset | Papers With Code

类别:10(OTB-2013), 16(OTB-2015)

图像:OTB-50 (官网前 49 个视频,其中 Skating2 为 2 个);OTB-100 (TB-50 加上官网上后 49 个视频,其中 Jogging 为 2 个)

大小:1.3GB(OTB-50)、2.6GB(OTB-100)

注释:groundtruth_rect.txt 包含每一帧矩形边界框位置,注意在大多数序列中,第一行对应于第一帧,最后一行对应于最后一帧,除了序列 David(300:770), Football1(1:74), Freeman3(1:460), Freeman4(1:283). 官网上还有每个视频的标注目标属性,分为 IV(Illumination Variation), SV(Scale Variation), OCC(Occlusion), DEF(Deformation), MB(Motion Blur), FM(Fast Motion), IPR(In-Plane Rotation), OPR(Out-of-Plane Rotation), OV(Out-of-View), BC(Background Clutters), LR(Low Resolution).

预处理(chatgpt)

二者的标注文件内容基本是一致的,只需进行简单的处理

还是很麻烦的,恶心死了

提取类别

import os

def extract_and_save_classes(data_dir, split, output_file):
    classes_set = set()

    split_folder = os.path.join(data_dir, split)

    for class_name in os.listdir(split_folder):
        class_folder = os.path.join(split_folder, class_name)
        if os.path.isdir(class_folder):
            classes_set.add(class_name)

    with open(output_file, 'w') as classes_file:
        for class_name in sorted(classes_set):
            classes_file.write(f"{class_name}\n")

if __name__ == "__main__":
    data_dir = '/yolo_data'
  
    # Process the 'train' split
    train_split = 'train'
    train_output_file = os.path.join(data_dir, 'code', 'train', 'classes.txt')
    if not os.path.exists(train_output_file):
        os.makedirs(os.path.join(data_dir, 'code', 'train'), exist_ok=True)
        extract_and_save_classes(data_dir, train_split, train_output_file)

    # Process the 'test' split
    test_split = 'test'
    test_output_file = os.path.join(data_dir, 'code', 'test', 'classes.txt')
    if not os.path.exists(test_output_file):
        os.makedirs(os.path.join(data_dir, 'code', 'test'), exist_ok=True)
        extract_and_save_classes(data_dir, test_split, test_output_file)

提取图片

import os
import shutil

def rename_and_save_images(data_dir, split, output_folder):
    split_folder = os.path.join(data_dir, split)
    output_split_folder = os.path.join(output_folder)
    print(output_split_folder,split_folder)
    os.makedirs(output_split_folder, exist_ok=True)
    for class_name in os.listdir(split_folder):
        class_folder = os.path.join(split_folder, class_name, 'img')

        for img_name in os.listdir(class_folder):
            img_path = os.path.join(class_folder, img_name)
            output_img_name = f"{class_name}_{img_name}"
            output_img_path = os.path.join(output_split_folder, output_img_name)
            shutil.copy(img_path, output_img_path)

if __name__ == "__main__":
    data_dir = '/yolo_data'
  
    # Process the 'train' split
    train_split = 'train'
    train_output_folder = os.path.join(data_dir, 'code', 'train', 'images')
    os.makedirs(train_output_folder, exist_ok=True)
    rename_and_save_images(data_dir, train_split, train_output_folder)

    # Process the 'test' split
    test_split = 'test'
    test_output_folder = os.path.join(data_dir, 'code', 'test', 'images')
    os.makedirs(test_output_folder, exist_ok=True)
    rename_and_save_images(data_dir, test_split, test_output_folder)

提取标注信息

import os
import shutil
import cv2

def extract_and_save_labels(data_dir, split, output_folder, classes_file):
    split_folder = os.path.join(data_dir, split)
    os.makedirs(output_folder, exist_ok=True)

    with open(classes_file, 'r') as classes_file:
        classes = classes_file.read().splitlines()
        print(classes)

    for class_id, class_name in enumerate(classes):
        print(class_id,class_name)
        class_folder = os.path.join(split_folder, class_name)
        print("class_folder",class_folder)
        txt_files = [f for f in os.listdir(class_folder) if f.endswith('.txt')]
        for i in range(len(txt_files)):
            groundtruth_file_path = os.path.join(class_folder, txt_files[i])
            print("Attempting to open:", groundtruth_file_path)
            with open(groundtruth_file_path, 'r') as groundtruth_file:
                    lines = groundtruth_file.readlines()
            i = 0
            for image_name in os.listdir(class_folder+"/img"):
                if not image_name.endswith(".jpg"):
                    continue
                # 获取图像尺寸
                image_path = os.path.join(class_folder, "img", image_name)
                image = cv2.imread(image_path)
                height, width, _ = image.shape
                if i< len(lines):
                        label_values = f"{class_id} {lines[i].strip()}"
                        i+=1
                        # 归一化处理
                        label_values = label_values.split(" ")
                        try:
                            normalized_values = [
                                int(label_values[0]),  # 目标类别id
                                float(label_values[1].split(",")[0]) / width,  # 目标中心位置x
                                float(label_values[1].split(",")[1]) / height,  # 目标中心位置y
                                float(label_values[1].split(",")[2]) / width,  # 目标宽度w
                                float(label_values[1].split(",")[3]) / height  # 目标高度h
                            ]
                        except:
                            normalized_values = [
                                int(label_values[0]),  # 目标类别id
                                float(label_values[1].split("\t")[0]) / width,  # 目标中心位置x
                                float(label_values[1].split("\t")[1]) / height,  # 目标中心位置y
                                float(label_values[1].split("\t")[2]) / width,  # 目标宽度w
                                float(label_values[1].split("\t")[3]) / height  # 目标高度h
                            ]

                        label_line = " ".join(map(str, normalized_values))
                        # 构建输出文件路径
                        output_file_path = os.path.join(output_folder, f"{class_name}_{image_name.split('.')[0]}.txt")
                        # 检查文件是否存在
                        if os.path.exists(output_file_path):
                            # 追加数据到现有文件
                            with open(output_file_path, 'a') as output_file:
                                output_file.write('\n' + label_line)
                        else:
                            # 创建新文件并保存 label_line 到文件
                            with open(output_file_path, 'w') as output_file:
                                output_file.write(label_line)
    #保存label_line到/yolo_data/code/split/lables/class_name+image_name.split(".")[0]+".txt"
if __name__ == "__main__":
    data_dir = '/yolo_data'
  
    # Process the 'train' split
    train_split = 'train'
    train_output_folder = os.path.join(data_dir, 'code', 'train', 'labels')
    train_classes_file = os.path.join(data_dir, 'code', 'train', 'classes.txt')
    os.makedirs(train_output_folder, exist_ok=True)
    extract_and_save_labels(data_dir, train_split, train_output_folder, train_classes_file)

    # Process the 'test' split
    test_split = 'test'
    test_output_folder = os.path.join(data_dir, 'code', 'test', 'labels')
    test_classes_file = os.path.join(data_dir, 'code', 'test', 'classes.txt')
    os.makedirs(test_output_folder, exist_ok=True)
    extract_and_save_labels(data_dir, test_split, test_output_folder, test_classes_file)

图片大小处理

import os
import cv2

def resize_images(input_folder, output_folder, target_size=(416, 416)):
    for filename in os.listdir(input_folder):
        print(filename)
        if filename.endswith(".jpg"):  # Assuming images have these extensions
            input_path = os.path.join(input_folder, filename)
            output_path = os.path.join(output_folder, filename)

            # Read the image
            image = cv2.imread(input_path)

            # Resize the image
            resized_image = cv2.resize(image, target_size)

            # Save the resized image
            cv2.imwrite(output_path, resized_image)

if __name__ == "__main__":
    input_folder = '/yolo_data/code/test/images'
    output_folder = '/yolo_data/code/test/images'

    resize_images(input_folder, output_folder)
    print("ok")

训练

写一个 yaml 文件

# 数据集源路径root、训练集、验证集、测试集地址
path: /yolo_data/code/  # 数据集源路径root dir
train: train  # root下的训练集地址 128 images
val: test  # root下的验证集地址 128 images
test: test   # root下的验证集地址 128 images

# 数据集类别信息
nc: 70  # 数据集类别数量
names: [
    'Basketball', 'Biker', 'Bird1', 'BlurBody', 'BlurCar2', 'BlurFace', 'BlurOwl', 'Board', 'Bolt', 'Box',
    'Boy', 'Car1', 'Car2', 'CarDark', 'CarScale', 'ClifBar', 'Coke', 'Couple', 'Coupon', 'Crossing', 'Crowds',
    'Dancer', 'David', 'David2', 'Deer', 'Diving', 'Dog', 'Doll', 'DragonBaby', 'Dudek', 'FaceOcc1', 'Fish',
    'FleetFace', 'Football', 'Freeman1', 'Freeman3', 'Girl', 'Gym', 'Human2', 'Human3', 'Human4', 'Human5',
    'Human6', 'Human7', 'Ironman', 'Jogging', 'Jump', 'Jumping', 'KiteSurf', 'Lemming', 'Liquor', 'Man',
    'Matrix', 'Mhyang', 'MotorRolling', 'MountainBike', 'Panda', 'RedTeam', 'Rubik', 'Shaking', 'Singer1',
    'Skater', 'Skater2', 'Skating1', 'Skiing', 'Soccer', 'Subway', 'Surfer', 'Suv', 'Tiger1'
]

训练

官方:训练 - Ultralytics YOLOv8 文档

from ultralytics import YOLO
import cv2

# 加载模型
model = YOLO('yolov8n.pt')  # 加载预训练模型(推荐用于训练)

# 使用2个GPU训练模型
results = model.train(data='readme.yaml', epochs=2, imgsz=416, device=[0, 1])

结果

还没跑完,后面放结果

  • 人工智能

    人工智能(Artificial Intelligence)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门技术科学。

    132 引用 • 188 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...