/**
  * First quantizes the feature vector against codebook, and then runs viterbi decoding
  *
  * @param rf
  * @return
  */
 public String recognizeGesture(RawFeature rf) {
   codebook = new Codebook();
   GestureFeature[] gestureFeatures = getFeature(rf);
   Points[] pts = getPointsFromFeatureVector(gestureFeatures);
   int[] quantized = codebook.quantize(pts);
   String[] regGestures = readRegGestureModels();
   HiddenMarkov[] hmms = new HiddenMarkov[regGestures.length];
   // read hmms
   for (int i = 0; i < hmms.length; i++) {
     hmms[i] = new HiddenMarkov(regGestures[i]);
   }
   // find likelihood by viterbi decoding of quantized seq
   double[] likelihoods = new double[regGestures.length];
   for (int j = 0; j < likelihoods.length; j++) {
     likelihoods[j] = hmms[j].viterbi(quantized);
   }
   // find the largest likelihood
   double highest = Double.NEGATIVE_INFINITY;
   int wordIndex = -1;
   for (int j = 0; j < regGestures.length; j++) {
     if (likelihoods[j] > highest) {
       highest = likelihoods[j];
       wordIndex = j;
     }
   }
   // best matched
   return regGestures[wordIndex];
 }
 /**
  * Performs hmm train for all training data set.<br>
  * First quantizes the feature vector against codebook, and then train baum-welch
  *
  * @return
  */
 public boolean trainHMM() {
   boolean operationSuccess = false;
   codebook = new Codebook();
   database.setMode(DBMode.TRAINDATA);
   Model[][] regModels = database.readAllDataofCurrentMode();
   String[] gestName = database.getRegisteredModelNames();
   int quantizedSeq[][];
   HiddenMarkov mkv = new HiddenMarkov(NUM_STATES, NUM_SYMBOLS);
   // for each gesture
   for (int i = 0; i < regModels.length; i++) {
     operationSuccess = false;
     // for each train sample of current gesture
     quantizedSeq = new int[regModels[i].length][];
     for (int j = 0; j < regModels[i].length; j++) {
       GestureFeature[] gf = getFeature((RawFeature) regModels[i][j]);
       Points[] pts = getPointsFromFeatureVector(gf);
       quantizedSeq[j] = codebook.quantize(pts);
     }
     mkv.setTrainSeq(quantizedSeq);
     mkv.train();
     mkv.save(gestName[i]);
     operationSuccess = true;
   }
   return operationSuccess;
 }