Android Open Source - wiigee_android_test Quantizer






From Project

Back to project page wiigee_android_test.

License

The source code is released under:

GNU Lesser General Public License

If you think the Android project wiigee_android_test listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * wiigee - accelerometerbased gesture recognition
 * Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
 * //  w w  w.  ja  v  a  2 s  .co m
 * Developed at University of Oldenburg
 * Contact: wiigee@benjaminpoppinga.de
 *
 * This file is part of wiigee.
 *
 * wiigee is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package org.wiigee.logic;

import java.util.Vector;
import org.wiigee.event.AccelerationEvent;
import org.wiigee.util.Log;

/**
 * This class implements a quantization component. In this case a
 * k-mean-algorithm is used. In this case the initial values of the algorithm
 * are ordered as two intersected circles, representing an abstract globe with
 * k=14 elements. As a special feature the radius of this globe would be
 * calculated dynamically before the training of this component.
 * 
 * @author Benjamin 'BePo' Poppinga
 */
public class Quantizer {

  /** This is the initial radius of this model. */
  private double radius;

  /** Number of states from the following Hidden Markov Model */
  private int numStates;

  /** The representation of the so called Centeroids */
  private double[][] map;

  /** True, if map is already trained. */
  private boolean maptrained;

  /**
   * Initialize a empty quantizer. The states variable is necessary since some
   * algorithms need this value to calculate their values correctly.
   * 
   * @param numStates
   *            number of hidden markov model states
   */
  public Quantizer(int numStates) {
    this.numStates = numStates;
    this.map = new double[14][3];
    this.maptrained = false;
  }

  /**
   * 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) {
    Vector<AccelerationEvent> data = gesture.getData();
    double pi = Math.PI;
    this.radius = (gesture.getMaxAcceleration() + gesture
        .getMinAcceleration()) / 2;
    Log.write("Using radius: " + this.radius);

    // 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.size()];
    int[][] g = new int[this.map.length][data.size()];

    do {
      // Derive new Groups...
      g_alt = this.copyarray(g);
      g = this.deriveGroups(gesture);

      // calculate new centeroids
      for (int i = 0; i < this.map.length; i++) {
        double zaehlerX = 0;
        double zaehlerY = 0;
        double zaehlerZ = 0;
        int nenner = 0;
        for (int j = 0; j < data.size(); j++) {
          if (g[i][j] == 1) {
            zaehlerX += data.elementAt(j).getX();
            zaehlerY += data.elementAt(j).getY();
            zaehlerZ += data.elementAt(j).getZ();
            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.size();
     * j++) { Log.write(g[i][j] + "|"); } Log.write(""); }
     */

  }

  /**
   * This methods looks up a Gesture to a group matrix, used by the
   * k-mean-algorithm (traincenteroid method) above.
   * 
   * @param gesture
   *            the gesture
   */
  public int[][] deriveGroups(Gesture gesture) {
    Vector<AccelerationEvent> data = gesture.getData();
    int[][] groups = new int[this.map.length][data.size()];

    // Calculate cartesian distance
    double[][] d = new double[this.map.length][data.size()];
    double[] curr = new double[3];
    double[] vector = new double[3];
    for (int i = 0; i < this.map.length; i++) { // zeilen
      double[] ref = this.map[i];
      for (int j = 0; j < data.size(); j++) { // spalten

        curr[0] = data.elementAt(j).getX();
        curr[1] = data.elementAt(j).getY();
        curr[2] = data.elementAt(j).getZ();

        vector[0] = ref[0] - curr[0];
        vector[1] = ref[1] - curr[1];
        vector[2] = ref[2] - curr[2];
        d[i][j] = Math.sqrt((vector[0] * vector[0])
            + (vector[1] * vector[1]) + (vector[2] * vector[2]));
        // Log.write(d[i][j] + "|");
      }
      // Log.write("");
    }

    // look, to which group a value belongs
    for (int j = 0; j < data.size(); j++) {
      double smallest = Double.MAX_VALUE;
      int row = 0;
      for (int i = 0; i < this.map.length; i++) {
        if (d[i][j] < smallest) {
          smallest = d[i][j];
          row = i;
        }
        groups[i][j] = 0;
      }
      groups[row][j] = 1; // guppe gesetzt
    }

    // Debug output
    /*
     * for (int i = 0; i < groups.length; i++) { // zeilen for (int j = 0; j
     * < groups[i].length; j++) { Log.write(groups[i][j] + "|"); }
     * Log.write(""); }
     */

    return groups;

  }

  /**
   * 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);
    Vector<Integer> sequence = new Vector<Integer>();

    // Log.write("Visible symbol sequence: ");

    for (int j = 0; j < groups[0].length; j++) { // spalten
      for (int i = 0; i < groups.length; i++) { // zeilen
        if (groups[i][j] == 1) {
          // Log.write(" "+ i);
          sequence.add(i);
          break;
        }
      }
    }

    // die sequenz darf nicht zu kurz sein... mindestens so lang
    // wie die anzahl der zustnde. weil sonst die formeln nicht klappen.
    // english: 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.size() < this.numStates) {
      sequence.add(sequence.elementAt(sequence.size() - 1));
      // Log.write(" "+sequence.elementAt(sequence.size()-1));
    }

    // Log.write("");

    int[] out = new int[sequence.size()];
    for (int i = 0; i < sequence.size(); i++) {
      out[i] = sequence.elementAt(i);
    }

    return out;
  }

  /**
   * Prints out the current centeroids-map. Its for debug or technical
   * interests.
   */
  public void printMap() {
    Log.write("Centeroids:");
    for (int i = 0; i < this.map.length; i++) {
      Log.write(i + ". :" + this.map[i][0] + ":"
          + this.map[i][1] + ":" + this.map[i][2]);
    }
  }

  /**
   * Function to deepcopy an array.
   */
  private int[][] copyarray(int[][] alt) {
    int[][] neu = new int[alt.length][alt[0].length];
    for (int i = 0; i < alt.length; i++) {
      for (int j = 0; j < alt[i].length; j++) {
        neu[i][j] = alt[i][j];
      }
    }
    return neu;
  }

  /**
   * Function to look if the two arrays containing the same values.
   */
  private boolean equalarrays(int[][] one, int[][] two) {
    for (int i = 0; i < one.length; i++) {
      for (int j = 0; j < one[i].length; j++) {
        if (!(one[i][j] == two[i][j])) {
          return false;
        }
      }
    }
    return true;
  }

  public double getRadius() {
    return this.radius;
  }

  public double[][] getHashMap() {
    return this.map;
  }

  public void setUpManually(double[][] map, double radius) {
    this.map = map;
    this.radius = radius;
  }
}




