当前位置: 首页 > news >正文

基于 YOLOv8+ByteTrack+SuperVision 构建,实现足球比赛全流程智能分析

足球比赛视频智能分析与追踪系统
基于YOLOv8+ByteTrack+SuperVision库的足球比赛监测系统

交付内容 :
完整源代码

训练好的模型权重文件(best.pt)与示例视频

数据导出与 HTML 报告生成模块
可扩展说明:接口清晰,便于继续加热区图、事件检测、更多统计指标等

足球比赛视频智能分析与追踪系统 完整构建方案

一、系统核心功能概述

本系统基于YOLOv8+ByteTrack+SuperVision构建,实现足球比赛全流程智能分析,核心功能包括:

  1. 球员、裁判、足球多目标检测与多目标追踪
  2. 球员速度、距离、控球率等运动数据实时统计
  3. 相机运动补偿,消除镜头平移缩放对数据的影响
  4. 数据可视化标注与分析报告生成
  5. 球队识别、球员ID管理与赛事数据导出
  6. 支持视频文件/实时流输入,FPS可满足赛事级实时分析需求

二、环境依赖安装

pipinstallultralytics bytetrack supervision opencv-python numpy pandas matplotlib pyside6

三、核心模块代码实现

1. 主程序入口main.py

importsysfromPySide6.QtWidgetsimportQApplicationfromPySide6.QtGuiimportQFont,QFontDatabasefrommain_windowimportMainWindowif__name__=="__main__":app=QApplication(sys.argv)app.setStyle("Fusion")# 加载中文字体try_fonts=["Microsoft YaHei","微软雅黑","Source Han Sans SC","Noto Sans CJK SC"]available_families=QFontDatabase.families()forfnameintry_fonts:iffnameinavailable_families:app.setFont(QFont(fname,10))breakw=MainWindow()w.show()sys.exit(app.exec())

2. 主界面与核心逻辑main_window.py

