======Analyse de données Kinect et Xsens ======
{{tag>project poppy-kine}}
Cette page explique comment extraire la courbe de position d'un segment du corps à partir d'un enregistrement fait par la Kinect et par le Xsens et comment comparer le bruit des courbes de mouvement.
===== Obtenir les fichiers de données =====
{{tag>tutorial}}
Il faut réaliser l'enregistrement avec la kinect et le Xsens de manière simultanée pour que les courbes de mouvements correspondent.
==== Kinect ====
Pour enregistrer et obtenir le fichier de données des nouvements avec la kinect suivre le point 2.2.1 de la page:
[[poppy-kine:poppy-kine-2015-s5|http://wiki-robot.enstb.org/doku.php?id=poppy-kine-2015-s5]]
==== Xsens ====
Pour enregistrer avec le Xsens en utilisant MVN Studio suivre les explications de la page suivante [[sensors:x-sens|http://wiki-robot.enstb.org/doku.php?id=sensors:x-sens]]
Pour extraire le fichier de données de mouvement suivre les explications des vidéos suivantes:
[[https://tutorial.xsens.com/video/exporting-mvnx]] (Pour paramétrer les données à exporter)
[[https://tutorial.xsens.com/video/exporting-data]] (Pour exporter le fichier)
===== Structure des fichiers =====
{{tag>tutorial}}
==== Kinect ====
Les fichiers textes contenant les mesures prises par la kinect sont des fichier JSON structuré de la manière suivante {{ :jsonkinect.png?300 |}}
==== Xsens ====
Les fichiers mvnx contenant les données extraites du Xsens sont des fichiers XML structurés de la manière suivante :
-La première partie du fichier définit la position initiale des segments du corps.
-La seconde partie du fichier contient les données de position en tant que telles, organisées par type de données et par instant.
{{ :xmlxsens.png?300 |}}
===== Extraction des données =====
Le but est d'obtenir une matrice par axe de la forme:{{ :matriceres.png?300 |}}
Cette forme de matrice permettra de représenter la courbe de mouvement d'un segment du corps en fonction du temps et de réaliser des calculs pour évaluer le bruit.
Les fichiers de données issus de la Kinect et du Xsens étant différent il faut réaliser deux scripts python d'extraction différent.
==== Kinect ====
{{tag>software}}
Pour lire un fichier de données kinect on applique le code suivant:
import json
from pprint import pprint
from collections import OrderedDict
import matplotlib.pyplot as plt
import numpy as np
import sys, os
str = "%s/%s.%s"%("C:/Users/binou/Desktop/Kinect", sys.argv[1], "txt")
print str
with open(str) as data_file:
data = json.load(data_file, object_pairs_hook=OrderedDict)
#declaration des ordonnees
joints = ["Head", "Neck", "bSpine", "lAnkle", "lElbow", "lHand", "lHip",
"lKnee", "lShoulder", "lThumb", "lWrist", "mShoulder", "mSpine", "rAnkle",
"rElbow", "rHand", "rHip", "rKnee", "rShoulder", "rThumb", "rWrist"]
#declaration de l'abscisse
x = []
#Declaration d'une fonction permettant de lire les donnees de position
def LirePositionKinect():
#declaration des matrices de sortie
mat1 = []
mat2 = []
mat3 = []
#p sert a parcourir les lignes de la matrice resultat
p = 0
#On repere les valeurs des abscisses dans le jeu de donnees
for element in data["positions"]:
x.append(json.dumps(element).replace("\"", ""))
#On cherche ensuite les donnees par jointure
#Pour chaque instant capture
for i in x:
#On initialise les lignes a ajouter dans les matrices de resultat
y1 = []
y2 = []
y3 = []
#On ajoute un emplacement pour ajouter la ligne
mat1.append([])
mat2.append([])
mat3.append([])
#Pour chaque joint de l'instant capture
for j in joints:
#On ajoute les valeurs dans la ligne a inserer
y1.append(data["positions"][i][j][0])
y2.append(data["positions"][i][j][1])
y3.append(data["positions"][i][j][2])
#On ajoute la ligne dans la matrice resultat
mat1[p] += y1
mat2[p] += y2
mat3[p] += y3
#On incremente p pour passer a la ligne suivante
p += 1
#Convertion des listes en tableau et transposition
res1 = np.asarray(mat1).T
res2 = np.asarray(mat2).T
res3 = np.asarray(mat3).T
resx = np.asarray(x)
#On retourne les resultats
return res1, res2, res3, resx;
==== Xsens ====
Pour le Xsens il faut d'abord modifier le fichier.
Il faut tout d'abord l'enregistrer en tant que fichier XML, par exemple en l'ouvrant sous NotePad++, puis enregistrer sous.
Ensuite, il faut retirer la première partie qui définie les position initiales des segments, pour ne garder que ce qui est entre les balises .
Puis on applique le code suivant pour lire les données:
str = "%s.%s"%(sys.argv[1], "xml")
print str
tree = etree.parse(str)
#Declaration de la matrice en abscisse (le temps)
t = []
for frame in tree.xpath("/frames/frame"):
t.append(frame.get("index"))
root = tree.getroot()
#récupération des données d'orientation
def LirePositionXsens():
#declarations des matrice de sortie
mat1 = []
mat2 = []
mat3 = []
#p sert a parcourir les lignes de la matrice resultat
p = 0
#On initialise les lignes a ajouter dans les matrices de resultat
y1 = []
y2 = []
y3 = []
for i in range(2,len(t),1):
mat1.append([])
mat2.append([])
mat3.append([])
#Pour chaque segment de l'instant de capture
str = root[i][1].text.split()
#on remplis la matrice y1
for j in range(0,69,3):
#92 = nombe se seg * 4
y1.append(str[j])
#on remplis la matrice y2
for j in range(1,69,3):
#92 = nombe se seg * 4
y2.append(str[j])
#on remplis la matrice y3
for j in range(2,69,3):
#92 = nombe se seg * 4
y3.append(str[j])
mat1[p] += y1
del y1[:]
mat2[p] += y2
del y2[:]
mat3[p] += y3
del y3[:]
p +=1
res1 = np.array(mat1)
res2 = np.array(mat2)
res3 = np.array(mat3)
return res1, res2, res3
===== Affichage des courbes de mouvements =====
On cherche à afficher en simultané les courbes de mouvements de la kinect et du Xsens pour pouvoir les comparer.
Le code suivant permet d'afficher les courbes de mouvement pour un fichier dont le nom est passé en parmaètres dans la ligne de commande ainsi que le segment et l'axe voulu.
from LireXsens import LirePositionXsens, LireOrientationXsens, LireSegment
from LireKinect import LireOrientationKinect, LirePositionKinect
import matplotlib.pyplot as plt
import numpy as np
import sys, os
#declaration des joints de la kinect
joints = ["Head", "Neck", "bSpine", "lAnkle", "lElbow", "lHand", "lHip",
"lKnee", "lShoulder", "lThumb", "lWrist", "mShoulder", "mSpine", "rAnkle",
"rElbow", "rHand", "rHip", "rKnee", "rShoulder", "rThumb", "rWrist"]
#creation de dictionnaire pour associer au membre leur index
dicK={"Head":1, "Neck":2, "bSpine":3, "lAnkle":4, "lElbow":5, "lHand":6, "lHip":7,
"lKnee":8, "lShoulder":9, "lThumb":10, "lWrist":11, "mShoulder":12, "mSpine":13, "rAnkle":14,
"rElbow":15, "rHand":16, "rHip":17, "rKnee":18, "rShoulder":19, "rThumb":20, "rWrist":21}
dicX={'Pelvis':1, 'L5':2, 'L3':3, 'T12':4, 'T8':5, 'Neck':6, 'Head':7, 'rShoulder':8, 'rUpperArm':9,
'rForeArm':10, 'rHand':11, 'lShoulder':12, 'lUpperArm':13, 'lElbow':14, 'lHand':15,
'rUpperLeg':16, 'rLowerLeg':17, 'rtFoot':18, 'rToe':18, 'lUpperLeg':20, 'lLowerLeg':21, 'lFoot':22, 'lToe':23}
#On recupere les valeurs de orientation du Xsens
Xores1, Xores2, Xores3, Xores4, t = LireOrientationXsens();
#on transpose les matrice Xores
tXores1 = Xores1.T
tXores2 = Xores2.T
tXores3 = Xores3.T
tXores4 = Xores4.T
#On recupere les valeurs des positions
Xpres1, Xpres2, Xpres3= LirePositionXsens();
#on transpose les matrice Xpres
tXpres1 = Xpres1.T
tXpres2 = Xpres2.T
tXpres3 = Xpres3.T
#on enleve les index de pose de calibration
t.remove("-2")
t.remove("-3")
#On recupere les valeurs de position de la kinect
#Kores1, Kores2, Kores3, Kores4, Koresx = LireOrientationKinect();
#On recupere les valeurs de position de la kinect
Kpres1, Kpres2, Kpres3, Kpresx = LirePositionKinect();
#on plot la position du segments passe en parametre
if sys.argv[3] == "x":
plt.figure(1)
plt.subplot(211)
plt.plot(Kpresx, Kpres1[dicK.get(sys.argv[2])])
plt.title ("Kinect")
plt.subplot(212)
plt.plot(t, tXpres1[dicX.get(sys.argv[2])])
plt.title ("Xsens")
plt.show()
if sys.argv[3] == "y":
plt.figure(1)
plt.subplot(211)
plt.plot(Kpresx, Kpres2[dicK.get(sys.argv[2])])
plt.title ("Kinect")
plt.subplot(212)
plt.plot(t, tXpres2[dicX.get(sys.argv[2])])
plt.title ("Xsens")
plt.show()
if sys.argv[3] == "z":
plt.figure(1)
plt.subplot(211)
plt.plot(Kpresx, Kpres3[dicK.get(sys.argv[2])])
plt.title ("Kinect")
plt.subplot(212)
plt.plot(t, tXpres3[dicX.get(sys.argv[2])])
plt.title ("Xsens")
plt.show()
On exécute ce script dans la console:
{{ :script.png?300 |}}
Remarque: Il faut que les fichiers Kinect et Xsens aient le même nom (suivis de leur extension respective) et se trouve dans le même dossier que le script Afficher.py
Le fichier chris1_0 est un enregistrement d'un exercice où la personne lève le bras droit, puis le bras gauche, puis les deux.
On obtient le graphique suivant:
{{ :courbesmouvements.png?300 |}}
On remarque sur ce graphique que la courbe de mouvement issue des données de la kinect est plus bruitée que celle issue du Xsens. La prochaine étape sera de quantifier ce bruit.
===== Calcul du bruit =====
Pour évaluer le bruit nous allons réaliser deux calculs.
Le premier consiste à calculer le nombres de pics de bruit. Pour cela il faut tout d'abord fixer une valeur seuil. Si l'écart de valeur entre deux instant dépasse ce seuil alors on compte un pic. Plus le nombre de pic est élevé, plus le signal est bruité.
Le deuxième calcul consiste à faire le moyenne des valeurs de 5 points consécutifs et de comparer cette valeur à celle du point central (c'est à dire le troisième). Dans le cas idéal, les valeurs sont identique. En pratique, plus les valeurs sont éloignées, plus le signal est bruité.
On calcul aussi l'écart-type de l'écart entre le point central et la moyenne des 5 points.
Pour réaliser ces calculs sur un ensemble de fichier on applique les scripts python suivants.
==== Kinect ====
{{tag>software}}
from LireKinect import LirePositionKinect, LireOrientationKinect
import numpy as np
import os, sys
#creation de dictionnaire pour associer au membre leur index
dicK={"Head":1, "Neck":2, "bSpine":3, "lAnkle":4, "lElbow":5, "lHand":6, "lHip":7,
"lKnee":8, "lShoulder":9, "lThumb":10, "lWrist":11, "mShoulder":12, "mSpine":13, "rAnkle":14,
"rElbow":15, "rHand":16, "rHip":17, "rKnee":18, "rShoulder":19, "rThumb":20, "rWrist":21}
def moyenne(tableau):
return sum(tableau, 0.0) / len(tableau)
def variance(tableau):
m=moyenne(tableau)
return moyenne([(x-m)**2 for x in tableau])
def ecartype(tableau):
return variance(tableau)**0.5
#On creer une liste qui contient toutes les valeurs d'ecart type pour tous les fichier et tous les segments
#on fera le calcul de l'ecart type sur cette liste plus tard
listeEcartx = []
listeEcarty = []
listeEcartz = []
EcartMoyenSegmentx=[]
EcartMoyenSegmenty=[]
EcartMoyenSegmentz=[]
PicMoyenSegmentx=[]
PicMoyenSegmenty=[]
PicMoyenSegmentz=[]
for seg in range (1,21,1):
print seg
#On remplis une liste qui contient la valeur totale de pic pour chaque fichier
totpicx = []
totpicy = []
totpicz = []
totEcartMoyenx=[]
totEcartMoyeny=[]
totEcartMoyenz=[]
for element in os.listdir('C:/Users/binou/Desktop/Kinect'):
if element.endswith('.txt'):
#On recupere les valeurs de orientation de la kinect
#Kores1, Kores2, Kores3, Kores4, Koresx = LireOrientationKinect();
#On recupere les valeurs des positions
Kpres1, Kpres2, Kpres3, Kpresx = LirePositionKinect(element);
#compteur de pics
picx = 0
picy = 0
picz = 0
#suivant l'axe des x
for i in range(len(Kpresx) - 1):
if abs(Kpres1[seg][i+1] - Kpres1[seg][i]) >0.05:
picx += 1
#suivant l'axe des z
for i in range(len(Kpresx) - 1):
if abs(Kpres2[seg][i+1] - Kpres2[seg][i]) >0.05:
picy += 1
#suivant l'axe des z
for i in range(len(Kpresx) - 1):
if abs(Kpres3[seg][i+1] - Kpres3[seg][i]) >0.05:
picz += 1
totpicx.append(picx)
totpicy.append(picy)
totpicz.append(picz)
#faire la moyenne de 5 points
Mx = []
My = []
Mz = []
for i in range(2,len(Kpresx)-2,5):
Mx.append((Kpres1[seg][i-2]+Kpres1[seg][i-1]+Kpres1[seg][i]+Kpres1[seg][i+1]+Kpres1[seg][i+2])/5)
for i in range(2,len(Kpresx)-2,5):
My.append((Kpres2[seg][i-2]+Kpres2[seg][i-1]+Kpres2[seg][i]+Kpres2[seg][i+1]+Kpres2[seg][i+2])/5)
for i in range(2,len(Kpresx)-2,5):
Mz.append((Kpres3[seg][i-2]+Kpres3[seg][i-1]+Kpres3[seg][i]+Kpres3[seg][i+1]+Kpres3[seg][i+2])/5)
#On evalue l'ecart du point du milieu a la moyenne
ecartx = []
ecarty = []
ecartz = []
for i,j in zip(range (len(Mx)),range (3, len(Kpresx), 5)) :
ecartx.append(abs(Mx[i] - Kpres3[seg][j]))
listeEcartx.append(abs(Mx[i] - Kpres3[seg][j]))
for i,j in zip(range (len(My)),range (3, len(Kpresx), 5)) :
ecarty.append(abs(My[i] - Kpres3[seg][j]))
listeEcarty.append(abs(My[i] - Kpres3[seg][j]))
for i,j in zip(range (len(Mz)),range (3, len(Kpresx), 5)) :
ecartz.append(abs(Mz[i] - Kpres3[seg][j]))
listeEcartz.append(abs(Mz[i] - Kpres3[seg][j]))
#on calcul l'ecart moyen sur une courbe
EcartMoyenx = moyenne(ecartx)
EcartMoyeny = moyenne(ecarty)
EcartMoyenz = moyenne(ecartz)
totEcartMoyenx.append(EcartMoyenx)
totEcartMoyeny.append(EcartMoyeny)
totEcartMoyenz.append(EcartMoyenz)
#On remplis une liste qui contient les ecarts moyens de chaque segment
EcartMoyenSegmentx.append(moyenne(totEcartMoyenx))
EcartMoyenSegmenty.append(moyenne(totEcartMoyeny))
EcartMoyenSegmentz.append(moyenne(totEcartMoyenz))
#On remplis une liste qui contient le nombre moyen de pic de chaque segment
PicMoyenSegmentx.append(moyenne(totpicx))
PicMoyenSegmenty.append(moyenne(totpicy))
PicMoyenSegmentz.append(moyenne(totpicz))
#Moyenne globale des pics pour tout les fichiers et tout les segments
MoyenneGlobalePicx = moyenne (PicMoyenSegmentx)
MoyenneGlobalePicy = moyenne (PicMoyenSegmenty)
MoyenneGlobalePicz = moyenne (PicMoyenSegmentz)
#Moyenne globale des ecarts pour tout les fichiers et tout les segments
MoyenneGlobaleEcartx = moyenne (EcartMoyenSegmentx)
MoyenneGlobaleEcarty = moyenne (EcartMoyenSegmenty)
MoyenneGlobaleEcartz = moyenne (EcartMoyenSegmentz)
#On calcul l'ecart type de la serie d'ecart du point central
ETx = ecartype(listeEcartx)
ETy = ecartype(listeEcarty)
ETz = ecartype(listeEcartz)
fichier = open("Bruit_Moyen_Kinect.txt","w")
fichier.write("""------------------Ecart moyen entre le point central et la moyenne ------------------\n""")
fichier.write ("""%s = %s \n""" % ("Ecart Moyen suivant x", MoyenneGlobaleEcartx))
fichier.write ("""%s = %s \n""" % ("Ecart Moyen suivant y", MoyenneGlobaleEcarty))
fichier.write ("""%s = %s \n""" % ("Ecart Moyen suivant z", MoyenneGlobaleEcartz))
fichier.write ("""------------------Ecart type de l'ecart du point central a la moyenne------------------\n""")
fichier.write ("""%s = %s \n""" % ("Ecart Type suivant x", ETx))
fichier.write ("""%s = %s \n""" % ("Ecart Type suivant y", ETy))
fichier.write ("""%s = %s \n""" % ("EcartType suivant z", ETz))
fichier.write ("""------------------Nombre moyen de pic------------------\n""")
fichier.write ("""%s = %s \n""" % ("Nombre moyen de pic suivant x", MoyenneGlobalePicx))
fichier.write ("""%s = %s \n""" % ("Nombre moyen de pic suivant y", MoyenneGlobalePicy))
fichier.write ("""%s = %s \n""" % ("Nombre moyen de pic suivant z", MoyenneGlobalePicz))
fichier.close()
==== Xsens ====
Le code pour le Xsens est similaire à celui de la kinect. Il faut juste appeler LirePositionXsens () au lieu de LirePositionKinect()