基于YOLO算法實現網球運動實時分析(附源碼)

e94c72d411790c3e7b9f80c07cfd0bad.gif

大家好,我是小F~

今天給大家介紹一個計算機視覺實戰的項目。

該項目使用YOLO算法檢測球員和網球,并利用cnn提取球場關鍵點。

進而分析視頻中的網球運動員,測量他們的速度、擊球速度和擊球次數。

ac215435d724f6066b7df6db9a514c1f.gif

使用win10電腦,Python 3.9.7,相關依賴版本如下。

numpy==1.22.4
opencv_python==4.8.0.74
pandas==2.2.2
torch==2.0.1
torchvision==0.15.2
ultralytics==8.0.178

可以使用conda創建Python環境,然后執行主程序。

電腦無需GPU,普通CPU電腦即可~

#?創建Python環境
conda?create?--name?tennis_analysis??python=3.9.7
#?激活環境
conda?activate?tennis_analysis
#?安裝依賴
pip?install?-r?requirements.txt?-i?https://mirror.baidu.com/pypi/simple#?執行程序
python?main.py

主程序代碼如下。

from?utils?import?(read_video,save_video,measure_distance,draw_player_stats,convert_pixel_distance_to_meters)
import?constants
from?trackers?import?PlayerTracker,?BallTracker
from?court_line_detector?import?CourtLineDetector
from?mini_court?import?MiniCourt
import?cv2
import?pandas?as?pd
from?copy?import?deepcopydef?main():#?Read?Videoinput_video_path?=?"input_videos/input_video.mp4"video_frames?=?read_video(input_video_path)#?Detect?Players?and?Ballplayer_tracker?=?PlayerTracker(model_path='yolov8x')ball_tracker?=?BallTracker(model_path='models/yolo5_last.pt')player_detections?=?player_tracker.detect_frames(video_frames,read_from_stub=True,stub_path="tracker_stubs/player_detections.pkl")ball_detections?=?ball_tracker.detect_frames(video_frames,read_from_stub=True,stub_path="tracker_stubs/ball_detections.pkl")ball_detections?=?ball_tracker.interpolate_ball_positions(ball_detections)#?Court?Line?Detector?modelcourt_model_path?=?"models/keypoints_model.pth"court_line_detector?=?CourtLineDetector(court_model_path)court_keypoints?=?court_line_detector.predict(video_frames[0])#?choose?playersplayer_detections?=?player_tracker.choose_and_filter_players(court_keypoints,?player_detections)#?MiniCourtmini_court?=?MiniCourt(video_frames[0])#?Detect?ball?shotsball_shot_frames?=?ball_tracker.get_ball_shot_frames(ball_detections)#?Convert?positions?to?mini?court?positionsplayer_mini_court_detections,?ball_mini_court_detections?=?mini_court.convert_bounding_boxes_to_mini_court_coordinates(player_detections,ball_detections,court_keypoints)player_stats_data?=?[{'frame_num':?0,'player_1_number_of_shots':?0,'player_1_total_shot_speed':?0,'player_1_last_shot_speed':?0,'player_1_total_player_speed':?0,'player_1_last_player_speed':?0,'player_2_number_of_shots':?0,'player_2_total_shot_speed':?0,'player_2_last_shot_speed':?0,'player_2_total_player_speed':?0,'player_2_last_player_speed':?0,}]for?ball_shot_ind?in?range(len(ball_shot_frames)?-?1):start_frame?=?ball_shot_frames[ball_shot_ind]end_frame?=?ball_shot_frames[ball_shot_ind?+?1]ball_shot_time_in_seconds?=?(end_frame?-?start_frame)?/?24??#?24fps#?Get?distance?covered?by?the?balldistance_covered_by_ball_pixels?=?measure_distance(ball_mini_court_detections[start_frame][1],ball_mini_court_detections[end_frame][1])distance_covered_by_ball_meters?=?convert_pixel_distance_to_meters(distance_covered_by_ball_pixels,constants.DOUBLE_LINE_WIDTH,mini_court.get_width_of_mini_court())#?Speed?of?the?ball?shot?in?km/hspeed_of_ball_shot?=?distance_covered_by_ball_meters?/?ball_shot_time_in_seconds?*?3.6#?player?who?the?ballplayer_positions?=?player_mini_court_detections[start_frame]player_shot_ball?=?min(player_positions.keys(),key=lambda?player_id:?measure_distance(player_positions[player_id],ball_mini_court_detections[start_frame][1]))#?opponent?player?speedopponent_player_id?=?1?if?player_shot_ball?==?2?else?2distance_covered_by_opponent_pixels?=?measure_distance(player_mini_court_detections[start_frame][opponent_player_id],player_mini_court_detections[end_frame][opponent_player_id])distance_covered_by_opponent_meters?=?convert_pixel_distance_to_meters(distance_covered_by_opponent_pixels,constants.DOUBLE_LINE_WIDTH,mini_court.get_width_of_mini_court())speed_of_opponent?=?distance_covered_by_opponent_meters?/?ball_shot_time_in_seconds?*?3.6current_player_stats?=?deepcopy(player_stats_data[-1])current_player_stats['frame_num']?=?start_framecurrent_player_stats[f'player_{player_shot_ball}_number_of_shots']?+=?1current_player_stats[f'player_{player_shot_ball}_total_shot_speed']?+=?speed_of_ball_shotcurrent_player_stats[f'player_{player_shot_ball}_last_shot_speed']?=?speed_of_ball_shotcurrent_player_stats[f'player_{opponent_player_id}_total_player_speed']?+=?speed_of_opponentcurrent_player_stats[f'player_{opponent_player_id}_last_player_speed']?=?speed_of_opponentplayer_stats_data.append(current_player_stats)player_stats_data_df?=?pd.DataFrame(player_stats_data)frames_df?=?pd.DataFrame({'frame_num':?list(range(len(video_frames)))})player_stats_data_df?=?pd.merge(frames_df,?player_stats_data_df,?on='frame_num',?how='left')player_stats_data_df?=?player_stats_data_df.ffill()player_stats_data_df['player_1_average_shot_speed']?=?player_stats_data_df['player_1_total_shot_speed']?/?\player_stats_data_df['player_1_number_of_shots']player_stats_data_df['player_2_average_shot_speed']?=?player_stats_data_df['player_2_total_shot_speed']?/?\player_stats_data_df['player_2_number_of_shots']player_stats_data_df['player_1_average_player_speed']?=?player_stats_data_df['player_1_total_player_speed']?/?\player_stats_data_df['player_2_number_of_shots']player_stats_data_df['player_2_average_player_speed']?=?player_stats_data_df['player_2_total_player_speed']?/?\player_stats_data_df['player_1_number_of_shots']#?Draw?output##?Draw?Player?Bounding?Boxesoutput_video_frames?=?player_tracker.draw_bboxes(video_frames,?player_detections)output_video_frames?=?ball_tracker.draw_bboxes(output_video_frames,?ball_detections)##?Draw?court?Keypointsoutput_video_frames?=?court_line_detector.draw_keypoints_on_video(output_video_frames,?court_keypoints)#?Draw?Mini?Courtoutput_video_frames?=?mini_court.draw_mini_court(output_video_frames)output_video_frames?=?mini_court.draw_points_on_mini_court(output_video_frames,?player_mini_court_detections)output_video_frames?=?mini_court.draw_points_on_mini_court(output_video_frames,?ball_mini_court_detections,color=(0,?255,?255))#?Draw?Player?Statsoutput_video_frames?=?draw_player_stats(output_video_frames,?player_stats_data_df)##?Draw?frame?number?on?top?left?cornerfor?i,?frame?in?enumerate(output_video_frames):cv2.putText(frame,?f"Frame:?{i}",?(10,?30),?cv2.FONT_HERSHEY_SIMPLEX,?1,?(0,?255,?0),?2)save_video(output_video_frames,?"output_videos/output_video.avi")if?__name__?==?"__main__":main()