importsysimportcv2importnumpyasnpimportpandasaspdfromdatetimeimportdatetimefromPySide6.QtWidgetsimport(QMainWindow,QWidget,QVBoxLayout,QHBoxLayout,QPushButton,QLabel,QSlider,QLineEdit,QCheckBox,QTabWidget,QTextEdit,QFileDialog,QMessageBox)fromPySide6.QtCoreimportQt,QThread,Signal,QTimerfromPySide6.QtGuiimportQImage,QPixmapfromultralyticsimportYOLOfromsupervisionimportByteTrack,VideoSink,Detections,BoundingBoxAnnotator,LabelAnnotator# 全局配置CONFIG={"model_path":"best.pt","imgsz":640,"conf_thres":0.5,"classes":[0,1,2],# player, referee, ball"fps":25,"pitch_width":68,# 场地宽度(m)"pitch_length":105# 场地长度(m)}classFootballAnalysisThread(QThread):frame_signal=Signal(np.ndarray)data_signal=Signal(dict)log_signal=Signal(str)def__init__(self,source):super().__init__()self.source=source self.running=Falseself.model=YOLO(CONFIG["model_path"])self.tracker=ByteTrack()self.tracks={"players":{},"referees":{},"ball":{}}self.player_speed={}self.camera_movement=[]self.annotator=BoundingBoxAnnotator()self.label_annotator=LabelAnnotator()defrun(self):self.running=Truecap=cv2.VideoCapture(self.source)fps=cap.get(cv2.CAP_PROP_FPS)orCONFIG["fps"]dt=1/fpswhileself.runningandcap.isOpened():ret,frame=cap.read()ifnotret:break# 目标检测与追踪results=self.model(frame,conf=CONFIG["conf_thres"],imgsz=CONFIG["imgsz"],classes=CONFIG["classes"])detections=Detections.from_ultralytics(results[0])detections=self.tracker.update_with_detections(detections)# 更新轨迹self.update_tracks(detections,dt)# 绘制标注annotated_frame=self.annotator.annotate(scene=frame.copy(),detections=detections)labels=[f"ID:{track_id}"fortrack_idindetections.tracker_id]annotated_frame=self.label_annotator.annotate(scene=annotated_frame,detections=detections,labels=labels)# 绘制速度与距离信息self.draw_player_stats(annotated_frame)# 发送帧self.frame_signal.emit(annotated_frame)cap.release()defupdate_tracks(self,detections,dt):"""更新目标轨迹与速度数据"""ifdetections.tracker_idisNone:returnfori,track_idinenumerate(detections.tracker_id):class_id=detections.class_id[i]xyxy=detections.xyxy[i]center=((xyxy[0]+xyxy[2])/2,(xyxy[1]+xyxy[3])/2)ifclass_id==0:# playeriftrack_idnotinself.tracks["players"]:self.tracks["players"][track_id]=[]self.tracks["players"][track_id].append(center)# 计算速度iflen(self.tracks["players"][track_id])>2:prev=self.tracks["players"][track_id][-2]dx=center[0]-prev[0]dy=center[1]-prev[1]speed_pixel=np.sqrt(dx**2+dy**2)# 像素速度转km/h(简化换算,需结合场地参数校准)speed=speed_pixel*0.05/dt*3.6self.player_speed[track_id]=speeddefdraw_player_stats(self,frame):"""在画面上绘制球员速度信息"""fortrack_id,speedinself.player_speed.items():iftrack_idinself.tracks["players"]andlen(self.tracks["players"][track_id])>0:x,y=self.tracks["players"][track_id][-1]cv2.putText(frame,f"{speed:.1f}km/h",(int(x),int(y)-20),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),2)defstop(self):self.running=Falseself.wait()classMainWindow(QMainWindow):def__init__(self):super().__init__()self.setWindowTitle("Football AI 足球比赛智能分析系统")self.setGeometry(100,100,1600,900)self.analysis_thread=Noneself.recorded_data=[]self.init_ui()definit_ui(self):central_widget=QWidget()self.setCentralWidget(central_widget)main_layout=QHBoxLayout(central_widget)# 左侧导航栏nav_panel=QWidget()nav_layout=QVBoxLayout(nav_panel)self.btn_home=QPushButton("首页")self.btn_detect=QPushButton("实时监测")self.btn_export=QPushButton("数据导出")nav_layout.addWidget(self.btn_home)nav_layout.addWidget(self.btn_detect)nav_layout.addWidget(self.btn_export)# 右侧主界面right_panel=QTabWidget()self.init_video_tab(right_panel)self.init_data_tab(right_panel)main_layout.addWidget(nav_panel,1)main_layout.addWidget(right_panel,4)definit_video_tab(self,tab_widget):video_tab=QWidget()layout=QVBoxLayout(video_tab)self.video_label=QLabel("视频将在此处显示")self.video_label.setAlignment(Qt.AlignCenter)layout.addWidget(self.video_label)# 控制面板control_layout=QHBoxLayout()self.btn_open_video=QPushButton("导入视频")self.btn_start_detect=QPushButton("开始分析")self.btn_stop_detect=QPushButton("停止分析")control_layout.addWidget(self.btn_open_video)control_layout.addWidget(self.btn_start_detect)control_layout.addWidget(self.btn_stop_detect)layout.addLayout(control_layout)# 信号连接self.btn_open_video.clicked.connect(self.open_video_file)self.btn_start_detect.clicked.connect(self.start_analysis)self.btn_stop_detect.clicked.connect(self.stop_analysis)tab_widget.addTab(video_tab,"实时监测")definit_data_tab(self,tab_widget):data_tab=QWidget()layout=QVBoxLayout(data_tab)self.btn_export_csv=QPushButton("导出CSV数据")self.btn_export_html=QPushButton("生成HTML报告")layout.addWidget(self.btn_export_csv)layout.addWidget(self.btn_export_html)tab_widget.addTab(data_tab,"数据导出")defopen_video_file(self):path,_=QFileDialog.getOpenFileName(self,"选择视频文件","","Video Files (*.mp4 *.avi)")ifpath:self.video_path=path QMessageBox.information(self,"提示",f"已选择视频:{path}")defstart_analysis(self):ifnothasattr(self,"video_path"):QMessageBox.warning(self,"警告","请先导入视频文件")returnifself.analysis_threadandself.analysis_thread.isRunning():self.analysis_thread.stop()self.analysis_thread=FootballAnalysisThread(self.video_path)self.analysis_thread.frame_signal.connect(self.update_frame)self.analysis_thread.log_signal.connect(self.log_message)self.analysis_thread.start()defstop_analysis(self):ifself.analysis_thread:self.analysis_thread.stop()self.video_label.clear()self.video_label.setText("视频将在此处显示")defupdate_frame(self,frame):rgb=cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)h,w,ch=rgb.shape bytes_per_line=ch*w qimg=QImage(rgb.data,w,h,bytes_per_line,QImage.Format_RGB888)self.video_label.setPixmap(QPixmap.fromImage(qimg).scaled(self.video_label.size(),Qt.KeepAspectRatio))deflog_message(self,msg):print(f"[LOG]{msg}")defcloseEvent(self,event):self.stop_analysis()event.accept()

