簡體   English   中英

時間/位置列表上的Python低通濾波器

[英]Python low-pass filter on list of Time/Position

首先讓我解釋一下我的目標和問題。 我有一個物體在 bocal(准確地說是老鼠)內成圈運動 ,我需要知道它在一分鍾內旋轉了多少 這個運動不是一個完美的循環,並且可能是混亂的 它可以停止幾秒鍾,然后再次開始移動。

但是我知道的是,我每分鍾旋轉3到20次 => 低頻(0.05 Hz到0.33 Hz之間 )。

我正在30分鍾內30 fps的相機拍攝該對象。 使用Python和OpenCV,我設法提取(X,Y)坐標。 由於30 fps對於我要尋找的頻率來說有點高,因此我選擇了15幀來獲得2 Hz采樣頻率

第一個問題是,有時我會遺漏一點,因為OpenCV無法找到對象。 這是我無法解決的問題,因為使用HSV彩色蒙版跟蹤的點有時是隱藏的。

實際上,我要過濾的數據是:

  • 框架,框架編號的列表 在索引[i]處,我具有與X [i]和Y [i]對應的幀號
  • X, X坐標的列表
  • Y, Y坐標列表

例如,我有這樣的列表:

  • 框架= [15、90、165、180、195、210、225、300、315、375、405]
  • X = [395,487,389,389,358,382,373,389,397,403,446]
  • Y = [167、211、166、173、180、185、191、223、241、231、238]

如您所見,這是運動的王者,我需要過濾高頻。

現在, 我的問題是 :即使我在過濾和編碼方面有一些基礎知識,我也不知道該怎么做以及使用哪個庫。 我讀過scipy應該具有所有必需的功能,但是我不知道要使用哪個,以及如何使用。

我不確定,但是我認為我應該做這樣的事情:

  • 傅里葉變換
  • 低通濾波
  • 逆變換

您能告訴我我是否正確,並為編碼部分指明正確的方向嗎?

謝謝您的幫助,

馬蒂厄

在深入研究傅立葉變換之前,您可以僅應用一階或二階低通濾波器。 您可以先對數據進行線性插值,以使頻率恆定為2Hz 然后,您可以將一階低通濾波器應用於數據點。

y_k = a * x_k + (1-a) * y_km1, a in [0,1]

x_k是您的觀察值,y_k是您的濾波后的估計值。

然后,如果第一個原型產生了一些有用的結果,則您也許可以使用一些物理模型來獲得更好的估計量。 卡爾曼濾波器可以更好地利用您的基本物理現實。 但是為此,您首先需要了解如何為物理現實建模的想法。

https://en.wikipedia.org/wiki/Kalman_filter

在這里,您也許還可以找到有關跟蹤計算機視覺運動的更接近的示例: http : //www.diss.fu-berlin.de/docs/servlets/MCRFileNodeServlet/FUDOCS_derivate_000000000473/2005_12.pdf

所以這是我按照您告訴我的方法計算出的代碼:我創建了2個函數:

  • 如果幀之間的間隔不超過6個間隔,則將使用三次多項式進行插值。 否則它將按段進行插值。
  • 過濾也對段進行過濾。

目前,我還沒有嘗試過更改a的值以找到正確的值,但是絕對可以給我帶來很好的結果。

初步結果

