Middleware :
Began to create a curve segmenter based on cutting on local extremums.
Remove joint arguments on hand quit events to notify Processing when skeleton is not detected anymore.
/*
* This file is part of the TraKERS\Middleware package.
*
* (c) IRI <http://www.iri.centrepompidou.fr/>
*
* For the full copyright and license information, please view the LICENSE_MIDDLEWARE
* file that was distributed with this source code.
*/
/*
* Projet : TraKERS
* Module : MIDDLEWARE
* Sous-Module : Search
* Classe : Segmenter
*
* Auteur : alexandre.bastien@iri.centrepompidou.fr
*
* Fonctionnalités : Permet d'extraire à la volée les segments du tracé en cours.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Media3D;
namespace Trakers.Tracking.Search
{
public class Segmenter
{
//Accès à la classe de détection principale pour les paramètres.
private KinectMain kinectMain;
//Stocke les positions d'une main au cours du temps.
private List<Point3D> handPointerHistory;
//Point précédent.
private Point3D prevPt;
//Ratio : on prend 1/ratio points.
private int ratio;
//Indique le numéro du point actuellement enregistré (pour le ratio).
private int currentPointNumber;
//Extremums enregistrés parmi les 3 axes pour détecter les changements de sens.
private double Xmax, Ymax, Zmax;
private double Xmin, Ymin, Zmin;
//On établit une distance en nombre de points entre le point actuel l'extremum
//local détecté dans les 3 axes (pour copier le segment : points de 0 à id de l'extremum).
private int distToXmax, distToYmax, distToZmax;
private int distToXmin, distToYmin, distToZmin;
//Points critiques.
private Point3D minPt, maxPt;
//Tendance actuelle du tracé.
private bool XtowardRight, YtowardUp, ZtowardFront;
//Limites de différences à partir desquelles .
private int directionChangeTresholdXY;
private float directionChangeTresholdZ;
/*
* Initialisation du segmenter.
* Coupe une courbe en deux dès qu'il repère un changement important de trajectoire.
*/
public Segmenter(int _ratio, KinectMain _kinectMain)
{
kinectMain = _kinectMain;
directionChangeTresholdXY = kinectMain.getDirectionChangeTresholdXY();
directionChangeTresholdZ = kinectMain.getDirectionChangeTresholdZ();
handPointerHistory = new List<Point3D>();
ratio = _ratio;
currentPointNumber = 1;
prevPt = new Point3D(0, 0, 0);
Xmax = Ymax = Zmax = Xmin = Ymin = Zmin = -1;
distToXmax = distToYmax = distToZmax = distToXmin = distToYmin = distToZmin = -1;
}
/*
* Getters et setters.
*/
public void SetRatio(int _ratio)
{
ratio = _ratio;
}
public void SetDirectionChangeTresholdXY(int _directionChangeTresholdXY)
{
directionChangeTresholdXY = _directionChangeTresholdXY;
}
public void SetDirectionChangeTresholdZ(float _directionChangeTresholdZ)
{
directionChangeTresholdZ = _directionChangeTresholdZ;
}
public int GetRatio()
{
return ratio;
}
public int SetDirectionChangeTresholdXY()
{
return directionChangeTresholdXY;
}
public float SetDirectionChangeTresholdZ()
{
return directionChangeTresholdZ;
}
/*
* On charge tous les paramètres d'un coup.
*/
public void setParams(int _ratio, int _directionChangeTresholdXY, float _directionChangeTresholdZ)
{
ratio = _ratio;
directionChangeTresholdXY = _directionChangeTresholdXY;
directionChangeTresholdZ = _directionChangeTresholdZ;
}
/*
* Enregistre le point passé en paramètre d'après le ratio.
*/
public void RecordPoint(Point3D pt)
{
//Indique l'ID du point à couper.
int whereToCut;
//Si le ratio est excédé, on peut enregistrer.
if (currentPointNumber > ratio)
currentPointNumber = 1;
//Si le point précédent est à une position différente du point actuel.
if(prevPt.X != pt.X || prevPt.Y != pt.Y || prevPt.Z != pt.Z)
{
//Si le numéro est 1 (début ou ratio atteint), on enregistre.
if(currentPointNumber == 1)
handPointerHistory.Add(pt);
//Si le point précédent a été initialisé avec un vrai point.
if (prevPt.X > 0 && prevPt.Y > 0 && prevPt.Z > 0)
{
//Appel aux detecteurs d'extremums.
if ((whereToCut = DetectDirectionChangeAtXAxis(pt)) > 0)
Segment(whereToCut);
else if((whereToCut = DetectDirectionChangeAtYAxis(pt)) > 0)
Segment(whereToCut);
else if ((whereToCut = DetectDirectionChangeAtZAxis(pt)) > 0)
Segment(whereToCut);
}
//On met à jour le point précédent.
prevPt = pt;
//On passe au numéro suivant (jusqu'à atteindre le ration plus tard).
currentPointNumber++;
}
}
/*
* Détecte un changement de sens (extremum) dans l'axe X.
*/
public int DetectDirectionChangeAtXAxis(Point3D pt)
{
//ID où couper en cas d'extremum.
int whereToCut = -1;
//Mise à jour des extremums.
if (Xmax == -1 || Xmax < pt.X)
{
//Si le point est plus grand en X que Xmax, alors il est remplacé et on réinitialise la
//distance au dernier maximum en X.
Xmax = pt.X;
maxPt = pt;
distToXmax = 0;
}
else
distToXmax++;
if (Xmin == -1 || Xmin > pt.X)
{
//Si le point est plus petit en X que Xmin, alors il est remplacé et on réinitialise la
//distance au dernier minimum en X.
Xmin = pt.X;
minPt = pt;
distToXmin = 0;
}
else
distToXmin++;
//Si X max est plus grand que la position actuelle additionnée du seuil
//et que l'extremum n'est pas le premier point sauvegardé.
if (Xmax > pt.X + directionChangeTresholdXY && maxPt != handPointerHistory.First())
whereToCut = currentPointNumber - distToXmax;
//Si X min est plus petit que la position actuelle à laquelle on a retiré le seuil
//et que l'extremum n'est pas le premier point sauvegardé.
if (Xmin < pt.X - directionChangeTresholdXY && minPt != handPointerHistory.First())
whereToCut = currentPointNumber - distToXmin;
return whereToCut;
}
/*
* Détecte un changement de sens (extremum) dans l'axe Y.
*/
public int DetectDirectionChangeAtYAxis(Point3D pt)
{
//ID où couper en cas d'extremum.
int whereToCut = -1;
//Mise à jour des extremums.
if (Ymax == -1 || Ymax < pt.Y)
{
//Si le point est plus grand en Y que Ymax, alors il est remplacé et on réinitialise la
//distance au dernier maximum en Y.
Ymax = pt.Y;
maxPt = pt;
distToYmax = 0;
}
else
distToYmax++;
if (Ymin == -1 || Ymin > pt.Y)
{
//Si le point est plus petit en Y que Ymin, alors il est remplacé et on réinitialise la
//distance au dernier minimum en Y.
Ymin = pt.Y;
minPt = pt;
distToYmin = 0;
}
else
distToYmin++;
//Si Y max est plus grand que la position actuelle additionnée du seuil
//et que l'extremum n'est pas le premier point sauvegardé.
if (Ymax > pt.Y + directionChangeTresholdXY && maxPt != handPointerHistory.First())
whereToCut = currentPointNumber - distToYmax;
//Si Y min est plus petit que la position actuelle à laquelle on a retiré le seuil
//et que l'extremum n'est pas le premier point sauvegardé.
if (Ymin < pt.Y - directionChangeTresholdXY && minPt != handPointerHistory.First())
whereToCut = currentPointNumber - distToYmin;
return whereToCut;
}
/*
* Détecte un changement de sens (extremum) dans l'axe Z.
*/
public int DetectDirectionChangeAtZAxis(Point3D pt)
{
//ID où couper en cas d'extremum.
int whereToCut = -1;
//Mise à jour des extremums.
if (Zmax == -1 || Zmax < pt.Z)
{
//Si le point est plus grand en Z que Ymax, alors il est remplacé et on réinitialise la
//distance au dernier maximum en Z.
Zmax = pt.Z;
maxPt = pt;
distToZmax = 0;
}
else
distToZmax++;
if (Zmin == -1 || Zmin > pt.Z)
{
//Si le point est plus petit en Z que Zmin, alors il est remplacé et on réinitialise la
//distance au dernier minimum en Z.
Zmin = pt.Z;
minPt = pt;
distToZmin = 0;
}
else
distToZmin++;
//Si Z max est plus grand que la position actuelle additionnée du seuil
//et que l'extremum n'est pas le premier point sauvegardé.
if (Zmax > pt.Z + directionChangeTresholdXY && maxPt != handPointerHistory.First())
whereToCut = currentPointNumber - distToZmax;
//Si Z min est plus petit que la position actuelle à laquelle on a retiré le seuil
//et que l'extremum n'est pas le premier point sauvegardé.
if (Zmin < pt.Z - directionChangeTresholdXY && minPt != handPointerHistory.First())
whereToCut = currentPointNumber - distToZmin;
return whereToCut;
}
/*
* Découpe le tracé en cours en segment allant du premier point au premier extremum trouvé.
*/
public void Segment(int whereToCut)
{
handPointerHistory.RemoveRange(0, whereToCut);
currentPointNumber -= whereToCut;
}
}
}