成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

基于 Kalman 濾波的無標簽網(wǎng)球運動員追蹤

開發(fā)
本項目展示了如何利用GroundingDINO的無監(jiān)督能力來追蹤網(wǎng)球運動員,而無需依賴標注數(shù)據(jù),將復雜的目標檢測轉(zhuǎn)化為可操作的運動員追蹤。

近年來,隨著體育追蹤項目的興起,越來越多的體育愛好者開始使用自動化運動員追蹤技術。大多數(shù)方法遵循一個常見的工作流程:收集標注數(shù)據(jù),訓練YOLO模型,將運動員坐標投影到場地或球場的俯視圖中,并利用這些追蹤數(shù)據(jù)生成高級分析,以獲取潛在的競技洞察。然而,在本項目中,我們提供了一種工具,可以繞過對標注數(shù)據(jù)的需求,轉(zhuǎn)而依賴GroundingDINO的無監(jiān)督追蹤能力,并結(jié)合Kalman濾波來克服GroundingDINO輸出的噪聲問題。

我們的數(shù)據(jù)集來源于一組公開的廣播視頻,視頻鏈接:https://github.com/HaydenFaulkner/Tennis。這些數(shù)據(jù)包括2012年溫布爾登奧運會期間多場網(wǎng)球比賽的錄像,我們重點關注了塞雷娜·威廉姆斯(Serena Williams)和維多利亞·阿扎倫卡(Victoria Azarenka)之間的一場比賽。

對于不熟悉GroundingDINO的人來說,它將目標檢測與語言相結(jié)合,允許用戶輸入提示,例如“一個網(wǎng)球運動員”,模型隨后會返回符合描述的候選目標檢測框。RoboFlow提供了一個很好的教程,供有興趣使用的人參考——但我在下面也粘貼了一些非常基礎的代碼。如下所示,你可以通過提示讓模型識別一些在目標檢測數(shù)據(jù)集中很少被標記的對象,比如狗狗和狗的舌頭。

from groundingdino.util.inference import load_model, load_image, predict, annotate

BOX_TRESHOLD = 0.35
TEXT_TRESHOLD = 0.25

# processes the image to GroundingDino standards
image_source, image = load_image("dog.jpg")

prompt = "dog tongue, dog"
boxes, logits, phrases = predict(
    model=model, 
    image=image, 
    caption=TEXT_PROMPT, 
    box_threshold=BOX_TRESHOLD, 
    text_threshold=TEXT_TRESHOLD
)

然而,在職業(yè)網(wǎng)球場上區(qū)分運動員并不像提示“網(wǎng)球運動員”那么簡單。模型經(jīng)常會錯誤識別場上的其他人員,例如線審、球童和其他裁判,導致標注跳躍且不一致。此外,模型有時甚至無法在某些幀中檢測到運動員,導致標注框出現(xiàn)空白或無法持續(xù)出現(xiàn)在每一幀中。

追蹤在第一例中捕捉到線審,在第二例中捕捉到球童。圖片由作者制作

為了解決這些挑戰(zhàn),我們應用了幾種有針對性的方法。首先,我們將檢測框縮小到所有可能框中的前三個概率最高的框。通常,線審的概率得分高于運動員,這就是為什么我們不只過濾到兩個框。然而,這引發(fā)了一個新問題:如何在每一幀中自動區(qū)分運動員和線審?

我們觀察到,線和球工作人員的檢測框通常持續(xù)時間較短,往往只持續(xù)幾幀。基于此,我們假設通過關聯(lián)連續(xù)幀中的框,可以過濾掉那些只短暫出現(xiàn)的人員,從而隔離出運動員。

那么,我們?nèi)绾螌崿F(xiàn)跨幀對象之間的這種關聯(lián)呢?幸運的是,多目標追蹤領域已經(jīng)對這個問題進行了廣泛研究。Kalman濾波器是多目標追蹤中的主要工具,通常與其他識別指標(如顏色)結(jié)合使用。對于我們的目的,一個基本的Kalman濾波器實現(xiàn)就足夠了。簡單來說(更深入的探討可以參考這篇文章),Kalman濾波器是一種基于先前測量結(jié)果概率估計對象位置的方法。它在處理噪聲數(shù)據(jù)時特別有效,但也適用于在視頻中跨時間關聯(lián)對象,即使檢測不一致(例如運動員未被每一幀追蹤到)。我們在這里實現(xiàn)了一個完整的Kalman濾波器,但將在接下來的段落中介紹一些主要步驟。

