GestureRecognitionToolkit  Version: 1.0 Revision: 04-03-15
The Gesture Recognition Toolkit (GRT) is a cross-platform, open-source, c++ machine learning library for real-time gesture recognition.
ParticleClassifier.cpp
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 #include "ParticleClassifier.h"
22 
23 namespace GRT{
24 
25 //Register the ParticleClassifier module with the Classifier base class
26 RegisterClassifierModule< ParticleClassifier > ParticleClassifier::registerModule("ParticleClassifier");
27 
28 ParticleClassifier::ParticleClassifier( const unsigned int numParticles,const double sensorNoise,const double transitionSigma,const double phaseSigma,const double velocitySigma )
29 {
30  this->numParticles = numParticles;
31  this->sensorNoise = sensorNoise;
32  this->transitionSigma = transitionSigma;
33  this->phaseSigma = phaseSigma;
34  this->velocitySigma = velocitySigma;
35  useNullRejection = true;
36  supportsNullRejection = true;
37  classType = "ParticleClassifier";
38  classifierType = classType;
39  classifierMode = TIMESERIES_CLASSIFIER_MODE;
40  debugLog.setProceedingText("[DEBUG ParticleClassifier]");
41  errorLog.setProceedingText("[ERROR ParticleClassifier]");
42  trainingLog.setProceedingText("[TRAINING ParticleClassifier]");
43  warningLog.setProceedingText("[WARNING ParticleClassifier]");
44 }
45 
47  *this = rhs;
48 }
49 
51 {
52 }
53 
55 
56  if( this != &rhs ){
57 
58  this->numParticles = rhs.numParticles;
59  this->sensorNoise = rhs.sensorNoise;
60  this->transitionSigma = rhs.transitionSigma;
61  this->phaseSigma = rhs.phaseSigma;
62  this->velocitySigma = rhs.velocitySigma;
63  this->particleFilter = rhs.particleFilter;
64 
65  //Copy the classifier variables
66  copyBaseVariables( (Classifier*)&rhs );
67  }
68  return *this;
69 }
70 
72  if( classifier == NULL ) return false;
73 
74  if( this->getClassifierType() == classifier->getClassifierType() ){
75  ParticleClassifier *ptr = (ParticleClassifier*)classifier;
76 
77  this->numParticles = ptr->numParticles;
78  this->sensorNoise = ptr->sensorNoise;
79  this->transitionSigma = ptr->transitionSigma;
80  this->phaseSigma = ptr->phaseSigma;
81  this->velocitySigma = ptr->velocitySigma;
82  this->particleFilter = ptr->particleFilter;
83 
84  //Copy the classifier variables
85  return copyBaseVariables( classifier );
86  }
87  return false;
88 }
89 
91 
92  clear();
93 
94  numClasses = trainingData.getNumClasses();
95  numInputDimensions = trainingData.getNumDimensions();
96  ranges = trainingData.getRanges();
97 
98  //Scale the training data if needed
99  if( useScaling ){
100  trainingData.scale(0, 1);
101  }
102 
103  //Train the particle filter
104  particleFilter.train( numParticles, trainingData, sensorNoise, transitionSigma, phaseSigma, velocitySigma );
105 
106  classLabels.resize(numClasses);
107  classLikelihoods.resize(numClasses,0);
108  classDistances.resize(numClasses,0);
109 
110  for(unsigned int i=0; i<numClasses; i++){
111  classLabels[i] = trainingData.getClassTracker()[i].classLabel;
112  }
113 
114  trained = true;
115 
116  return trained;
117 }
118 
119 bool ParticleClassifier::predict_( VectorDouble &inputVector ){
120 
121  if( !trained ){
122  errorLog << "predict_(VectorDouble &inputVector) - The model has not been trained!" << endl;
123  return false;
124  }
125 
126  if( numInputDimensions != inputVector.size() ){
127  errorLog << "predict_(VectorDouble &inputVector) - The number of features in the model " << numInputDimensions << " does not match that of the input vector " << inputVector.size() << endl;
128  return false;
129  }
130 
131  //Scale the input data if needed
132  if( useScaling ){
133  for(unsigned int j=0; j<numInputDimensions; j++){
134  inputVector[j] = scale(inputVector[j],ranges[j].minValue,ranges[j].maxValue,0,1);
135  }
136  }
137 
138  predictedClassLabel = 0;
139  maxLikelihood = 0;
140  std::fill(classLikelihoods.begin(),classLikelihoods.end(),0);
141  std::fill(classDistances.begin(),classDistances.end(),0);
142 
143  //Update the particle filter
144  particleFilter.filter( inputVector );
145 
146  //Count the number of particles per class
147  unsigned int gestureTemplate = 0;
148  unsigned int gestureLabel = 0;
149  unsigned int gestureIndex = 0;
150  for(unsigned int i=0; i<numParticles; i++){
151  gestureTemplate = (unsigned int)particleFilter[i].x[0]; //The first element in the state vector is the gesture template index
152  gestureLabel = particleFilter.gestureTemplates[ gestureTemplate ].classLabel;
153  gestureIndex = getClassLabelIndexValue( gestureLabel );
154 
155  classDistances[ gestureIndex ] += particleFilter[i].w;
156  }
157 
158  bool rejectPrediction = false;
159  if( useNullRejection ){
160  if( particleFilter.getWeightSum() < 1.0e-5 ){
161  rejectPrediction = true;
162  }
163  }
164 
165  //Compute the class likelihoods
166  for(unsigned int i=0; i<numClasses; i++){
167 
168  classLikelihoods[ i ] = rejectPrediction ? 0 : classDistances[i];
169 
170  if( classLikelihoods[i] > maxLikelihood ){
171  predictedClassLabel = classLabels[i];
172  maxLikelihood = classLikelihoods[i];
173  }
174  }
175 
176  //Estimate the phase
177  phase = particleFilter.getStateEstimation()[1]; //The 2nd element in the state vector is the estimatied phase
178 
179  return true;
180 
181 }
182 
184 
186 
187  particleFilter.clear();
188 
189  return true;
190 }
191 
193 
195 
196  particleFilter.reset();
197 
198  return true;
199 }
200 
201 bool ParticleClassifier::saveModelToFile(fstream &file) const{
202 
203  if(!file.is_open())
204  {
205  errorLog <<"saveModelToFile(fstream &file) - The file is not open!" << endl;
206  return false;
207  }
208 
209 
210 
211  return true;
212 }
213 
215 
216  clear();
217 
218  if(!file.is_open())
219  {
220  errorLog << "loadModelFromFile(string filename) - Could not open file to load model" << endl;
221  return false;
222  }
223 
224 
225 
226  //Flag that the model is trained
227  trained = true;
228 
229  //Resize the prediction results to make sure it is setup for realtime prediction
230  maxLikelihood = DEFAULT_NULL_LIKELIHOOD_VALUE;
231  bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
232  classLikelihoods.resize(numClasses,DEFAULT_NULL_LIKELIHOOD_VALUE);
233  classDistances.resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
234 
235  return true;
236 }
237 
238 const vector< ParticleClassifierGestureTemplate >& ParticleClassifier::getGestureTemplates() const{
239  return particleFilter.gestureTemplates;
240 }
241 
242 const ParticleClassifierParticleFilter& ParticleClassifier::getParticleFilter() const {
243  return particleFilter;
244 }
245 
246 VectorDouble ParticleClassifier::getStateEstimation() const{
247  return particleFilter.getStateEstimation();
248 }
249 
250 double ParticleClassifier::getPhase() const{
251  if( trained ){
252  return particleFilter.getStateEstimation()[1];
253  }
254  return 0;
255 }
256 
257 double ParticleClassifier::getVelocity() const{
258  if( trained ){
259  return particleFilter.getStateEstimation()[2];
260  }
261  return 0;
262 }
263 
264 bool ParticleClassifier::setNumParticles(const unsigned int numParticles){
265 
266  clear();
267 
268  this->numParticles = numParticles;
269 
270  return true;
271 }
272 
273 bool ParticleClassifier::setSensorNoise(const unsigned int sensorNoise){
274 
275  clear();
276 
277  this->sensorNoise = sensorNoise;
278 
279  return true;
280 }
281 
282 bool ParticleClassifier::setTransitionSigma(const unsigned int transitionSigma){
283 
284  clear();
285 
286  this->transitionSigma = transitionSigma;
287 
288  return true;
289 }
290 
291 bool ParticleClassifier::setPhaseSigma(const unsigned int phaseSigma){
292 
293  clear();
294 
295  this->phaseSigma = phaseSigma;
296 
297  return true;
298 }
299 
300 bool ParticleClassifier::setVelocitySigma(const unsigned int velocitySigma){
301 
302  clear();
303 
304  this->velocitySigma = velocitySigma;
305 
306  return true;
307 }
308 
309 
310 } //End of namespace GRT
311 
VectorDouble getStateEstimation() const
bool copyBaseVariables(const Classifier *classifier)
Definition: Classifier.cpp:91
Definition: AdaBoost.cpp:25
ParticleClassifier(const unsigned int numParticles=2000, const double sensorNoise=20.0, const double transitionSigma=0.005, const double phaseSigma=0.1, const double velocitySigma=0.01)
virtual bool saveModelToFile(fstream &file) const
virtual bool loadModelFromFile(fstream &file)
double scale(const double &x, const double &minSource, const double &maxSource, const double &minTarget, const double &maxTarget, const bool constrain=false)
Definition: MLBase.h:339
UINT getClassLabelIndexValue(UINT classLabel) const
Definition: Classifier.cpp:193
double getWeightSum() const
bool scale(const double minTarget, const double maxTarget)
virtual bool reset()
Definition: Classifier.cpp:121
vector< ClassTracker > getClassTracker() const
virtual bool clear()
Definition: Classifier.cpp:140
virtual bool train_(TimeSeriesClassificationData &trainingData)
string getClassifierType() const
Definition: Classifier.cpp:159
virtual bool deepCopyFrom(const Classifier *classifier)
ParticleClassifier & operator=(const ParticleClassifier &rhs)
virtual bool predict_(VectorDouble &inputVector)
virtual bool filter(SENSOR_DATA &data)