最終可以在output_videos文件夾下看到結果。

9e796e09a6fde183cca899fd82e1ff54.png

結果如下所示。

145bb8c4bda7bcf194eda68a0b796ff1.png

這里還提供了網球模型訓練的代碼,大家可以使用Colab或Kaggle的免費GPU進行訓練。

感興趣的小伙伴,可以自行去學習下~

02b7ec9a500caba8bc58819b6c392885.png

項目源碼,公眾號后臺回復:「網球分析」,即可獲得。

萬水千山總是情,點個?👍?行不行

推薦閱讀

320554683c0cfed55272b40b6c2a5496.jpeg

151a0abceb004e46d346cde0fff18ad1.jpeg

2901b93a9c4c05c93aadd47dba41aeb3.jpeg

···? END? ···

7fdc980d1452027cbbf5e40cf3578f53.jpeg

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/16523.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/16523.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/16523.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【源碼】java + uniapp交易所源代碼/帶搭建教程java交易所/完整源代碼

java uniapp交易所源代碼/帶搭建教程java交易所/完整源代碼 帶簡潔教程,未測 java uniapp交易所源代碼/帶搭建教程java交易所/完整源代碼 - 吾愛資源網

【古董技術】ms-dos應用程序的結構

序 制定一個MS-DOS應用程序計劃需要認真分析程序的大小。這種分析可以幫助程序員確定MS-DOS支持的兩種程序風格中哪一種最適合該應用程序。.EXE程序結構為大型程序提供了好處,因為所有.EXE文件之前都有額外的512字節(或更多)的文件頭。另一方…

