public TriggeredProcessingUnit(bool autofilter) : base(autofilter) { this.learning = false; this.analyzing = false; this.current = new Gesture(); this.trainsequence = new List<Gesture>(); }
/** * Make a deep copy of another Gesture object. * * @param original Another Gesture object */ public Gesture(Gesture original) { this.data = new List<AccelerationVector>(); var origin = original.getData(); for (int i = 0; i < origin.Count; i++) { this.add((AccelerationVector)origin[i]); } }
private Gesture Circle() { var gesture = new Gesture(); var steps = Enumerable.Range(1, 100) .Select(i => 2 * Math.PI * i / 100.0) .Select(i => new AccelerationVector(-Math.Sin(i), -Math.Cos(i), -Math.Sin(i))); foreach (var s in steps) { gesture.add(s); } return gesture; }
/** * This method recognize a specific gesture, given to the procedure. * For classification a bayes classification algorithm is used. * * @param g gesture to classify */ public GestureModel classifyGesture(Gesture g) { // Calculate the denominator, Bayesian double sum = 0; foreach (var model in gesturemodel) { sum += model.DefaultProbability * model.GetMatchProbability(g); } GestureModel recognized = null; // which gesture has been recognized double recogprob = Int32.MinValue; // probability of this gesture double probgesture = 0; // temporal value for bayes algorithm double probmodel = 0; // temporal value for bayes algorithm foreach (var model in gesturemodel) { double tmpgesture = model.GetMatchProbability(g); double tmpmodel = model.DefaultProbability; if (((tmpmodel * tmpgesture) / sum) > recogprob) { probgesture = tmpgesture; probmodel = tmpmodel; recogprob = ((tmpmodel * tmpgesture) / sum); recognized = model; } } // a gesture could be recognized if (recogprob > 0 && probmodel > 0 && probgesture > 0 && sum > 0) { this.lastprob = recogprob; return recognized; } else { // no gesture could be recognized return null; } }
public void StopTraining() { if (this.learning) { if (this.current.getCountOfData() > 0) { Gesture gesture = new Gesture(this.current); this.trainsequence.Add(gesture); this.current = new Gesture(); } this.learning = false; } }
public void StopRecognition() { if (this.analyzing) { if (this.current.getCountOfData() > 0) { Gesture gesture = new Gesture(this.current); var recognized = this.classifier.classifyGesture(gesture); if (recognized != null) { double recogprob = this.classifier.getLastProbability(); this.OnGestureRecognized(recognized, recogprob); } else { this.OnGestureRecognized(null, 0.0); // No gesture recognized } this.current = new Gesture(); } this.analyzing = false; } }
/** * With this method you can transform a gesture to a discrete symbol * sequence with values between 0 and granularity (number of observations). * * @param gesture * Gesture to get the observationsequence to. */ public int[] getObservationSequence(Gesture gesture) { int[,] groups = this.deriveGroups(gesture); List<int> sequence = new List<int>(); for (int j = 0; j < groups.GetLength(1); j++) { // spalten for (int i = 0; i < groups.GetLength(0); i++) { // zeilen if (groups[i,j] == 1) { sequence.Add(i); break; } } } // this is very dirty! it have to be here because if not // too short sequences would cause an error. i've to think about a // better resolution than copying the old value a few time. while (sequence.Count < this.numStates) { sequence.Add(sequence[sequence.Count - 1]); } int[] output = new int[sequence.Count]; for (int i = 0; i < sequence.Count; i++) { output[i] = sequence[i]; } return output; }
/** * This methods looks up a Gesture to a group matrix, used by the * k-mean-algorithm (traincenteroid method) above. * * @param gesture * the gesture */ private int[,] deriveGroups(Gesture gesture) { List<AccelerationVector> data = gesture.getData(); int[,] groups = new int[this.map.Length, data.Count]; // Calculate cartesian distance double[,] d = new double[this.map.Length, data.Count]; double[] curr = new double[3]; double[] vector = new double[3]; for (int i = 0; i < this.map.Length; i++) { // lines var line = this.map[i]; for (var j = 0; j < data.Count; j++) { // split var accel = data[j]; curr[0] = accel.X; curr[1] = accel.Y; curr[2] = accel.Z; vector[0] = line[0] - curr[0]; vector[1] = line[1] - curr[1]; vector[2] = line[2] - curr[2]; d[i,j] = Math.Sqrt((vector[0] * vector[0]) + (vector[1] * vector[1]) + (vector[2] * vector[2])); } } // look, to which group a value belongs for (int j = 0; j < data.Count; j++) { double smallest = Double.MaxValue; int row = 0; for (int i = 0; i < this.map.GetLength(0); i++) { if (d[i, j] < smallest) { smallest = d[i, j]; row = i; } groups[i, j] = 0; } groups[row, j] = 1; // group set } return groups; }
/** * Trains this Quantizer with a specific gesture. This means that the * positions of the centeroids would adapt to this training gesture. In our * case this would happen with a summarized virtual gesture, containing all * the other gestures. * * @param gesture * the summarized virtual gesture */ public void trainCenteroids(Gesture gesture) { List<AccelerationVector> data = gesture.getData(); double pi = Math.PI; this.radius = (gesture.getMaxAcceleration() + gesture.getMinAcceleration()) / 2; // x , z , y if (!this.maptrained) { this.maptrained = true; this.map[0] = new double[] { this.radius, 0.0, 0.0 }; this.map[1] = new double[] { Math.Cos(pi / 4) * this.radius, 0.0, Math.Sin(pi / 4) * this.radius }; this.map[2] = new double[] { 0.0, 0.0, this.radius }; this.map[3] = new double[] { Math.Cos(pi * 3 / 4) * this.radius, 0.0, Math.Sin(pi * 3 / 4) * this.radius }; this.map[4] = new double[] { -this.radius, 0.0, 0.0 }; this.map[5] = new double[] { Math.Cos(pi * 5 / 4) * this.radius, 0.0, Math.Sin(pi * 5 / 4) * this.radius }; this.map[6] = new double[] { 0.0, 0.0, -this.radius }; this.map[7] = new double[] { Math.Cos(pi * 7 / 4) * this.radius, 0.0, Math.Sin(pi * 7 / 4) * this.radius }; this.map[8] = new double[] { 0.0, this.radius, 0.0 }; this.map[9] = new double[] { 0.0, Math.Cos(pi / 4) * this.radius, Math.Sin(pi / 4) * this.radius }; this.map[10] = new double[] { 0.0, Math.Cos(pi * 3 / 4) * this.radius, Math.Sin(pi * 3 / 4) * this.radius }; this.map[11] = new double[] { 0.0, -this.radius, 0.0 }; this.map[12] = new double[] { 0.0, Math.Cos(pi * 5 / 4) * this.radius, Math.Sin(pi * 5 / 4) * this.radius }; this.map[13] = new double[] { 0.0, Math.Cos(pi * 7 / 4) * this.radius, Math.Sin(pi * 7 / 4) * this.radius }; } int[,] g_alt = new int[this.map.Length, data.Count]; int[,] g = new int[this.map.Length, data.Count]; do { // Derive new Groups... g_alt = this.copyarray(g); g = this.deriveGroups(gesture); // calculate new centeroids for (int i = 0; i < this.map.GetLength(0); i++) { double zaehlerX = 0; double zaehlerY = 0; double zaehlerZ = 0; int nenner = 0; for (int j = 0; j < data.Count; j++) { if (g[i,j] == 1) { var e = data[j]; zaehlerX += e.X; zaehlerY += e.Y; zaehlerZ += e.Z; nenner++; } } if (nenner > 1) { // nur wenn der nenner>0 oder >1??? ist muss // was // geaendert werden // Log.write("Setze neuen Centeroid!"); this.map[i] = new double[] {(zaehlerX / (double) nenner), (zaehlerY / (double) nenner), (zaehlerZ / (double) nenner) }; // Log.write("Centeroid: "+i+": "+newcenteroid[0]+":"+newcenteroid[1]); } } // new centeroids } while (!equalarrays(g_alt, g)); // Debug: Printout groups /* * for (int i = 0; i < n; i++) { for (int j = 0; j < this.data.Count; * j++) { Log.write(g[i][j] + "|"); } Log.write(""); } */ }
/** * Trains the model to a set of motion-sequences, representing * different evaluations of a gesture * * @param trainsequence a vector of gestures */ public void Train(IEnumerable<Gesture> trainsequence) { // summarize all vectors from the different gestures in one // gesture called sum. double maxacc = 0; double minacc = 0; Gesture sum = new Gesture(); foreach (var gesture in trainsequence) { IEnumerable<AccelerationVector> t = gesture.getData(); // add the max and min acceleration, we later get the average maxacc += gesture.getMaxAcceleration(); minacc += gesture.getMinAcceleration(); // transfer every single accelerationevent of each gesture to // the new gesture sum foreach (var accelerationEvent in t) { sum.add(accelerationEvent); } } // get the average and set it to the sum gesture sum.setMaxAndMinAcceleration(maxacc / trainsequence.Count(), minacc / trainsequence.Count()); // train the centeroids of the quantizer with this master gesture sum. this.quantizer.trainCenteroids(sum); // convert gesture vector to a sequence of discrete values var seqs = new List<int[]>(); foreach (var gesture in trainsequence) { seqs.Add(this.quantizer.getObservationSequence(gesture)); } // train the markov model with this derived discrete sequences this.markovmodell.train(seqs); // set the default probability for use with the bayes classifier this.SetDefaultProbability(trainsequence); }
/** * Returns the probability that a gesture matches to this * gesture model. * * @param gesture a gesture to test. * @return probability that the gesture belongs to this gesture * model. */ public double GetMatchProbability(Gesture gesture) { int[] sequence = quantizer.getObservationSequence(gesture); return this.markovmodell.getProbability(sequence); }