二維Kalman濾波器的狀態(tài)非常簡單,如下所示。我們只需要跟蹤x和y位置以及對象在兩個方向上的速度(忽略加速度)。

class KalmanStateVector2D:
    x: float
    y: float
    vx: float
    vy: float

Kalman濾波器分為兩個步驟:首先預測對象在下一幀中的位置,然后根據(jù)新的測量結(jié)果(在我們的案例中來自目標檢測器)更新預測。然而,在我們的示例中,新幀可能會有多個新對象,甚至可能會丟失前一幀中存在的對象,這就引出了如何將之前看到的框與當前看到的框關聯(lián)起來的問題。

我們選擇使用馬氏距離(Mahalanobis distance)結(jié)合卡方檢驗來評估當前檢測與過去對象匹配的概率。此外,我們保留了一個過去對象的隊列,以便擁有比一幀更長的“記憶”。具體來說,我們的記憶存儲了過去30幀中看到的任何對象的軌跡。然后,對于我們在新幀中找到的每個對象,我們遍歷我們的記憶,找到最可能與當前對象匹配的先前對象,匹配概率由馬氏距離給出。然而,我們也可能看到一個全新的對象,在這種情況下,我們應該將一個新對象添加到我們的記憶中。如果任何對象與記憶中的任何框的關聯(lián)概率小于30%,我們將其作為新對象添加到記憶中。

完整的Kalman濾波器如下:


from dataclasses import dataclass

import numpy as np
from scipy import stats

class KalmanStateVectorNDAdaptiveQ:
    states: np.ndarray # for 2 dimensions these are [x, y, vx, vy]
    cov: np.ndarray # 4x4 covariance matrix

    def __init__(self, states: np.ndarray) -> None:
        self.state_matrix = states
        self.q = np.eye(self.state_matrix.shape[0])
        self.cov = None
        # assumes a single step transition
        self.f = np.eye(self.state_matrix.shape[0])
        
        # divide by 2 as we have a velocity for each state
        index = self.state_matrix.shape[0] // 2
        self.f[:index, index:] = np.eye(index)

    def initialize_covariance(self, noise_std: float) -> None:
        self.cov = np.eye(self.state_matrix.shape[0]) * noise_std**2

    def predict_next_state(self, dt: float) -> None:
        self.state_matrix = self.f @ self.state_matrix
        self.predict_next_covariance(dt)

    def predict_next_covariance(self, dt: float) -> None:
        self.cov = self.f @ self.cov @ self.f.T + self.q

    def __add__(self, other: np.ndarray) -> np.ndarray:
        return self.state_matrix + other

    def update_q(
        self, innovation: np.ndarray, kalman_gain: np.ndarray, alpha: float = 0.98
    ) -> None:
        innovation = innovation.reshape(-1, 1)
        self.q = (
            alpha * self.q
            + (1 - alpha) * kalman_gain @ innovation @ innovation.T @ kalman_gain.T
        )

