GestureRecognitionToolkit  Version: 0.2.5
The Gesture Recognition Toolkit (GRT) is a cross-platform, open-source, c++ machine learning library for real-time gesture recognition.
ParticleClassifierParticleFilter.h
1 /*
2 GRT MIT License
3 Copyright (c) <2012> <Nicholas Gillian, Media Lab, MIT>
4 
5 Permission is hereby granted, free of charge, to any person obtaining a copy of this software
6 and associated documentation files (the "Software"), to deal in the Software without restriction,
7 including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in all copies or substantial
12 portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 */
20 
21 #ifndef GRT_PARTICLE_CLASSIFIER_PARTICLE_FILTER_HEADER
22 #define GRT_PARTICLE_CLASSIFIER_PARTICLE_FILTER_HEADER
23 
24 #include "../../CoreAlgorithms/ParticleFilter/ParticleFilter.h"
25 
26 GRT_BEGIN_NAMESPACE
27 
29  public:
31  classLabel = 0;
32  }
33 
35 
36  }
37 
38  unsigned int getLength() const {
39  return timeseries.getNumRows();
40  }
41 
42  unsigned int classLabel;
43  MatrixFloat timeseries;
44 };
45 
46 class ParticleClassifierParticleFilter : public ParticleFilter< Particle,VectorFloat > {
47 
48 public:
50  setEstimationMode( WEIGHTED_MEAN );
51  clear();
52  }
53 
55 
56  }
57 
58  virtual bool preFilterUpdate( VectorFloat &data ){
59 
60  //Randomly reset a small number of particles to ensure the classifier does not get stuck on one gesture
61  unsigned int numRandomFlipParticles = 0;//(unsigned int)floor( processNoise[0] * Float(numParticles) );
62 
63  for(unsigned int i=0; i<numRandomFlipParticles; i++){
64  //unsigned int randomParticleIndex = rand.getRandomNumberInt(0, numParticles);
65  unsigned int randomParticleIndex = i;
66 
67  particles[ randomParticleIndex ].x[0] = rand.getRandomNumberInt(0, numTemplates); //Randomly pick a template
68  particles[ randomParticleIndex ].x[1] = rand.getRandomNumberUniform(0,1); //Randomly pick a phase
69  particles[ randomParticleIndex ].x[2] = 0; //rand.getRandomNumberUniform(-processNoise[2],processNoise[2]); //Randomly pick a speed
70  }
71 
72  return true;
73  }
74 
75  virtual bool postFilterUpdate( VectorFloat &data ){
76 
77  return true;
78  }
79 
80  virtual bool predict( Particle &p ){
81 
82  //Given the prior set of particles, randomly generate new state estimations using the process model
83  const Float phase = p.x[1];
84 
85  //Update the phase
86  p.x[1] = Util::limit( phase + rand.getRandomNumberGauss(0.0,processNoise[1]) , 0, 1);
87 
88  //Update the velocity
89  p.x[2] += phase-p.x[1];
90 
91  //Limit the velocity
92  p.x[2] = Util::limit( p.x[2], -processNoise[2], processNoise[2] );
93 
94  return true;
95  }
96 
97  virtual bool update( Particle &p, VectorFloat &data ){
98 
99  //Generate the weights for the current particle
100  p.w = 1;
101 
102  //Get the gesture template
103  const unsigned int templateIndex = (unsigned int)p.x[0];
104 
105  if( templateIndex >= numTemplates ){
106  errorLog << "update( Particle &p, VectorFloat &data ) - Template index out of bounds! templateIndex: " << templateIndex << std::endl;
107  return false;
108  }
109 
110  //Get the current position in the template
111  const unsigned int templateLength = gestureTemplates[templateIndex].timeseries.getNumRows();
112  const unsigned int templatePos = (unsigned int)(p.x[1] * Float(templateLength-1));
113 
114  if( templatePos >= templateLength ){
115  errorLog << "update( Particle &p, VectorFloat &data ) - Template position out of bounds! templatePos: " << templatePos << " templateLength: " << templateLength << std::endl;
116  return false;
117  }
118 
119  for(unsigned int j=0; j<numInputDimensions; j++){
120  p.w *= gauss( data[j], gestureTemplates[templateIndex].timeseries[templatePos][j], measurementNoise[j] );
121  }
122 
123  return true;
124  }
125 
126  virtual bool clear(){
127 
128  //Clear the base class
130 
131  numInputDimensions = 0;
132  numTemplates = 0;
133  numClasses = 0;
134  resampleCounter = 0;
135  gestureTemplates.clear();
136 
137  return true;
138  }
139 
140  bool train( const unsigned int numParticles, const TimeSeriesClassificationData &trainingData, Float sensorNoise, Float transitionSigma, Float phaseSigma, Float velocitySigma){
141 
142  //Clear any previous model
143  clear();
144 
145  this->numParticles = numParticles;
146  numInputDimensions = trainingData.getNumDimensions();
147  numTemplates = trainingData.getNumSamples();
148  numClasses = trainingData.getNumClasses();
149 
150  gestureTemplates.resize( numTemplates );
151  for(unsigned int i=0; i<numTemplates; i++){
152  gestureTemplates[i].classLabel = trainingData[i].getClassLabel();
153  gestureTemplates[i].timeseries = trainingData[i].getData();
154  }
155 
156  //Init the particle filter
157  //State vector is:
158  //[0] gesture template index
159  //[1] phase (position within the template, normalized [0 1])
160  //[2] velocity (value between [-0.2 0.2])
161  stateVectorSize = 3;
162  initModel.resize( stateVectorSize, VectorFloat(2,0) );
163  processNoise.resize( stateVectorSize );
164  measurementNoise.resize( numInputDimensions );
165 
166  //Min state range
167  initModel[0][0] = 0;
168  initModel[1][0] = 0;
169  initModel[2][0] = -0.2;
170 
171  //Max state range
172  initModel[0][1] = numTemplates;
173  initModel[1][1] = 1;
174  initModel[2][1] = 0.2;
175 
176  //Set the measurement noise - this sets the sigma difference between the estimated position in the template and sensor input
177  for(unsigned int i=0; i<numInputDimensions; i++){
178  measurementNoise[i] = sensorNoise;
179  }
180 
181  //Set the process noise used for the
182  processNoise[0] = transitionSigma; //Controls the random template selection
183  processNoise[1] = phaseSigma; //Controls the phase update
184  processNoise[2] = velocitySigma; //Controls the maximum velocity update
185 
186  x.resize( stateVectorSize );
187  initialized = true;
188 
189  if( !initParticles( numParticles ) ){
190  errorLog << "ERROR: Failed to init particles!" << std::endl;
191  clear();
192  return false;
193  }
194 
195  return true;
196  }
197 
198  /*
199  virtual bool checkForResample(){
200  if( ++resampleCounter >= 100 ){
201  resampleCounter = 0;
202  return true;
203  }
204  return false;
205  }
206  */
207 
208  unsigned int numInputDimensions;
209  unsigned int numTemplates;
210  unsigned int numClasses;
211  unsigned int resampleCounter;
213 
214 };
215 
216 GRT_END_NAMESPACE
217 
218 #endif //GRT_PARTICLE_CLASSIFIER_PARTICLE_FILTER_HEADER
219 
virtual bool preFilterUpdate(VectorFloat &data)
virtual bool update(Particle &p, VectorFloat &data)
unsigned int getNumRows() const
Definition: Matrix.h:574
virtual bool clear()
static Float limit(const Float value, const Float minValue, const Float maxValue)
Definition: Util.cpp:172
virtual bool postFilterUpdate(VectorFloat &data)