可以只是已经制作好的数据集,也可以进行制作:
数据集制作:1,2,3步
数据集下载: https://pan.baidu.com/s/1upT_aD06lzjuz-Xjze0dcw 提取码: 6eax
windows下分卷解压文件:https://blog.csdn.net/qq_41941900/article/details/142366183
1.sn-tracking数据集足球赛事追踪数据集下载:
https://github.com/SoccerNet/sn-tracking
代码下载:
pip install SoccerNet
from SoccerNet.Downloader import SoccerNetDownloader
mySoccerNetDownloader = SoccerNetDownloader(LocalDirectory="path/to/SoccerNet")
mySoccerNetDownloader.downloadDataTask(task="tracking", split=["train","test","challenge"])
mySoccerNetDownloader.downloadDataTask(task="tracking-2023", split=["train", "test", "challenge"])
2.提取sn-tracking数据集中只有足球的图片,生成YOLO格式的数据
import os
import shutil
import cv2
"从snmot数据集中挑选含有足球的数据"
base_path = r"D:\mywork\dataset\IKCEST\images\train"
dataset_image_path = "IKCEST/images/train"
dataset_labels_path = "IKCEST/labels/train"
os.makedirs(dataset_image_path, exist_ok=True)
os.makedirs(dataset_labels_path, exist_ok=True)
snmot_list = os.listdir(base_path)
print(snmot_list)
for path in snmot_list:
new_path = os.path.join(base_path,path)
gt = os.path.join(new_path,"gt/gt.txt")
gameinfo = os.path.join(new_path, "gameinfo.ini")
with open(gameinfo) as f:
trackletID_ball = [i.split("=")[0].split("_")[-1] for i in f.readlines() if "ball" in i]
print(trackletID_ball)
with open(gt) as f:
label = f.readlines()
for trackletID in trackletID_ball:
label_list = []
for i in label:
seq = i.split(",")
if seq[1] == trackletID:
image_path = os.path.join(new_path, 'img1/{:06d}.jpg'.format(eval(seq[0]))).replace("\\","/")
new_image_path = os.path.join(dataset_image_path,path+"_"+os.path.basename(image_path))
label_path = os.path.join(dataset_labels_path,path+"_"+os.path.basename(image_path).replace(".jpg",".txt"))
shutil.copy(image_path,new_image_path)
x, y, w, h = [eval(mt) for mt in seq[2:6]]
x_center = x + w / 2
y_center = y + h / 2
height, width, channels = cv2.imread(image_path).shape
normalized_x_center = x_center / width
normalized_y_center = y_center / height
normalized_width = w / width
normalized_height = h / height
with open(label_path,"a") as wf:
wf.write(f"{0} {normalized_x_center} {normalized_y_center} {normalized_width} {normalized_height}\n")
3.将提取的只含有足球的数据集划分训练集和测试集
from glob import iglob
import os
import shutil
import random
dataset_image_path = "IKCEST/images/train"
dataset_labels_path = "IKCEST/labels/train"
dev_dataset_image_path = "IKCEST/images/dev"
dev_dataset_labels_path = "IKCEST/labels/dev"
os.makedirs(dev_dataset_image_path, exist_ok=True)
os.makedirs(dev_dataset_labels_path, exist_ok=True)
imageset = list(iglob(os.path.join(dataset_image_path,"*.jpg"),recursive=True))
print(len(imageset))
test_index = random.sample(list(range(len(imageset))),int(0.2*len(imageset)))
print(len(test_index))
for index in test_index:
new_image = os.path.join(dev_dataset_image_path,os.path.basename(imageset[index]))
new_label = os.path.join(dev_dataset_labels_path, os.path.basename(imageset[index]).replace(".jpg",".txt"))
shutil.move(imageset[index],new_image)
shutil.move(imageset[index].replace(".jpg",".txt").replace("images","labels"), new_label)
from glob import iglob
import os
base = "IKCEST"
train = ["train","dev"]
for i in train:
base_path = os.path.join(base,"images",i)
image_list = list(iglob(os.path.join(base_path,"*.jpg"),recursive=True))
with open(base + "/" + i + ".txt", "w") as fm:
for file_ in image_list:
fm.write("./"+file_.replace("IKCEST","").replace("\\","/")+"\n")
4.制作Yolov8的配置文件及训练配置yaml
SNMOT.yaml
path: D:/mywork/IKCEST_Football # dataset root dir
train: train.txt # train images (relative to 'path') 118287 images
val: dev.txt # val images (relative to 'path') 5000 images
test: dev.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794
names:
0: ball
# Download script/URL (optional)
download: |
from utils.general import download, Path
# Download labels
#segments = True # segment or box labels
#dir = Path(yaml['path']) # dataset root dir
#url = 'https://github.com/WongKinYiu/yolov7/releases/download/v0.1/'
#urls = [url + ('coco2017labels-segments.zip' if segments else 'coco2017labels.zip')] # labels
#download(urls, dir=dir.parent)
# Download data
#urls = ['http://images.cocodataset.org/zips/train2017.zip', # 19G, 118k images
# 'http://images.cocodataset.org/zips/val2017.zip', # 1G, 5k images
# 'http://images.cocodataset.org/zips/test2017.zip'] # 7G, 41k images (optional)
#download(urls, dir=dir / 'images', threads=3)
yolov8-p2.yaml
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P2-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect
# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
# [depth, width, max_channels]
#n: [0.33, 0.25, 1024]
#s: [0.33, 0.50, 1024]
#m: [0.67, 0.75, 768]
#l: [1.00, 1.00, 512]
x: [1.00, 1.25, 512]
# YOLOv8.0 backbone
backbone:
# [from, repeats, module, args]
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 3, C2f, [128, True]]
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 6, C2f, [256, True]]
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 6, C2f, [512, True]]
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 3, C2f, [1024, True]]
- [-1, 1, SPPF, [1024, 5]] # 9
# YOLOv8.0-p2 head
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 3, C2f, [512]] # 12
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 3, C2f, [256]] # 15 (P3/8-small)
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 2], 1, Concat, [1]] # cat backbone P2
- [-1, 3, C2f, [128]] # 18 (P2/4-xsmall)
- [-1, 1, Conv, [128, 3, 2]]
- [[-1, 15], 1, Concat, [1]] # cat head P3
- [-1, 3, C2f, [256]] # 21 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 12], 1, Concat, [1]] # cat head P4
- [-1, 3, C2f, [512]] # 24 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 9], 1, Concat, [1]] # cat head P5
- [-1, 3, C2f, [1024]] # 27 (P5/32-large)
- [[18, 21, 24, 27], 1, Detect, [nc]] # Detect(P2, P3, P4, P5)
5.训练足球检测模型
import sys
sys.path.append("ultralytics")
from ultralytics import YOLO
import os
os.system("wandb offline")
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
#https://blog.csdn.net/darkredrock/article/details/131046149
#model = YOLO('yolov8_config/yolov8-p2.yaml').load("yolov8x.pt")
model = YOLO('yolov8_config/yolov8-p2.yaml').load("runs/detect/train13/weights/last.pt")
#model = YOLO('yolov8_config/yolov8.yaml').load("runs/detect/train9/weights/last.pt")
results = model.train(data="yolov8_config/SNMOT.yaml", epochs=40, device='0',
batch=4,save=True, resume=True,amp=False,workers=0) # 断点恢复训练模型
6.足球目标追踪
# #https://blog.csdn.net/qq_42452134/article/details/135241059
import cv2
from ultralytics import YOLO
import os
import torch
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
# # 加载YOLOv8模型
model = YOLO(r'runs\detect\train14\weights\best.pt').to("cuda:0")
# 打开视频文件
video_path = "a3.mp4"
cap = cv2.VideoCapture(video_path)
sz = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),
int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
fps = 30
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
vout_1 = cv2.VideoWriter()
vout_1.open('a3_output_v8_p2_noaug.mp4',fourcc,fps,sz,True)
# 循环遍历视频帧
kk = 0
with open("result.txt","w") as f:
while cap.isOpened():
# 从视频读取一帧
success, frame = cap.read()
if success:
# 在帧上运行YOLOv8追踪,持续追踪帧间的物体
results = model.track(frame, persist=True)
# 输出每次追踪推理结果的boxes,这些参数实际上是和模型直接predict类似的。
if len(results[0].boxes.data) !=0:
result_track = torch.cat((torch.zeros(results[0].boxes.cls.shape).unsqueeze(1).to("cpu"), results[0].boxes.xywh.to("cpu"), results[0].boxes.conf.unsqueeze(1).to("cpu")), dim=1)
for i in range(result_track.shape[0]):
line = f"{kk+1},{int(result_track[i][0].item())}, {result_track[i][1].item()}, {result_track[i][2].item()}, {result_track[i][3].item()}, {result_track[i][4].item()}, {result_track[i][5].item()}, 1, -1, -1"
f.write(line+"\n")
# 在帧上展示结果
annotated_frame = results[0].plot()
vout_1.write(annotated_frame)
# 展示带注释的帧
#cv2.imshow("YOLOv8 Tracking", annotated_frame)
os.makedirs("runs/detect/track2",exist_ok=True)
cv2.imwrite(f"runs/detect/track2/{kk}.png",annotated_frame)
else:
vout_1.write(frame)
else:
# 如果视频结束则退出循环
break
kk +=1