Java Source Code List

asus4.wiigeeandroid.Logger.java
asus4.wiigeeandroid.MainActivity.java
org.wiigee.control.AndroidWiigee.java
org.wiigee.control.Wiigee.java
org.wiigee.device.AndroidDevice.java
org.wiigee.device.Device.java
org.wiigee.event.AccelerationEvent.java
org.wiigee.event.AccelerationListener.java
org.wiigee.event.ActionStartEvent.java
org.wiigee.event.ActionStopEvent.java
org.wiigee.event.ButtonListener.java
org.wiigee.event.ButtonPressedEvent.java
org.wiigee.event.ButtonReleasedEvent.java
org.wiigee.event.GestureEvent.java
org.wiigee.event.GestureListener.java
org.wiigee.event.MotionStartEvent.java
org.wiigee.event.MotionStopEvent.java
org.wiigee.filter.DirectionalEquivalenceFilter.java
org.wiigee.filter.Filter.java
org.wiigee.filter.HighPassFilter.java
org.wiigee.filter.IdleStateFilter.java
org.wiigee.filter.LowPassFilter.java
org.wiigee.filter.MotionDetectFilter.java
org.wiigee.logic.Classifier.java
org.wiigee.logic.GestureModel.java
org.wiigee.logic.Gesture.java
org.wiigee.logic.HMM.java
org.wiigee.logic.PreciseHMM.java
org.wiigee.logic.ProcessingUnit.java
org.wiigee.logic.Quantizer.java
org.wiigee.logic.TriggeredProcessingUnit.java
org.wiigee.util.FileIO.java
org.wiigee.util.Log.java