Analyse de données Kinect et Xsens

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.

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: 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 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)

Kinect

Les fichiers textes contenant les mesures prises par la kinect sont des fichier JSON structuré de la manière suivante 

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.

Le but est d'obtenir une matrice par axe de la forme: 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

Pour lire un fichier de données kinect on applique le code suivant:

Click to display ⇲

Click to hide ⇱

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 <frames>.

Puis on applique le code suivant pour lire les données:

Click to display ⇲

Click to hide ⇱

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

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.

Click to display ⇲

Click to hide ⇱

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:

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:

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.

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

Click to display ⇲

Click to hide ⇱

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()

  • poppy-kine/poppy-kine-2016-s5.txt
  • Last modified: 2019/04/25 14:08
  • (external edit)