C++第十七彈---string使用(下)

?個人主頁: 熬夜學編程的小林 💗系列專欄: 【C語言詳解】 【數據結構詳解】【C詳解】 目錄 1、標準庫中的string類 1.1、string類的常用接口說明 1.1.1、string類對象的修改操作 1.1.2、string類對象非成員函數重載 總結 1、標準庫中的…

牛客熱題:有效括號

📟作者主頁:慢熱的陜西人 🌴專欄鏈接:力扣刷題日記 📣歡迎各位大佬👍點贊🔥關注🚓收藏,🍉留言 文章目錄 牛客熱題:有效括號題目鏈接方法一&#x…

MySQL視圖教程(01):創建視圖

MySQL 創建視圖 在 MySQL 中, CREATE VIEW 語句用于創建一個數據庫視圖(View)。 MySQL 是一種常用的關系型數據庫管理系統,提供了 CREATE VIEW 語法,用于創建視圖(View)。視圖是一種虛擬的表&…

Mycat+Mysql搭建數據集群實現數據分片存儲

前言 MyCAT介紹 * 一個徹底開源的,面向企業應用開發的“大數據庫集群”; * 支持事務、ACID、可以替代MySQL的加強版數據庫; * 一個可以視為“MySQL”集群的企業級數據庫,用來替代昂貴的Oracle集群; * 一個融合內存緩存技術、Nosql技術、HDFS大數據的新型SQL; * 一個新穎…

QCC---DFU升級變更設備名和地址