class KalmanNDTrackerAdaptiveQ:

    def __init__(
        self,
        state: KalmanStateVectorNDAdaptiveQ,
        R: float,  # R
        Q: float,  # Q
        h: np.ndarray = None,
    ) -> None:
        self.state = state
        self.state.initialize_covariance(Q)
        self.predicted_state = None
        self.previous_states = []
        self.h = np.eye(self.state.state_matrix.shape[0]) if h is None else h
        self.R = np.eye(self.h.shape[0]) * R**2
        self.previous_measurements = []
        self.previous_measurements.append(
            (self.h @ self.state.state_matrix).reshape(-1, 1)
        )

    def predict(self, dt: float) -> None:
        self.previous_states.append(self.state)
        self.state.predict_next_state(dt)

    def update_covariance(self, gain: np.ndarray) -> None:
        self.state.cov -= gain @ self.h @ self.state.cov

    def update(
        self, measurement: np.ndarray, dt: float = 1, predict: bool = True
    ) -> None:
        """Measurement will be a x, y position"""
        self.previous_measurements.append(measurement)
        assert dt == 1, "Only single step transitions are supported due to F matrix"
        if predict:
            self.predict(dt=dt)
        innovation = measurement - self.h @ self.state.state_matrix
        gain_invertible = self.h @ self.state.cov @ self.h.T + self.R
        gain_inverse = np.linalg.inv(gain_invertible)
        gain = self.state.cov @ self.h.T @ gain_inverse

        new_state = self.state.state_matrix + gain @ innovation

        self.update_covariance(gain)
        self.state.update_q(innovation, gain)
        self.state.state_matrix = new_state

    def compute_mahalanobis_distance(self, measurement: np.ndarray) -> float:
        innovation = measurement - self.h @ self.state.state_matrix
        return np.sqrt(
            innovation.T
            @ np.linalg.inv(
                self.h @ self.state.cov @ self.h.T + self.R
            )
            @ innovation
        )

    def compute_p_value(self, distance: float) -> float:
        return 1 - stats.chi2.cdf(distance, df=self.h.shape[0])

    def compute_p_value_from_measurement(self, measurement: np.ndarray) -> float:
        """Returns the probability that the measurement is consistent with the predicted state"""
        distance = self.compute_mahalanobis_distance(measurement)
        return self.compute_p_value(distance)

在追蹤了過去30幀中檢測到的每個對象后,我們現(xiàn)在可以設計啟發(fā)式方法來精確定位哪些框最有可能代表我們的運動員。我們測試了兩種方法:選擇最靠近底線中心的框,以及選擇在我們記憶中觀察歷史最長的框。經(jīng)驗上,第一種策略在實際運動員遠離底線時經(jīng)常將線審標記為運動員,使其不太可靠。與此同時,我們注意到GroundingDino往往在不同的線審和球童之間“閃爍”,而真正的運動員則保持相對穩(wěn)定的存在。因此,我們的最終規(guī)則是選擇記憶中追蹤歷史最長的框作為真正的運動員。正如你在初始視頻中看到的,對于如此簡單的規(guī)則來說,它的效果出奇地好!

現(xiàn)在,我們的追蹤系統(tǒng)已經(jīng)在圖像上建立,我們可以轉(zhuǎn)向更傳統(tǒng)的分析,從鳥瞰視角追蹤運動員。這種視角可以評估關鍵指標,例如總移動距離、運動員速度和球場位置趨勢。例如,我們可以分析運動員是否經(jīng)常根據(jù)比賽中的位置針對對手的反手。為了實現(xiàn)這一點,我們需要將運動員坐標從圖像投影到標準化的球場模板上,從上方對齊視角以進行空間分析。

這就是單應性變換(homography)發(fā)揮作用的地方。單應性描述了兩個表面之間的映射關系,在我們的案例中,這意味著將原始圖像中的點映射到俯視的球場視圖。通過在原始圖像中識別一些關鍵點(例如球場上的線交叉點),我們可以計算一個單應性矩陣,將任何點轉(zhuǎn)換為鳥瞰圖。為了創(chuàng)建這個單應性矩陣,我們首先需要識別這些“關鍵點”。RoboFlow等平臺上的各種開源、許可寬松的模型可以幫助檢測這些點,或者我們可以在參考圖像上手動標記它們以用于變換。

正如你所看到的,預測的關鍵點并不完美,但我們發(fā)現(xiàn)小的誤差對最終的變換矩陣影響不大

在標記這些關鍵點后,下一步是將它們與參考球場圖像上的對應點匹配,以生成單應性矩陣。使用OpenCV,我們可以用幾行簡單的代碼創(chuàng)建這個變換矩陣:

import numpy as np
import cv2

# order of the points matters
source = np.array(keypoints) # (n, 2) matrix
target = np.array(court_coords) # (n, 2) matrix
m, _ = cv2.findHomography(source, target)