def Interpolation(Frame, X, Y, Frequence = 2):
    """Fonction réalisant l'interpolation cubique des points manquants si possible, avec le découpage en segment si nécessaire."""

    # Détermination de la séparation entre les Frames pour la fréquence d'échantillonage choisie
    FPS = 30
    DT = FPS / Frequence

    # Initialisation
    i = 0

    # Détermination du début de l'interpolation
    try:
        while Frame[i+2] - Frame[i] != 2 * DT:
            i += 1
            continue
    except:
        print ("Erreur : Il est impossible de commencer l'interpolation.")

    # Suppresion des points antérieurs
    Frame = Frame[i:]
    X = X[i:]
    Y = Y[i:]

    k = 0
    Frame_id = list()
    # Recherche des segments
    for i in range(len(Frame) - 1):
        if Frame[i+1] - Frame[i] > 6 * DT:
            Frame_id.append((k, i))
            k = i + 1

    # Ajout du dernier segment
    if k != len(Frame) - 1:
        Frame_id.append((k, len(Frame)-1))

    # Suppresion des segments de moins de 3 points
    for k in reversed(range(len(Frame_id))):
        i = Frame_id[k][0]
        j = Frame_id[k][1]

        if j - i < 2:
            del Frame_id[k]
            continue

    Abs_inter, X_inter, Y_inter = [], [], []
    for index in Frame_id:
        i = index[0]
        j = index[1]

        # Génération des abscisses sur chaque segment, ainsi que des fonctions interpolés
        Abscisse = np.arange(Frame[i], Frame[j] + DT, DT)

        fX = interp1d(Frame[i:j+1], X[i:j+1], kind = 'cubic')
        fY = interp1d(Frame[i:j+1], Y[i:j+1], kind = 'cubic')

        # Génération des nouvelles coordonnées sur le segment
        Xnew = fX(Abscisse)
        Ynew = fY(Abscisse)

        Abs_inter += Abscisse.tolist()
        X_inter += Xnew.tolist()
        Y_inter += Ynew.tolist()

    # Création des listes résultats finaux
    Frame_final, X_final, Y_final = [], [], []

    Time = 0
    while Time <= Abs_inter[len(Abs_inter)-1]:
        if Time in Frame:
            Frame_final.append(Time)
            X_final.append(X[Frame.index(Time)])
            Y_final.append(Y[Frame.index(Time)])
            Time += DT
            continue
        elif Time in Abs_inter:
            Frame_final.append(Time)
            X_final.append(X_inter[Abs_inter.index(Time)])
            Y_final.append(Y_inter[Abs_inter.index(Time)])
            Time += DT
            continue
        else:
            Time += DT

    return (Frame_final, X_final, Y_final)

def Filtrage2(Frame, X, Y, DT = 15, a = 0.1):
    """Fonction réalisant un filtrage passe-bas d'ordre 1 du signal."""
    # Initialisation
    X_temp, Y_temp = [], []
    X_filter, Y_filter = [], []
    i = 1
    X_temp.append(X[0])
    Y_temp.append(Y[0])

    # Filtrage par morceau
    while i < len(Frame):

        while Frame[i] - Frame[i-1] == DT:
            Xnew = a * X[i-1] + (1 - a) * X_temp[len(X_temp)-1]
            Ynew = a * Y[i-1] + (1 - a) * Y_temp[len(Y_temp)-1]
            X_temp.append(Xnew)
            Y_temp.append(Ynew)
            if i < len(Frame)-1:
                i += 1
            else:
                break

        X_filter += X_temp
        Y_filter += Y_temp
        X_temp, Y_temp = [], []
        X_temp.append(X[i])
        Y_temp.append(Y[i])
        i += 1

    return (X_filter, Y_filter)

我也嘗試過在scipy庫中使用Butterworth過濾器,但無法正常工作。 這是我無法解決的代碼:

def Filtrage(Frame, X, Y, DT = 15, fc = 0.5, frequence = 2, order = 5):
    """Fonction réalisant un filtrage passe-bas du signal."""
    # Détermination du filtre
    nyq = 0.5 * frequence
    normal_cutoff = fc / nyq
    b, a = butter(order, normal_cutoff, btype = 'low', analog = False)

    # Filtrage par morceau
    X_temp, Y_temp = [], []
    X_filter, Y_filter = [], []

    # Initialisation
    X_temp.append(X[0])
    Y_temp.append(Y[0])
    i = 1

    while i < len(Frame):

        while Frame[i] - Frame[i-1] == DT:
            X_temp.append(X[i])
            Y_temp.append(Y[i])
            if i < len(Frame)-1:
                i += 1
            else:
                break

        X_filter += lfilter(b, a, X_temp).tolist()
        Y_filter += lfilter(b, a, Y_temp).tolist()
        X_temp, Y_temp = [], []
        X_temp.append(X[i])
        Y_temp.append(Y[i])
        i += 1

    return (X_filter, Y_filter)

如果您對如何使Butterworth發揮作用有任何想法,我將很高興聽到。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM