Let me first explain my goal and my problem. I have an object moving in circle inside of a bocal (a mice to be precise), and I need to know how many rotation it does in one minute. The movement isn't a perfect circle, and can be chaotic. It can stopped for several seconds, and start again moving.
But what I know, is that I have between 3 and 20 rotation per minute => Low frequency (between 0.05 Hz and 0.33 Hz).
I'm filming this object with a 30 fps camera during 30 minutes. With Python and OpenCV, I manage to extract the (X,Y) coordinates. Since 30 fps is a bit high for the frequency I'm looking for, I selected one frame on 15 in order to have a sampling frequency of 2 Hz.
The first problem, is that sometimes, I'm missing a point because OpenCV couldn't find the object. This is a problem I can't solve, since the point I'm tracking with an HSV color mask is sometimes hidden.
In fact, the data I have to filter are :
For instance, I have this kind of list :
This is the king of movement I get, as you can see, I need to filter the high frequency.
And now my problem : Even if I have some basics in filtering and coding, I don't know how to do it, and which library to use. I've read that scipy should have all the required function, but I don't know which one to use, and how.
I'm not sure, but I think I should do something like this :
Could you please tell me if I'm right, and point me in the right direction for the coding part ?
Thanks for the help,
Mathieu
答案 0 :(得分:0)
在深入研究傅立叶变换之前,您可以应用一阶或二阶低通滤波器。您可以先对数据进行线性插值,以便频率恒定为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
答案 1 :(得分:0)
所以这里是我用你告诉我的代码编写的代码: 我创建了两个函数:
目前,我还没有尝试更改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工作有任何想法,我会很高兴听到它。