前言
基于 OTB100 数据集做目标跟踪,提供评价指标
chatGPT 写的代码,难看但是能用
参考:单目标跟踪数据集 | J. Xu (xujinzh.github.io)和[YOLOv8] - YOLO 数据集格式介绍和案例-CSDN 博客
数据
YOLOv8
地址
YOLO 数据集的格式主要包括以下几部分(注意:除扩展名外,标注文件的名称必须和图像的名称保持一致哦):
-
图像文件: 这是数据集中的图像文件,通常是 jpg 或 png 格式。
-
标注文件: 这是一个文本文件,包含了每张图像中目标对象的类别和位置信息
主要包含了以下内容:
-
每个目标对象的类别编号
-
目标对象在图像中的中心位置 (x,y)
-
目标对象的宽度和高度 (w,h)
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 的目标。
OTB100
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'
]
训练
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])
结果
还没跑完,后面放结果
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于