有了單應性矩陣,我們可以將圖像中的任何點映射到參考球場上。對于這個項目,我們的重點是運動員在球場上的位置。為了確定這一點,我們?nèi)∶總€運動員邊界框底部的中心點,將其作為他們在鳥瞰圖中的球場位置。

我們使用框底部的中心點來映射每個運動員在球場上的位置。圖示顯示了通過我們的單應性矩陣將關鍵點轉(zhuǎn)換為鳥瞰圖中的網(wǎng)球球場

總之,本項目展示了如何利用GroundingDINO的無監(jiān)督能力來追蹤網(wǎng)球運動員,而無需依賴標注數(shù)據(jù),將復雜的目標檢測轉(zhuǎn)化為可操作的運動員追蹤。通過解決關鍵挑戰(zhàn)——例如區(qū)分運動員與其他場上人員、確保跨幀的一致追蹤以及將運動員運動映射到球場的鳥瞰圖——我們?yōu)闊o需顯式標簽的穩(wěn)健追蹤管道奠定了基礎。

這種方法不僅解鎖了移動距離、速度和位置等洞察,還為更深入的比賽分析(如擊球目標和戰(zhàn)略覆蓋)打開了大門。通過進一步改進,包括從GroundingDINO輸出中提煉YOLO或RT-DETR模型,我們甚至可以開發(fā)出與現(xiàn)有商業(yè)解決方案相媲美的實時追蹤系統(tǒng),為網(wǎng)球世界的教練和球迷參與提供強大的工具。

責任編輯:趙寧寧 來源: 小白玩轉(zhuǎn)Python
相關推薦

2021-08-24 10:35:44

體育運動物聯(lián)網(wǎng)IOT

2024-08-08 09:08:33

3DAI應用

2016-12-14 14:15:42

業(yè)務人員利用率

2016-11-15 14:42:32

華為軟件開發(fā)云

2022-07-01 19:12:59

戴爾

2020-09-24 10:49:50

機器人人工智能系統(tǒng)

2018-05-04 07:21:48

物聯(lián)網(wǎng)設備物聯(lián)網(wǎng)可穿戴設備

2021-07-20 18:59:00

裁判人工智能AI

2020-01-10 17:30:57

信息安全漏洞技術

2022-09-14 12:59:27

人工智能運動課程足球比賽

2017-10-12 11:19:06

飛魚星

2011-04-02 12:00:32

Aruba網(wǎng)絡

2021-09-27 15:13:00

小米MIUI12.5

2011-02-23 12:28:11

Aruba澳大利亞網(wǎng)球協(xié)會

2014-12-24 13:53:48

2021-07-21 08:37:55

AI 裁判人工智能

2019-07-25 14:45:19

2018-06-27 08:25:53

技術VAR人工智能
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产成人高清视频 | 精品久久精品 | 国产精品我不卡 | 久久国产欧美日韩精品 | 草b视频| 成人免费视频网站在线看 | 久操福利 | 偷拍自拍网址 | 一区二区三区中文字幕 | 一级全黄少妇性色生活免费看 | 韩国电影久久 | 国内精品免费久久久久软件老师 | 奇米久久久 | 精品久久久久一区二区国产 | 欧美日韩在线一区二区三区 | 久久久久久蜜桃一区二区 | 国产一区在线免费观看 | 国产高清视频在线观看 | 一久久久 | 日韩中文字幕一区 | 亚洲国产一 | 久久人体视频 | 精品欧美激情在线观看 | 亚洲精品乱码久久久久久按摩 | 国产精品呻吟久久av凹凸 | 欧美成人精品在线 | 鲁视频 | 国产视频精品在线 | 成人在线观看中文字幕 | 久热精品免费 | 成年视频在线观看福利资源 | 啪啪av| 亚洲日韩中文字幕一区 | 日韩在线观看网站 | 国产一区二区三区四区五区加勒比 | www.色五月.com | 五月天综合网 | 日韩激情在线 | 一级黄色片在线看 | 国产精品久久久久久久久久久久久 | 日韩欧美一区二区三区免费观看 |