3. 相机运动补偿模块camera_movement_estimator.py

importcv2importnumpyasnpclassCameraMovementEstimator:def__init__(self,frame):self.minimum_distance=5self.lk_params=dict(winSize=(15,15),maxLevel=2,criteria=(cv2.TERM_CRITERIA_EPS|cv2.TERM_CRITERIA_COUNT,10,0.03))self.feature_params=dict(maxCorners=100,qualityLevel=0.3,minDistance=7,blockSize=7)self.prev_gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)self.prev_features=cv2.goodFeaturesToTrack(self.prev_gray,mask=None,**self.feature_params)defget_movement(self,frame):"""计算相机平移量"""gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)new_features,status,_=cv2.calcOpticalFlowPyrLK(self.prev_gray,gray,self.prev_features,None,**self.lk_params)movement_x,movement_y=0,0ifnew_featuresisnotNone:good_new=new_features[status==1]good_old=self.prev_features[status==1]iflen(good_new)>0andlen(good_old)>0:movement_x=np.mean(good_new[:,0]-good_old[:,0])movement_y=np.mean(good_new[:,1]-good_old[:,1])# 更新特征点self.prev_gray=gray self.prev_features=cv2.goodFeaturesToTrack(gray,mask=None,**self.feature_params)returnmovement_x,movement_y

4. 球员速度与距离估算模块speed_and_distance_estimator.py

importcv2importnumpyasnpclassSpeedAndDistanceEstimator:def__init__(self,fps,pitch_length=105,pitch_width=68):self.fps=fps self.pitch_length=pitch_length self.pitch_width=pitch_width self.player_positions={}self.player_speeds={}self.player_distances={}defadd_position(self,player_id,position,frame_num):"""记录球员位置"""ifplayer_idnotinself.player_positions:self.player_positions[player_id]=[]self.player_distances[player_id]=0self.player_positions[player_id].append((position,frame_num))defcalculate_speed(self,player_id):"""计算球员瞬时速度(km/h)"""iflen(self.player_positions[player_id])<2:return0pos1,frame1=self.player_positions[player_id][-2]pos2,frame2=self.player_positions[player_id][-1]dx=pos2[0]-pos1[0]dy=pos2[1]-pos1[1]distance_pixel=np.sqrt(dx**2+dy**2)dt=(frame2-frame1)/self.fpsifdt==0:return0# 像素距离转米(需结合场地参数校准)meters_per_pixel_x=self.pitch_length/1000meters_per_pixel_y=self.pitch_width/500distance_m=np.sqrt((dx*meters_per_pixel_x)**2+(dy*meters_per_pixel_y)**2)speed=(distance_m/dt)*3.6self.player_speeds[player_id]=speed self.player_distances[player_id]+=distance_mreturnspeeddefdraw_speed_and_distance(self,frame,player_id,position):"""在画面上绘制速度和距离信息"""speed=self.calculate_speed(player_id)distance=self.player_distances[player_id]cv2.putText(frame,f"{speed:.1f}km/h",(int(position[0]),int(position[1]-20)),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),2)cv2.putText(frame,f"{distance:.1f}m",(int(position[0]),int(position[1]-40)),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,255),2)returnframe

四、系统扩展接口说明

本系统接口设计清晰,可快速扩展以下功能:

  1. 热区图生成:基于球员轨迹数据,使用matplotlib生成球员活动热区分布图
  2. 事件检测:通过球员与足球的位置关系,自动识别传球、射门、抢断等关键事件
  3. 控球率统计:根据足球与球员的距离,计算两队控球时间占比
  4. 越位线辅助:基于球员位置自动绘制越位线,辅助越位判罚分析
  5. 战术阵型分析:根据球员位置分布,识别球队当前阵型与战术站位

五、使用说明

  1. 将训练好的YOLOv8/11模型best.pt放在项目根目录;
  2. 运行python main.py启动系统;
  3. 点击「导入视频」选择赛事视频文件;
  4. 点击「开始分析」启动目标检测与追踪;
  5. 分析完成后,可导出CSV格式的球员运动数据,或生成HTML可视化报告。

六、补充说明

  • 相机运动补偿模块使用光流法实现,可有效消除镜头平移缩放对球员位置和速度计算的影响;
  • 速度与距离估算需结合实际场地尺寸进行像素-米校准,以提升数据精度;
  • 如需部署到低配置设备,可使用YOLOv8n模型并降低输入分辨率,保证实时FPS;
  • 可通过修改CONFIG["classes"]扩展检测类别,如增加球门、角旗、广告牌等目标。

需要我帮你补充完整的HTML报告生成代码,或者扩展热区图、控球率统计的功能实现吗?

http://www.jsqmd.com/news/1148249/

相关文章:

  • 【无标题】企业展厅LED显示屏技术解刨
  • 如何精准识别校地合作中的潜在技术转移机会?
  • 新手实操|1688选品铺货全流程 一件代发零踩坑教程
  • 临时外包人员要提交代码,怎么只给他一个项目权限?
  • Windows系统文件chartv.dll丢失找不到问题解决
  • Windows系统文件cic.dll丢失找不到问题解决
  • 2026国内短期IT课程TOP5!广东广州等地培训公司实力获好评
  • Qt 容器的 COW 真相:detach 何时触发,又何时让你性能崩盘
  • 博通新款芯片将用于多代苹果产品,双方合作再拓展
  • 5分钟快速激活Windows和Office:KMS_VL_ALL_AIO智能激活指南
  • 456789
  • STM32直流电机控制:UNI Clicker与DRV8833实战
  • 如何从零构建FOC双轮腿机器人:完整实践指南
  • 通心译 (Tongxin Translation) — 鸿蒙端
  • 基于深度学习的道路车辆智能追踪与监控系统,采用最新的YOLOv11目标检测算法,结合ByteTrack多目标追踪技术、PaddleOCR车牌识别和区域入侵检测等先进功能,为智能交通管理提供全方位的解决
  • AI 工具链反思:平台团队到底该自研哪些轮子
  • 本地部署Bernini:角色替换从调参玄学到工程化实践
  • 网约车 Go 后端 + AI 编码工具实战踩坑记录|3 个高频问题完整复盘
  • 直流有刷电机驱动器TC78H651AFNG与dsPIC33EP512MU814应用解析
  • CircuitJS1 Desktop Mod:终极免费离线电路仿真软件,电子爱好者的数字实验室
  • 一条 UPDATE 锁住半张表:MySQL 没走索引的真实事故
  • 1988-2025年企业产学研专利申请与授权数量统计数据集
  • TLP241A光耦与MK60微控制器的工业隔离设计实践
  • 暗黑破坏神2存档编辑器:3步快速修改角色属性和物品管理终极指南
  • 桥梁坍塌安全监测与自然灾害预警:改进YOLO算法的目标检测数据集全解析10310期
  • 2026国内IT网课TOP5!广东广州等地培训公司口碑出众
  • OA 协同办公全景:一个底座装下公文、会议、用车、用印、日程、用品
  • 杰理之 IIS主机在没有数据输出时需保持【篇】
  • ‌小圆柱,大精度——圆柱形激光传感器如何重塑工业感知新标准
  • showcases shape the future of spaceflight