QCC---DFU升級變更設備名和地址 這個很多人碰到這個疑問,升級了改不了設備名和地址 /******************************************************************************* Copyright (c) 2018 Qualcomm Technologies International, Ltd. FILE NAME sink_dfu_ps.c DESCRIPT…

2024.5.1學習記錄

1、代碼隨想錄:貪心刷題 2、react 高級使用( hoc render、props、函數組件、serState 傳送門等) 3、游山玩水

《拯救大學生課設不掛科第四期之藍橋杯是什么?我是否要參加藍橋杯?選擇何種語言?如何科學備賽?方法思維教程》【官方筆記】

背景: 有些同學在大一或者大二可能會被老師建議參加藍橋杯,本視頻和文章主要是以一個過來人的身份來給與大家一些思路。 比如藍橋杯是什么?我是否要參加藍橋杯?參加藍橋杯該選擇何種語言?如何科學備賽?等…

2023年信息素養大賽小學組C++智能算法復賽試題解析

2023年信息素養大賽小學組C++智能算法復賽真題 智能算法挑戰復賽小學組(總共4道題)T1. 判斷數字出現了幾次 【題目描述】 給定一個正整數 n,判斷從 1 到這個數本身的所有數中,一共出現了多少次數字k。 【輸入格式】 輸入共1行,包括一個正整數n和一個正整數k。(0<n<…

JavaEE之線程(7)_單例模式(設計模式概念、單例模式優點、懶漢、餓漢模式)

一、什么是設計模式&#xff1f; 單例模式是設計模式中較為常見的一種。那么&#xff0c;什么是單例模式&#xff1f; 設計模式&#xff08;Design Pattern&#xff09;都是一些相對優秀的解決方案&#xff0c;很多問題都是典型的、有代表性的問題&#xff0c;學習設計模式&am…

C#面:如果出現ASP.NET中的事件不能觸發可能由于什么原因造成

當 ASP.NET 中的事件不能觸發時&#xff0c;可能由以下幾個原因造成&#xff1a; 事件綁定錯誤&#xff1a;請確保事件正確地綁定到相應的控件上。在 ASP.NET 中&#xff0c;可以通過在前端代碼或者后端代碼中使用事件處理程序來綁定事件。如果事件沒有正確地綁定到控件上&…

為什么本科畢業后我堅定地選擇了就業而不是考研?

大家好&#xff0c;我是小布丁。今天來聊聊我為什么本科畢業后選擇了就業而不是考研。 在整個大學期間&#xff0c;我被親戚拷問最多的問題就是&#xff1a;準備考研嗎&#xff1f;相信很多大學生都遇到過這種情況吧。 如果你說準備還好&#xff0c;親戚大概率就不會問下去&a…

js計算字符串大小存儲所占字節數

在JavaScript中&#xff0c;計算字符串所占的大小&#xff08;占用的字節數&#xff09;并不直接&#xff0c;但可以通過一些方法間接得到。 我們需要知道一個前提&#xff0c;英文字母 lenght 和字節數是一樣的&#xff1a;都是1&#xff0c;而中文 lenght1&#xff0c;字節數…

golang sqlite主從數據同步插件開發

### golang sqlite主從數據同步插件開發思路 參考Mysql的主從同步機制&#xff0c;Mysql是產生binlog&#xff0c;然后把binlog日志同步到從服務上。 同理&#xff0c;我們按sql執行順序記錄所有的增刪改查的sql語句&#xff0c;然后調用接口把sql語句傳到從服務上執行。 數…

關于軟件設計模式的理解

系列文章 關于時間復雜度o(1), o(n), o(logn), o(nlogn)的理解 關于HashMap的哈希碰撞、拉鏈法和key的哈希函數設計 關于JVM內存模型和堆內存模型的理解 關于代理模式的理解 關于Mysql基本概念的理解 關于軟件設計模式的理解 文章目錄 前言一、軟件設計模式遵循的六大原則…

前端面試題日常練-day35 【面試題】

題目 希望這些選擇題能夠幫助您進行前端面試的準備&#xff0c;答案在文末。 1. 以下哪個是使用jQuery選擇所有具有CSS類名"myClass"的元素的正確語法&#xff1f; a) $(".myClass") b) $("myClass") c) $("#myClass") d) $("…

FURNet問題

1. 為什么選擇使用弱監督學習&#xff1f; 弱監督學習減少了對精確標注數據的依賴&#xff0c;這在醫學圖像處理中尤為重要&#xff0c;因為高質量標注數據通常需要大量專業知識和時間。弱監督學習通過利用少量標注數據或粗略標注數據來訓練模型&#xff0c;降低了數據準備的成…

元組推導式

自學python如何成為大佬(目錄):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 使用元組推導式可以快速生成一個元組&#xff0c;它的表現形式和列表推導式類似&#xff0c;只是將列表推導式中的“[]”修改為“()”。例如&#xf…

python深入解析字符串操作的八大神技

新書上架~&#x1f447;全國包郵奧~ python實用小工具開發教程http://pythontoolsteach.com/3 歡迎關注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目錄 一、字符串的長度與切片 示例代碼 二、去除多余的空格 示例代碼 三、字符串的開頭與包含…