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.
GestureRecognitionPipeline.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 
22 
23 namespace GRT{
24 
26 {
27  initialized = false;
28  trained = false;
29  info = "";
30  pipelineMode = PIPELINE_MODE_NOT_SET;
31  inputVectorDimensions = 0;
32  outputVectorDimensions = 0;
33  predictedClassLabel = 0;
34  predictedClusterLabel = 0;
35  predictionModuleIndex = 0;
36  numTrainingSamples = 0;
37  numTestSamples = 0;
38  testAccuracy = 0;
39  testRMSError = 0;
40  testSquaredError = 0;
41  testRejectionPrecision = 0;
42  testRejectionRecall = 0;
43  testTime = 0;
44  trainingTime = 0;
45  classifier = NULL;
46  regressifier = NULL;
47  clusterer = NULL;
48  contextModules.resize( NUM_CONTEXT_LEVELS );
49 
50  debugLog.setProceedingText("[DEBUG GRP]");
51  errorLog.setProceedingText("[ERROR GRP]");
52  warningLog.setProceedingText("[WARNING GRP]");
53  testingLog.setProceedingText("[TEST GRP]");
54 }
55 
57 
58  initialized = false;
59  trained = false;
60  info = "";
61  pipelineMode = PIPELINE_MODE_NOT_SET;
62  inputVectorDimensions = 0;
63  outputVectorDimensions = 0;
64  predictedClassLabel = 0;
65  predictedClusterLabel = 0;
66  predictionModuleIndex = 0;
67  numTrainingSamples = 0;
68  numTestSamples = 0;
69  testAccuracy = 0;
70  testRMSError = 0;
71  testSquaredError = 0;
72  testRejectionPrecision = 0;
73  testRejectionRecall = 0;
74  testTime = 0;
75  trainingTime = 0;
76  classifier = NULL;
77  regressifier = NULL;
78  clusterer = NULL;
79  contextModules.resize( NUM_CONTEXT_LEVELS );
80 
81  debugLog.setProceedingText("[DEBUG GRP]");
82  errorLog.setProceedingText("[ERROR GRP]");
83  warningLog.setProceedingText("[WARNING GRP]");
84  testingLog.setProceedingText("[TEST GRP]");
85 
86  //Invoke the equals operator to copy the rhs data to this instance
87  *this = rhs;
88 }
89 
90 
92 
93  if( this != &rhs ){
94  this->clearAll();
95 
96  //Copy the pipeline variables
97  this->initialized = rhs.initialized;
98  this->trained = rhs.trained;
99  this->info = rhs.info;
100  this->inputVectorDimensions = rhs.inputVectorDimensions;
101  this->outputVectorDimensions = rhs.outputVectorDimensions;
102  this->predictedClassLabel = rhs.predictedClassLabel;
103  this->predictedClusterLabel = rhs.predictedClusterLabel;
104  this->pipelineMode = rhs.pipelineMode;
105  this->predictionModuleIndex = rhs.predictionModuleIndex;
106  this->numTrainingSamples = rhs.numTrainingSamples;
107  this->numTestSamples = rhs.numTestSamples;
108  this->testAccuracy = rhs.testAccuracy;
109  this->testRMSError = rhs.testRMSError;
110  this->testSquaredError = rhs.testSquaredError;
111  this->testTime = rhs.testTime;
112  this->trainingTime = rhs.trainingTime;
113  this->testFMeasure = rhs.testFMeasure;
114  this->testPrecision = rhs.testPrecision;
115  this->testRecall = rhs.testRecall;
116  this->regressionData = rhs.regressionData;
117  this->testRejectionPrecision = rhs.testRejectionPrecision;
118  this->testRejectionRecall = rhs.testRejectionRecall;
119  this->testConfusionMatrix = rhs.testConfusionMatrix;
120  this->crossValidationResults = rhs.crossValidationResults;
121  this->testResults = rhs.testResults;
122 
123  //Copy the GRT Base variables
124  this->debugLog = rhs.debugLog;
125  this->errorLog = rhs.errorLog;
126  this->trainingLog = rhs.trainingLog;
127  this->testingLog = rhs.testingLog;
128  this->warningLog = rhs.warningLog;
129 
130  for(unsigned int i=0; i<rhs.preProcessingModules.size(); i++){
131  this->addPreProcessingModule( *(rhs.preProcessingModules[i]) );
132  }
133 
134  for(unsigned int i=0; i<rhs.featureExtractionModules.size(); i++){
135  this->addFeatureExtractionModule( *(rhs.featureExtractionModules[i]) );
136  }
137 
139  setClassifier( *rhs.classifier );
140  }
141 
142  if( rhs.getIsPipelineInRegressionMode() ){
143  setRegressifier( *rhs.regressifier );
144  }
145 
146  if( rhs.getIsClustererSet() ){
147  setClusterer( *rhs.clusterer );
148  }
149 
150  for(unsigned int i=0; i<rhs.postProcessingModules.size(); i++){
151  this->addPostProcessingModule( *(rhs.postProcessingModules[i]) );
152  }
153 
154  for(unsigned int k=0; k<NUM_CONTEXT_LEVELS; k++){
155  for(unsigned int i=0; i<rhs.contextModules[k].size(); i++){
156  this->addContextModule( *(rhs.contextModules[k][i]), k );
157  }
158  }
159 
160  //Adding the modules will automatically set trained to false, so make sure we get the correct state
161  this->trained = rhs.trained;
162  }
163 
164  return *this;
165 }
166 
168 {
169  //Clean up the memory
170  deleteAllPreProcessingModules();
171  deleteAllFeatureExtractionModules();
172  deleteClassifier();
173  deleteRegressifier();
174  deleteClusterer();
175  deleteAllPostProcessingModules();
176  deleteAllContextModules();
177 }
178 
180 
181  trained = false;
182  trainingTime = 0;
184 
185  if( !getIsClassifierSet() ){
186  errorLog << "train(ClassificationData trainingData) - Failed To Train Classifier, the classifier has not been set!" << endl;
187  return false;
188  }
189 
190  if( trainingData.getNumSamples() == 0 ){
191  errorLog << "train(ClassificationData trainingData) - Failed To Train Classifier, there is no training data!" << endl;
192  return false;
193  }
194 
195  //Reset all the modules
196  reset();
197 
198  //Set the input vector dimension size
199  inputVectorDimensions = trainingData.getNumDimensions();
200 
201  //Pass the training data through any pre-processing or feature extraction units
202  UINT numDimensions = trainingData.getNumDimensions();
203 
204  //If there are any preprocessing or feature extraction modules, then get the size of the last module
207  numDimensions = featureExtractionModules[ featureExtractionModules.size()-1 ]->getNumOutputDimensions();
208  }else{
209  numDimensions = preProcessingModules[ preProcessingModules.size()-1 ]->getNumOutputDimensions();
210  }
211  }
212 
213  //Start the training timer
214  Timer timer;
215  timer.start();
216 
217  ClassificationData processedTrainingData( numDimensions );
218 
219  for(UINT i=0; i<trainingData.getNumSamples(); i++){
220  bool okToAddProcessedData = true;
221  UINT classLabel = trainingData[i].getClassLabel();
222  VectorDouble trainingSample = trainingData[i].getSample();
223 
224  //Perform any preprocessing
225  if( getIsPreProcessingSet() ){
226  for(UINT moduleIndex=0; moduleIndex<preProcessingModules.size(); moduleIndex++){
227  if( !preProcessingModules[moduleIndex]->process( trainingSample ) ){
228  errorLog << "train(ClassificationData trainingData) - Failed to PreProcess Training Data. PreProcessingModuleIndex: ";
229  errorLog << moduleIndex;
230  errorLog << endl;
231  return false;
232  }
233  trainingSample = preProcessingModules[moduleIndex]->getProcessedData();
234  }
235  }
236 
237  //Compute any features
239  for(UINT moduleIndex=0; moduleIndex<featureExtractionModules.size(); moduleIndex++){
240  if( !featureExtractionModules[moduleIndex]->computeFeatures( trainingSample ) ){
241  errorLog << "train(ClassificationData trainingData) - Failed to Compute Features from Training Data. FeatureExtractionModuleIndex ";
242  errorLog << moduleIndex;
243  errorLog << endl;
244  return false;
245  }
246  if( featureExtractionModules[moduleIndex]->getFeatureDataReady() ){
247  trainingSample = featureExtractionModules[moduleIndex]->getFeatureVector();
248  }else{
249  okToAddProcessedData = false;
250  break;
251  }
252  }
253  }
254 
255  if( okToAddProcessedData ){
256  //Add the training sample to the processed training data
257  processedTrainingData.addSample(classLabel, trainingSample);
258  }
259 
260  }
261 
262  if( processedTrainingData.getNumSamples() != trainingData.getNumSamples() ){
263 
264  warningLog << "train(ClassificationData trainingData) - Lost " << trainingData.getNumSamples()-processedTrainingData.getNumSamples() << " of " << trainingData.getNumSamples() << " training samples due to the processing stage!" << endl;
265  }
266 
267  //Store the number of training samples
268  numTrainingSamples = processedTrainingData.getNumSamples();
269 
270  //Train the classifier
271  trained = classifier->train_( processedTrainingData );
272  if( !trained ){
273  errorLog << "train(ClassificationData trainingData) - Failed To Train Classifier: " << classifier->getLastErrorMessage() << endl;
274  return false;
275  }
276 
277  //Store the training time
278  trainingTime = timer.getMilliSeconds();
279 
280  return true;
281 }
282 
283 bool GestureRecognitionPipeline::train(const ClassificationData &trainingData,const UINT kFoldValue,const bool useStratifiedSampling){
284 
285  trained = false;
286  trainingTime = 0;
288 
289  if( !getIsClassifierSet() ){
290  errorLog << "train(const ClassificationData &trainingData,const UINT kFoldValue,const bool useStratifiedSampling) - Failed To Train Classifier, the classifier has not been set!" << endl;
291  return false;
292  }
293 
294  if( trainingData.getNumSamples() == 0 ){
295  errorLog << "train(const ClassificationData &trainingData,const UINT kFoldValue,const bool useStratifiedSampling) - Failed To Train Classifier, there is no training data!" << endl;
296  return false;
297  }
298 
299  //Reset all the modules
300  reset();
301 
302  //Start the training timer
303  Timer timer;
304  timer.start();
305 
306  //Get a copy of the data so we can spilt it
307  ClassificationData data = trainingData;
308 
309  //Spilt the data into K folds
310  bool spiltResult = data.spiltDataIntoKFolds(kFoldValue, useStratifiedSampling);
311 
312  if( !spiltResult ){
313  return false;
314  }
315 
316  //Run the k-fold training and testing
317  double crossValidationAccuracy = 0;
318  ClassificationData foldTrainingData;
319  ClassificationData foldTestData;
320  vector< TestResult > cvResults(kFoldValue);
321 
322  for(UINT k=0; k<kFoldValue; k++){
324  foldTrainingData = data.getTrainingFoldData(k);
325 
326  if( !train( foldTrainingData ) ){
327  return false;
328  }
329 
330  //Test the classification system
331  foldTestData = data.getTestFoldData(k);
332 
333  if( !test( foldTestData ) ){
334  return false;
335  }
336 
337  crossValidationAccuracy += getTestAccuracy();
338  cvResults[k] = getTestResults();
339  }
340 
341  //Flag that the model has been trained
342  trained = true;
343 
344  //Set the accuracy of the classification system averaged over the kfolds
345  testAccuracy = crossValidationAccuracy / double(kFoldValue);
346  crossValidationResults = cvResults;
347 
348  //Store the training time
349  trainingTime = timer.getMilliSeconds();
350 
351  return true;
352 }
353 
355 
356  trained = false;
357  trainingTime = 0;
359 
360  if( !getIsClassifierSet() ){
361  errorLog << "train(const TimeSeriesClassificationData &trainingData) - Failed To Train Classifier, the classifier has not been set!" << endl;
362  return false;
363  }
364 
365  if( trainingData.getNumSamples() == 0 ){
366  errorLog << "train(TimeSeriesClassificationData trainingData) - Failed To Train Classifier, there is no training data!" << endl;
367  return false;
368  }
369 
370  //Reset all the modules
371  reset();
372 
373  //Start the training timer
374  Timer timer;
375  timer.start();
376 
377  //Set the input vector dimension size of the pipeline
378  inputVectorDimensions = trainingData.getNumDimensions();
379 
380  TimeSeriesClassificationData processedTrainingData( trainingData.getNumDimensions() );
381  TimeSeriesClassificationData timeseriesClassificationData;
382  ClassificationData classificationData;
383 
384  bool allowNullGestureClass = true;
385  processedTrainingData.setAllowNullGestureClass( allowNullGestureClass );
386  timeseriesClassificationData.setAllowNullGestureClass( allowNullGestureClass );
387  classificationData.setAllowNullGestureClass( allowNullGestureClass );
388 
389  //Setup the data structure, if the classifier works with timeseries data then we use TimeSeriesClassificationData
390  //otherwise we format the data as ClassificationData
391  if( classifier->getTimeseriesCompatible() ){
392  UINT trainingDataInputDimensionSize = trainingData.getNumDimensions();
393  if( getIsPreProcessingSet() ){
394  trainingDataInputDimensionSize = preProcessingModules[ preProcessingModules.size()-1 ]->getNumOutputDimensions();
395  }
397  trainingDataInputDimensionSize = featureExtractionModules[ featureExtractionModules.size()-1 ]->getNumOutputDimensions();
398  }
399  timeseriesClassificationData.setNumDimensions( trainingDataInputDimensionSize );
400  }else{
401  UINT trainingDataInputDimensionSize = trainingData.getNumDimensions();
402  if( getIsPreProcessingSet() ){
403  trainingDataInputDimensionSize = preProcessingModules[ preProcessingModules.size()-1 ]->getNumOutputDimensions();
404  }
406  trainingDataInputDimensionSize = featureExtractionModules[ featureExtractionModules.size()-1 ]->getNumOutputDimensions();
407  }
408  classificationData.setNumDimensions( trainingDataInputDimensionSize );
409  }
410 
411  //Pass the timeseries data through any pre-processing modules and add it to the processedTrainingData structure
412  for(UINT i=0; i<trainingData.getNumSamples(); i++){
413  UINT classLabel = trainingData[i].getClassLabel();
414  MatrixDouble trainingSample = trainingData[i].getData();
415 
416  if( getIsPreProcessingSet() ){
417 
418  //Try to process the matrix data row-by-row
419  bool resetPreprocessingModule = true;
420  for(UINT r=0; r<trainingSample.getNumRows(); r++){
421  VectorDouble sample = trainingSample.getRowVector( r );
422 
423  for(UINT moduleIndex=0; moduleIndex<preProcessingModules.size(); moduleIndex++){
424 
425  if( resetPreprocessingModule ){
426  preProcessingModules[moduleIndex]->reset();
427  }
428 
429  //Validate the input and output dimensions match!
430  if( preProcessingModules[moduleIndex]->getNumInputDimensions() != preProcessingModules[moduleIndex]->getNumOutputDimensions() ){
431  errorLog << "train(TimeSeriesClassificationData trainingData) - Failed To PreProcess Training Data. The number of inputDimensions (";
432  errorLog << preProcessingModules[moduleIndex]->getNumInputDimensions();
433  errorLog << ") in PreProcessingModule ";
434  errorLog << moduleIndex;
435  errorLog << " do not match the number of outputDimensions (";
436  errorLog << preProcessingModules[moduleIndex]->getNumOutputDimensions();
437  errorLog << endl;
438  return false;
439  }
440 
441  if( !preProcessingModules[moduleIndex]->process( sample ) ){
442  errorLog << "train(TimeSeriesClassificationData trainingData) - Failed To PreProcess Training Data. PreProcessingModuleIndex: ";
443  errorLog << moduleIndex;
444  errorLog << endl;
445  return false;
446  }
447  sample = preProcessingModules[moduleIndex]->getProcessedData();
448  }
449 
450  //The preprocessing modules should only be reset when r==0
451  resetPreprocessingModule = false;
452 
453  //Overwrite the original training sample with the preProcessed sample
454  for(UINT c=0; c<sample.size(); c++){
455  trainingSample[r][c] = sample[c];
456  }
457  }
458 
459  }
460 
461  //Add the training sample to the processed training data
462  processedTrainingData.addSample(classLabel,trainingSample);
463  }
464 
465  //Loop over the processed training data, perfrom any feature extraction if needed
466  //Add the data to either the timeseries or classification data structures
467  for(UINT i=0; i<processedTrainingData.getNumSamples(); i++){
468  UINT classLabel = processedTrainingData[i].getClassLabel();
469  MatrixDouble trainingSample = processedTrainingData[i].getData();
470  bool featureDataReady = false;
471  bool resetFeatureExtractionModules = true;
472 
473  VectorDouble inputVector;
474  MatrixDouble featureData;
475  //Try to process the matrix data row-by-row
476  for(UINT r=0; r<trainingSample.getNumRows(); r++){
477  inputVector = trainingSample.getRowVector( r );
478  featureDataReady = true;
479 
480  //Pass the processed training data through the feature extraction
482 
483  for(UINT moduleIndex=0; moduleIndex<featureExtractionModules.size(); moduleIndex++){
484 
485  if( resetFeatureExtractionModules ){
486  featureExtractionModules[moduleIndex]->reset();
487  }
488 
489  if( !featureExtractionModules[moduleIndex]->computeFeatures( inputVector ) ){
490  errorLog << "train(TimeSeriesClassificationData trainingData) - Failed To Compute Features For Training Data. FeatureExtractionModuleIndex: ";
491  errorLog << moduleIndex;
492  errorLog << endl;
493  return false;
494  }
495 
496  //Overwrite the input vector with the features so this can either be input to the next feature module
497  //or converted to the LabelledClassificationData format
498  inputVector = featureExtractionModules[moduleIndex]->getFeatureVector();
499  featureDataReady = featureExtractionModules[moduleIndex]->getFeatureDataReady();
500  }
501 
502  //The feature extraction modules should only be reset on r == 0
503  resetFeatureExtractionModules = false;
504 
505  if( featureDataReady ){
506 
507  if( classifier->getTimeseriesCompatible() ){
508  if( !featureData.push_back( inputVector ) ){
509  errorLog << "train(TimeSeriesClassificationData trainingData) - Failed To add feature vector to feature data matrix! FeatureExtractionModuleIndex: " << endl;
510  return false;
511  }
512  }else classificationData.addSample(classLabel, inputVector);
513  }
514 
515  }else{
516  if( classifier->getTimeseriesCompatible() ){
517  if( !featureData.push_back( inputVector ) ){
518  errorLog << "train(TimeSeriesClassificationData trainingData) - Failed To add feature vector to feature data matrix! FeatureExtractionModuleIndex: " << endl;
519  return false;
520  }
521  }
522  else classificationData.addSample(classLabel, inputVector);
523  }
524  }
525 
526  if( classifier->getTimeseriesCompatible() ) timeseriesClassificationData.addSample(classLabel, featureData);
527 
528  }
529 
530  //Train the classification system
531  if( classifier->getTimeseriesCompatible() ){
532  numTrainingSamples = timeseriesClassificationData.getNumSamples();
533  trained = classifier->train( timeseriesClassificationData );
534  }else{
535  numTrainingSamples = classificationData.getNumSamples();
536  trained = classifier->train( classificationData );
537  }
538 
539  if( !trained ){
540  errorLog << "train(TimeSeriesClassificationData trainingData) - Failed To Train Classifier" << classifier->getLastErrorMessage() << endl;
541  return false;
542  }
543 
544  //Store the training time
545  trainingTime = timer.getMilliSeconds();
546 
547  return true;
548 }
549 
550 bool GestureRecognitionPipeline::train(const TimeSeriesClassificationData &trainingData,const UINT kFoldValue,const bool useStratifiedSampling){
551 
552  trained = false;
553  trainingTime = 0;
555 
556  if( !getIsClassifierSet() ){
557  errorLog << "train(const TimeSeriesClassificationData &trainingData,const UINT kFoldValue,const bool useStratifiedSampling) - Failed To Train Classifier, the classifier has not been set!" << endl;
558  return false;
559  }
560 
561  if( trainingData.getNumSamples() == 0 ){
562  errorLog << "train(const TimeSeriesClassificationData &trainingData,const UINT kFoldValue,const bool useStratifiedSampling) - Failed To Train Classifier, there is no training data!" << endl;
563  return false;
564  }
565 
566  //Reset all the modules
567  reset();
568 
569  //Start the training timer
570  Timer timer;
571  timer.start();
572 
573  //Get a copy of the data so we can split it
574  TimeSeriesClassificationData data = trainingData;
575 
576  //Spilt the data into K folds
577  if( !data.spiltDataIntoKFolds(kFoldValue, useStratifiedSampling) ){
578  errorLog << "train(const TimeSeriesClassificationData &trainingData,const UINT kFoldValue,const bool useStratifiedSampling) - Failed To Spilt Dataset into KFolds!" << endl;
579  return false;
580  }
581 
582  //Run the k-fold training and testing
583  double crossValidationAccuracy = 0;
584  TimeSeriesClassificationData foldTrainingData;
585  TimeSeriesClassificationData foldTestData;
586 
587  for(UINT k=0; k<kFoldValue; k++){
589  foldTrainingData = data.getTrainingFoldData(k);
590 
591  if( !train( foldTrainingData ) ){
592  errorLog << "train(const TimeSeriesClassificationData &trainingData,const UINT kFoldValue,const bool useStratifiedSampling) - Failed to train pipeline for fold " << k << "." << endl;
593  return false;
594  }
595 
596  //Test the classification system
597  foldTestData = data.getTestFoldData(k);
598 
599  if( !test( foldTestData ) ){
600  errorLog << "train(const TimeSeriesClassificationData &trainingData,const UINT kFoldValue,const bool useStratifiedSampling) - Failed to test pipeline for fold " << k << "." << endl;
601  return false;
602  }
603 
604  crossValidationAccuracy += getTestAccuracy();
605  }
606 
607  //Flag that the model has been trained
608  trained = true;
609 
610  //Set the accuracy of the classification system averaged over the kfolds
611  testAccuracy = crossValidationAccuracy / double(kFoldValue);
612 
613  //Store the training time
614  trainingTime = timer.getMilliSeconds();
615 
616  return true;
617 }
618 
620 
621  trained = false;
622  trainingTime = 0;
624 
625  //Reset all the modules
626  reset();
627 
628  //Start the training timer
629  Timer timer;
630  timer.start();
631 
632  //Set the input vector dimension size
633  inputVectorDimensions = trainingData.getNumInputDimensions();
634 
635  //Pass the training data through any pre-processing or feature extraction units
636  RegressionData processedTrainingData;
637 
638  //Set the dimensionality of the data
639  UINT numInputs = 0;
640  UINT numTargets = trainingData.getNumTargetDimensions();
642  numInputs = trainingData.getNumInputDimensions();
643  }else{
644 
646  numInputs = preProcessingModules[ preProcessingModules.size()-1 ]->getNumOutputDimensions();
647  }
648 
650  numInputs = featureExtractionModules[ featureExtractionModules.size()-1 ]->getNumOutputDimensions();
651  }
652 
654  numInputs = featureExtractionModules[ featureExtractionModules.size()-1 ]->getNumOutputDimensions();
655  }
656  }
657 
658  processedTrainingData.setInputAndTargetDimensions(numInputs, numTargets);
659 
660  for(UINT i=0; i<trainingData.getNumSamples(); i++){
661  VectorDouble inputVector = trainingData[i].getInputVector();
662  VectorDouble targetVector = trainingData[i].getTargetVector();
663 
664  if( getIsPreProcessingSet() ){
665  for(UINT moduleIndex=0; moduleIndex<preProcessingModules.size(); moduleIndex++){
666  if( !preProcessingModules[ moduleIndex ]->process( inputVector ) ){
667  errorLog << "train(const RegressionData &trainingData) - Failed To Compute Features For Training Data. PreProcessingModuleIndex: " << moduleIndex << endl;
668  return false;
669  }
670 
671  inputVector = preProcessingModules[ moduleIndex ]->getProcessedData();
672  }
673  }
674 
676  for(UINT moduleIndex=0; moduleIndex<featureExtractionModules.size(); moduleIndex++){
677  if( !featureExtractionModules[ moduleIndex ]->computeFeatures( inputVector ) ){
678  errorLog << "train(const RegressionData &trainingData) - Failed To Compute Features For Training Data. FeatureExtractionModuleIndex: " << moduleIndex << endl;
679  return false;
680  }
681 
682  inputVector = featureExtractionModules[ moduleIndex ]->getFeatureVector();
683  }
684  }
685 
686  //Add the training sample to the processed training data
687  if( !processedTrainingData.addSample(inputVector,targetVector) ){
688  errorLog << "train(const RegressionData &trainingData) - Failed to add processed training sample to training data" << endl;
689  return false;
690  }
691  }
692 
693  //Store the number of training samples
694  numTrainingSamples = processedTrainingData.getNumSamples();
695 
696  //Train the classification system
697  if( getIsRegressifierSet() ){
698  trained = regressifier->train( processedTrainingData );
699  if( !trained ){
700  errorLog << "train(const RegressionData &trainingData) - Failed To Train Regressifier: " << regressifier->getLastErrorMessage() << endl;
701  return false;
702  }
703  }else{
704  errorLog << "train(const RegressionData &trainingData) - Classifier is not set" << endl;
705  return false;
706  }
707 
708  //Store the training time
709  trainingTime = timer.getMilliSeconds();
710 
711  return true;
712 }
713 
714 bool GestureRecognitionPipeline::train(const RegressionData &trainingData,const UINT kFoldValue){
715 
716  trained = false;
717  trainingTime = 0;
719 
720  if( !getIsRegressifierSet() ){
721  errorLog << "train(const RegressionData &trainingData,const UINT kFoldValue) - Failed To Train Regressifier, the regressifier has not been set!" << endl;
722  return false;
723  }
724 
725  if( trainingData.getNumSamples() == 0 ){
726  errorLog << "train(const RegressionData &trainingData,const UINT kFoldValue) - Failed To Train Regressifier, there is no training data!" << endl;
727  return false;
728  }
729 
730  //Reset all the modules
731  reset();
732 
733  //Start the training timer
734  Timer timer;
735  timer.start();
736 
737  //Get a copy of the training data so we can split it
738  RegressionData data = trainingData;
739 
740  //Spilt the data into K folds
741  bool spiltResult = data.spiltDataIntoKFolds(kFoldValue);
742 
743  if( !spiltResult ){
744  return false;
745  }
746 
747  //Run the k-fold training and testing
748  double crossValidationAccuracy = 0;
749  RegressionData foldTrainingData;
750  RegressionData foldTestData;
751  for(UINT k=0; k<kFoldValue; k++){
753  foldTrainingData = data.getTrainingFoldData(k);
754 
755  if( !train( foldTrainingData ) ){
756  return false;
757  }
758 
759  //Test the classification system
760  foldTestData = data.getTestFoldData(k);
761 
762  if( !test( foldTestData ) ){
763  return false;
764  }
765 
766  crossValidationAccuracy += getTestRMSError();
767 
768  }
769 
770  //Flag that the model has been trained
771  trained = true;
772 
773  testAccuracy = crossValidationAccuracy / double(kFoldValue);
774 
775  //Store the training time
776  trainingTime = timer.getMilliSeconds();
777 
778  return true;
779 }
780 
782 
783  trained = false;
784  trainingTime = 0;
786 
787  if( !getIsClustererSet() ){
788  errorLog << "train(const UnlabelledData &trainingData) - Failed To Train Clusterer, the clusterer has not been set!" << endl;
789  return false;
790  }
791 
792  if( trainingData.getNumSamples() == 0 ){
793  errorLog << "train(const UnlabelledData &trainingData) - Failed To Train Clusterer, there is no training data!" << endl;
794  return false;
795  }
796 
797  //Reset all the modules
798  reset();
799 
800  //Set the input vector dimension size
801  inputVectorDimensions = trainingData.getNumDimensions();
802 
803  //Pass the training data through any pre-processing or feature extraction units
804  UINT numDimensions = trainingData.getNumDimensions();
805 
806  //If there are any preprocessing or feature extraction modules, then get the size of the last module
809  numDimensions = featureExtractionModules[ featureExtractionModules.size()-1 ]->getNumOutputDimensions();
810  }else{
811  numDimensions = preProcessingModules[ preProcessingModules.size()-1 ]->getNumOutputDimensions();
812  }
813  }
814 
815  //Start the training timer
816  Timer timer;
817  timer.start();
818 
819  UnlabelledData processedTrainingData( numDimensions );
820 
821  for(UINT i=0; i<trainingData.getNumSamples(); i++){
822  bool okToAddProcessedData = true;
823  VectorDouble trainingSample = trainingData[i];
824 
825  //Perform any preprocessing
826  if( getIsPreProcessingSet() ){
827  for(UINT moduleIndex=0; moduleIndex<preProcessingModules.size(); moduleIndex++){
828  if( !preProcessingModules[moduleIndex]->process( trainingSample ) ){
829  errorLog << "train(const UnlabelledData &trainingData) - Failed to PreProcess Training Data. PreProcessingModuleIndex: ";
830  errorLog << moduleIndex;
831  errorLog << endl;
832  return false;
833  }
834  trainingSample = preProcessingModules[moduleIndex]->getProcessedData();
835  }
836  }
837 
838  //Compute any features
840  for(UINT moduleIndex=0; moduleIndex<featureExtractionModules.size(); moduleIndex++){
841  if( !featureExtractionModules[moduleIndex]->computeFeatures( trainingSample ) ){
842  errorLog << "train(const UnlabelledData &trainingData) - Failed to Compute Features from Training Data. FeatureExtractionModuleIndex ";
843  errorLog << moduleIndex;
844  errorLog << endl;
845  return false;
846  }
847  if( featureExtractionModules[moduleIndex]->getFeatureDataReady() ){
848  trainingSample = featureExtractionModules[moduleIndex]->getFeatureVector();
849  }else{
850  okToAddProcessedData = false;
851  break;
852  }
853  }
854  }
855 
856  if( okToAddProcessedData ){
857  //Add the training sample to the processed training data
858  processedTrainingData.addSample(trainingSample);
859  }
860 
861  }
862 
863  if( processedTrainingData.getNumSamples() != trainingData.getNumSamples() ){
864 
865  warningLog << "train(const ClassificationData &trainingData) - Lost " << trainingData.getNumSamples()-processedTrainingData.getNumSamples() << " of " << trainingData.getNumSamples() << " training samples due to the processing stage!" << endl;
866  }
867 
868  //Store the number of training samples
869  numTrainingSamples = processedTrainingData.getNumSamples();
870 
871  //Train the cluster model
872  trained = clusterer->train_( processedTrainingData );
873  if( !trained ){
874  errorLog << "train(const UnlabelledData &trainingData) - Failed To Train Clusterer: " << clusterer->getLastErrorMessage() << endl;
875  return false;
876  }
877 
878  //Store the training time
879  trainingTime = timer.getMilliSeconds();
880 
881  return true;
882 }
883 
885 
886  //Clear any previous test results
888 
889  //Make sure the classification model has been trained
890  if( !trained ){
891  errorLog << "test(const ClassificationData &testData) - Classifier is not trained" << endl;
892  return false;
893  }
894 
895  //Make sure the dimensionality of the test data matches the input vector's dimensions
896  if( testData.getNumDimensions() != inputVectorDimensions ){
897  errorLog << "test(const ClassificationData &testData) - The dimensionality of the test data (" + Util::toString(testData.getNumDimensions()) + ") does not match that of the input vector dimensions of the pipeline (" << inputVectorDimensions << ")" << endl;
898  return false;
899  }
900 
901  if( !getIsClassifierSet() ){
902  errorLog << "test(const ClassificationData &testData) - The classifier has not been set" << endl;
903  return false;
904  }
905 
906  //Reset all the modules
907  reset();
908 
909  //Validate that the class labels in the test data match the class labels in the model
910  bool classLabelValidationPassed = true;
911  for(UINT i=0; i<testData.getNumClasses(); i++){
912  bool labelFound = false;
913  for(UINT k=0; k<classifier->getNumClasses(); k++){
914  if( testData.getClassTracker()[i].classLabel == classifier->getClassLabels()[k] ){
915  labelFound = true;
916  break;
917  }
918  }
919 
920  if( !labelFound ){
921  classLabelValidationPassed = false;
922  errorLog << "test(const ClassificationData &testData) - The test dataset contains a class label (" << testData.getClassTracker()[i].classLabel << ") that is not in the model!" << endl;
923  }
924  }
925 
926  if( !classLabelValidationPassed ){
927  errorLog << "test(const ClassificationData &testData) - Model Class Labels: ";
928  for(UINT k=0; k<classifier->getNumClasses(); k++){
929  errorLog << classifier->getClassLabels()[k] << "\t";
930  }
931  errorLog << endl;
932  return false;
933  }
934 
935  double rejectionPrecisionCounter = 0;
936  double rejectionRecallCounter = 0;
937  unsigned int confusionMatrixSize = classifier->getNullRejectionEnabled() ? classifier->getNumClasses()+1 : classifier->getNumClasses();
938  VectorDouble precisionCounter(classifier->getNumClasses(), 0);
939  VectorDouble recallCounter(classifier->getNumClasses(), 0);
940  VectorDouble confusionMatrixCounter(confusionMatrixSize,0);
941 
942  //Resize the test matrix
943  testConfusionMatrix.resize(confusionMatrixSize, confusionMatrixSize);
944  testConfusionMatrix.setAllValues(0);
945 
946  //Resize the precision and recall vectors
947  testPrecision.clear();
948  testRecall.clear();
949  testFMeasure.clear();
950  testPrecision.resize(getNumClassesInModel(), 0);
951  testRecall.resize(getNumClassesInModel(), 0);
952  testFMeasure.resize(getNumClassesInModel(), 0);
953  testResults.resize(testData.getNumSamples());
954  numTestSamples = testData.getNumSamples();
955 
956  //Start the test timer
957  Timer timer;
958  timer.start();
959 
960  //Run the test
961  for(UINT i=0; i<numTestSamples; i++){
962  UINT classLabel = testData[i].getClassLabel();
963  VectorDouble testSample = testData[i].getSample();
964 
965  //Pass the test sample through the pipeline
966  if( !predict( testSample ) ){
967  errorLog << "test(const ClassificationData &testData) - Prediction failed for test sample at index: " << i << endl;
968  return false;
969  }
970 
971  //Update the test metrics
972  UINT predictedClassLabel = getPredictedClassLabel();
973 
974  if( !updateTestMetrics(classLabel,predictedClassLabel,precisionCounter,recallCounter,rejectionPrecisionCounter,rejectionRecallCounter, confusionMatrixCounter) ){
975  errorLog << "test(const ClassificationData &testData) - Failed to update test metrics at test sample index: " << i << endl;
976  return false;
977  }
978 
979  //Keep track of the classification results encase the user needs them later
980  testResults[i].setClassificationResult(i, classLabel, predictedClassLabel, getUnProcessedPredictedClassLabel(),getClassLikelihoods(), getClassDistances());
981 
982  //Update any observers
983  classifier->notifyTestResultsObservers( testResults[i] );
984  }
985 
986  if( !computeTestMetrics(precisionCounter,recallCounter,rejectionPrecisionCounter,rejectionRecallCounter, confusionMatrixCounter, numTestSamples) ){
987  errorLog <<"test(const ClassificationData &testData) - Failed to compute test metrics!" << endl;
988  return false;
989  }
990 
991  testTime = timer.getMilliSeconds();
992 
993  return true;
994 }
995 
997 
998  //Clear any previous test results
1000 
1001  //Make sure the classification model has been trained
1002  if( !trained ){
1003  errorLog << "test(const TimeSeriesClassificationData &testData) - The classifier has not been trained" << endl;
1004  return false;
1005  }
1006 
1007  //Make sure the dimensionality of the test data matches the input vector's dimensions
1008  if( testData.getNumDimensions() != inputVectorDimensions ){
1009  errorLog << "test(const TimeSeriesClassificationData &testData) - The dimensionality of the test data (" << testData.getNumDimensions() << ") does not match that of the input vector dimensions of the pipeline (" << inputVectorDimensions << ")" << endl;
1010  return false;
1011  }
1012 
1013  if( !getIsClassifierSet() ){
1014  errorLog << "test(const TimeSeriesClassificationData &testData) - The classifier has not been set" << endl;
1015  return false;
1016  }
1017 
1018  //Reset all the modules
1019  reset();
1020 
1021  double rejectionPrecisionCounter = 0;
1022  double rejectionRecallCounter = 0;
1023  const UINT K = classifier->getNumClasses();
1024  UINT confusionMatrixSize = classifier->getNullRejectionEnabled() ? K+1 : K;
1025  VectorDouble precisionCounter(K, 0);
1026  VectorDouble recallCounter(K, 0);
1027  VectorDouble confusionMatrixCounter(confusionMatrixSize,0);
1028 
1029  //Resize the test matrix
1030  testConfusionMatrix.resize(confusionMatrixSize,confusionMatrixSize);
1031  testConfusionMatrix.setAllValues(0);
1032 
1033  //Resize the precision and recall vectors
1034  testPrecision.resize(K, 0);
1035  testRecall.resize(K, 0);
1036  testFMeasure.resize(K, 0);
1037  numTestSamples = testData.getNumSamples();
1038 
1039  //Start the test timer
1040  Timer timer;
1041  timer.start();
1042 
1043  //Run the test
1044  const UINT M = testData.getNumSamples();
1045  for(UINT i=0; i<M; i++){
1046  UINT classLabel = testData[i].getClassLabel();
1047  MatrixDouble timeseries = testData[i].getData();
1048 
1049  //Pass the test timeseries through the pipeline
1050  if( !predict( timeseries ) ){
1051  errorLog << "test(const TimeSeriesClassificationData &testData) - Failed to run prediction for test sample index: " << i << endl;
1052  return false;
1053  }
1054 
1055  //Update the test metrics
1056  UINT predictedClassLabel = getPredictedClassLabel();
1057 
1058  if( !updateTestMetrics(classLabel,predictedClassLabel,precisionCounter,recallCounter,rejectionPrecisionCounter,rejectionRecallCounter, confusionMatrixCounter) ){
1059  errorLog << "test(const TimeSeriesClassificationData &testData) - Failed to update test metrics at test sample index: " << i << endl;
1060  return false;
1061  }
1062 
1063  }
1064 
1065  if( !computeTestMetrics(precisionCounter,recallCounter,rejectionPrecisionCounter,rejectionRecallCounter, confusionMatrixCounter, M) ){
1066  errorLog << "test(const TimeSeriesClassificationData &testData) - Failed to compute test metrics!" << endl;
1067  return false;
1068  }
1069 
1070  testTime = timer.getMilliSeconds();
1071 
1072  return true;
1073 }
1074 
1076 
1077  //Clear any previous test results
1078  clearTestResults();
1079 
1080  //Make sure the classification model has been trained
1081  if( !trained ){
1082  errorLog << "test(const TimeSeriesClassificationDataStream &testData) - The classifier has not been trained" << endl;
1083  return false;
1084  }
1085 
1086  //Make sure the dimensionality of the test data matches the input vector's dimensions
1087  if( testData.getNumDimensions() != inputVectorDimensions ){
1088  errorLog << "test(const TimeSeriesClassificationDataStream &testData) - The dimensionality of the test data (" + Util::toString(testData.getNumDimensions()) + ") does not match that of the input vector dimensions of the pipeline (" << inputVectorDimensions << ")" << endl;
1089  return false;
1090  }
1091 
1092  if( !getIsClassifierSet() ){
1093  errorLog << "test(const TimeSeriesClassificationDataStream &testData) - The classifier has not been set" << endl;
1094  return false;
1095  }
1096 
1097  //Reset all the modules
1098  reset();
1099 
1100  //double rejectionPrecisionCounter = 0;
1101  //double rejectionRecallCounter = 0;
1102  UINT confusionMatrixSize = classifier->getNullRejectionEnabled() ? classifier->getNumClasses()+1 : classifier->getNumClasses();
1103  VectorDouble precisionCounter(getNumClassesInModel(), 0);
1104  VectorDouble recallCounter(getNumClassesInModel(), 0);
1105  VectorDouble confusionMatrixCounter(confusionMatrixSize,0);
1106 
1107  //Resize the test matrix
1108  testConfusionMatrix.resize(confusionMatrixSize,confusionMatrixSize);
1109  testConfusionMatrix.setAllValues(0);
1110 
1111  //Resize the precision and recall vectors
1112  testPrecision.resize(getNumClassesInModel(), 0);
1113  testRecall.resize(getNumClassesInModel(), 0);
1114  testFMeasure.resize(getNumClassesInModel(), 0);
1115 
1116  //Resize the classification results vector
1117  testResults.resize(testData.getNumSamples());
1118  numTestSamples = testData.getNumSamples();
1119 
1120  //Start the test timer
1121  Timer timer;
1122  timer.start();
1123 
1124  //Get a copy of the data so we can modify it
1125  TimeSeriesClassificationDataStream data = testData;
1126 
1127  //Run the test
1128  data.resetPlaybackIndex(0); //Make sure that the test data start at 0
1129  for(UINT i=0; i<data.getNumSamples(); i++){
1130  ClassificationSample sample = data.getNextSample();
1131  UINT classLabel = sample.getClassLabel();
1132  VectorDouble testSample = sample.getSample();
1133 
1134  //Pass the test sample through the pipeline
1135  if( !predict( testSample ) ){
1136  errorLog << "test(const TimeSeriesClassificationDataStream &testData) - Prediction Failed! " << classifier->getLastErrorMessage() << endl;
1137  return false;
1138  }
1139 
1140  //Update the test metrics
1141  UINT predictedClassLabel = getPredictedClassLabel();
1142 
1143  /* //TODO - Need to update this!
1144  if( !updateTestMetrics(classLabel,predictedClassLabel,precisionCounter,recallCounter,rejectionPrecisionCounter,rejectionRecallCounter, confusionMatrixCounter) ){
1145  errorLog << "test(LabelledContinuousTimeSeriesClassificationData &testData) - Failed to update test metrics at test sample index: " << i << endl;
1146  return false;
1147  }
1148  */
1149 
1150  if( classLabel == predictedClassLabel ) testAccuracy++;
1151 
1152  //Store the test results so they can be used later
1153  testResults[i].setClassificationResult(i, classLabel, predictedClassLabel, getUnProcessedPredictedClassLabel(), getClassLikelihoods(), getClassDistances());
1154 
1155  //Notify all observers of the test result
1156  classifier->notifyTestResultsObservers( testResults[i] );
1157 
1158  testingLog << "test iteration: " << i;
1159  testingLog << "\tClassLabel: " << classLabel;
1160  testingLog << "\tPredictedClassLabel: " << predictedClassLabel;
1161  testingLog << "\tLikelihood: " << getMaximumLikelihood() << endl;
1162  }
1163 
1164  /* //TODO - Need to update this!
1165  if( !computeTestMetrics(precisionCounter,recallCounter,rejectionPrecisionCounter,rejectionRecallCounter, confusionMatrixCounter, testData.getNumSamples()) ){
1166  errorLog << "test(LabelledContinuousTimeSeriesClassificationData &testData) - Failed to compute test metrics !" << endl;
1167  return false;
1168  }
1169  */
1170 
1171  testTime = timer.getMilliSeconds();
1172  testAccuracy = testAccuracy / double( testData.getNumSamples() ) * 100.0;
1173 
1174  testingLog << "Test complete. Total testing time: " << testTime << endl;
1175 
1176  return true;
1177 }
1178 
1180 
1181  //Clear any previous test results
1182  clearTestResults();
1183 
1184  //Make sure the classification model has been trained
1185  if( !trained ){
1186  errorLog << "test(const RegressionData &testData) - Regressifier is not trained" << endl;
1187  return false;
1188  }
1189 
1190  //Make sure the dimensionality of the test data matches the input vector's dimensions
1191  if( testData.getNumInputDimensions() != inputVectorDimensions ){
1192  errorLog << "test(const RegressionData &testData) - The dimensionality of the test data (" << testData.getNumInputDimensions() << ") does not match that of the input vector dimensions of the pipeline (" << inputVectorDimensions << ")" << endl;
1193  return false;
1194  }
1195 
1196  if( !getIsRegressifierSet() ){
1197  errorLog << "test(const RegressionData &testData) - The regressifier has not been set" << endl;
1198  return false;
1199  }
1200 
1201  if( regressifier->getNumOutputDimensions() != testData.getNumTargetDimensions() ){
1202  errorLog << "test(const RegressionData &testData) - The size of the output of the regressifier (" << regressifier->getNumOutputDimensions() << ") does not match that of the size of the number of target dimensions (" << testData.getNumTargetDimensions() << ")" << endl;
1203  return false;
1204  }
1205 
1206  //Reset all the modules
1207  reset();
1208 
1209  numTestSamples = testData.getNumSamples();
1210  testResults.resize( numTestSamples );
1211 
1212  //Start the test timer
1213  Timer timer;
1214  timer.start();
1215 
1216  //Run the test
1217  testSquaredError = 0;
1218  testRMSError = 0;
1219  for(UINT i=0; i<numTestSamples; i++){
1220  VectorDouble inputVector = testData[i].getInputVector();
1221  VectorDouble targetVector = testData[i].getTargetVector();
1222 
1223  //Pass the test sample through the pipeline
1224  if( !map( inputVector ) ){
1225  errorLog << "test(const RegressionData &testData) - Failed to map input vector!" << endl;
1226  return false;
1227  }
1228 
1229  //Update the RMS error
1230  double sum = 0;
1231  VectorDouble regressionData = regressifier->getRegressionData();
1232  for(UINT j=0; j<targetVector.size(); j++){
1233  sum += SQR( regressionData[j]-targetVector[j] );
1234  }
1235 
1236  testSquaredError += sum;
1237 
1238  //Keep track of the regression results encase the user needs them later
1239  testResults[i].setRegressionResult(i,regressionData,targetVector);
1240 
1241  //Update any observers
1242  regressifier->notifyTestResultsObservers( testResults[i] );
1243  }
1244 
1245  //Compute the test metrics
1246  testRMSError = sqrt( testSquaredError / double( testData.getNumSamples() ) );
1247 
1248  testTime = timer.getMilliSeconds();
1249 
1250  return true;
1251 }
1252 
1253 bool GestureRecognitionPipeline::predict(const VectorDouble &inputVector){
1254 
1255  //Make sure the classification model has been trained
1256  if( !trained ){
1257  errorLog << "predict(const VectorDouble &inputVector) - The classifier has not been trained" << endl;
1258  return false;
1259  }
1260 
1261  //Make sure the dimensionality of the input vector matches the inputVectorDimensions
1262  if( inputVector.size() != inputVectorDimensions ){
1263  errorLog << "predict(const VectorDouble &inputVector) - The dimensionality of the input vector (" << int(inputVector.size()) << ") does not match that of the input vector dimensions of the pipeline (" << inputVectorDimensions << ")" << endl;
1264  return false;
1265  }
1266 
1267  if( getIsClassifierSet() ){
1268  return predict_classifier( inputVector );
1269  }
1270 
1271  if( getIsRegressifierSet() ){
1272  return predict_regressifier( inputVector );
1273  }
1274 
1275  if( getIsClustererSet() ){
1276  return predict_clusterer( inputVector );
1277  }
1278 
1279  errorLog << "predict(const VectorDouble &inputVector) - Neither a classifier, regressifer or clusterer is set" << endl;
1280  return false;
1281 }
1282 
1284 
1285  //Make sure the classification model has been trained
1286  if( !trained ){
1287  errorLog << "predict(const MatrixDouble &inputMatrix) - The classifier has not been trained" << endl;
1288  return false;
1289  }
1290 
1291  //Make sure the dimensionality of the input matrix matches the inputVectorDimensions
1292  if( input.getNumCols() != inputVectorDimensions ){
1293  errorLog << "predict(const MatrixDouble &inputMatrix) - The dimensionality of the input matrix (" << input.getNumCols() << ") does not match that of the input vector dimensions of the pipeline (" << inputVectorDimensions << ")" << endl;
1294  return false;
1295  }
1296 
1297  if( !getIsClassifierSet() ){
1298  errorLog << "predict(const MatrixDouble &inputMatrix) - A classifier has not been set" << endl;
1299  return false;
1300  }
1301 
1302  MatrixDouble inputMatrix = input;
1303 
1304  predictedClassLabel = 0;
1305 
1306  //Update the context module
1307  predictionModuleIndex = START_OF_PIPELINE;
1308 
1309  //Perform any pre-processing
1310  if( getIsPreProcessingSet() ){
1311 
1312  for(UINT moduleIndex=0; moduleIndex<preProcessingModules.size(); moduleIndex++){
1313  MatrixDouble tmpMatrix( inputMatrix.getNumRows(), preProcessingModules[moduleIndex]->getNumOutputDimensions() );
1314 
1315  for(UINT i=0; i<inputMatrix.getNumRows(); i++){
1316  if( !preProcessingModules[moduleIndex]->process( inputMatrix.getRowVector(i) ) ){
1317  errorLog << "predict(const MatrixDouble &inputMatrix) - Failed to PreProcess Input Matrix. PreProcessingModuleIndex: " << moduleIndex << endl;
1318  return false;
1319  }
1320  tmpMatrix.setRowVector( preProcessingModules[moduleIndex]->getProcessedData(), i );
1321  }
1322 
1323  //Update the input matrix with the preprocessed data
1324  inputMatrix = tmpMatrix;
1325  }
1326  }
1327 
1328  //Update the context module
1329  predictionModuleIndex = AFTER_PREPROCESSING;
1330  //Todo
1331 
1332  //Perform any feature extraction
1333  if( getIsFeatureExtractionSet() ){
1334 
1335  for(UINT moduleIndex=0; moduleIndex<featureExtractionModules.size(); moduleIndex++){
1336  MatrixDouble tmpMatrix( inputMatrix.getNumRows(), featureExtractionModules[moduleIndex]->getNumOutputDimensions() );
1337 
1338  for(UINT i=0; i<inputMatrix.getNumRows(); i++){
1339  if( !featureExtractionModules[moduleIndex]->computeFeatures( inputMatrix.getRowVector(i) ) ){
1340  errorLog << "predict(const MatrixDouble &inputMatrix) - Failed to PreProcess Input Matrix. FeatureExtractionModuleIndex: " << moduleIndex << endl;
1341  return false;
1342  }
1343  tmpMatrix.setRowVector( featureExtractionModules[moduleIndex]->getFeatureVector(), i );
1344  }
1345 
1346  //Update the input matrix with the preprocessed data
1347  inputMatrix = tmpMatrix;
1348  }
1349  }
1350 
1351  //Update the context module
1352  predictionModuleIndex = AFTER_FEATURE_EXTRACTION;
1353  //Todo
1354 
1355  //Perform the classification
1356  if( !classifier->predict( inputMatrix ) ){
1357  errorLog <<"predict(const MatrixDouble &inputMatrix) - Prediction Failed! " << classifier->getLastErrorMessage() << endl;
1358  return false;
1359  }
1360  predictedClassLabel = classifier->getPredictedClassLabel();
1361 
1362  //Update the context module
1363  //Todo
1364 
1365  //Perform any post processing
1366  predictionModuleIndex = AFTER_CLASSIFIER;
1367  if( getIsPostProcessingSet() ){
1368 
1369  if( pipelineMode != CLASSIFICATION_MODE){
1370  errorLog << "predict_(const MatrixDouble &inputMatrix) - Pipeline Mode Is Not in CLASSIFICATION_MODE!" << endl;
1371  return false;
1372  }
1373 
1374  VectorDouble data;
1375  for(UINT moduleIndex=0; moduleIndex<postProcessingModules.size(); moduleIndex++){
1376 
1377  //Select which input we should give the postprocessing module
1378  if( postProcessingModules[moduleIndex]->getIsPostProcessingInputModePredictedClassLabel() ){
1379  //Set the input
1380  data.resize(1);
1381  data[0] = predictedClassLabel;
1382 
1383  //Verify that the input size is OK
1384  if( data.size() != postProcessingModules[moduleIndex]->getNumInputDimensions() ){
1385  errorLog << "predict(const MatrixDouble &inputMatrix) - The size of the data vector (" << int(data.size()) << ") does not match that of the postProcessingModule (" << postProcessingModules[moduleIndex]->getNumInputDimensions() << ") at the moduleIndex: " << moduleIndex << endl;
1386  return false;
1387  }
1388 
1389  //Postprocess the data
1390  if( !postProcessingModules[moduleIndex]->process( data ) ){
1391  errorLog << "predict(const MatrixDouble &inputMatrix) - Failed to post process data. PostProcessing moduleIndex: " << moduleIndex << endl;
1392  return false;
1393  }
1394 
1395  //Select which output we should update
1396  data = postProcessingModules[moduleIndex]->getProcessedData();
1397  }
1398 
1399  //Select which output we should update
1400  if( postProcessingModules[moduleIndex]->getIsPostProcessingOutputModePredictedClassLabel() ){
1401  //Get the processed predicted class label
1402  data = postProcessingModules[moduleIndex]->getProcessedData();
1403 
1404  //Verify that the output size is OK
1405  if( data.size() != 1 ){
1406  errorLog << "predict(const MatrixDouble &inputMatrix) - The size of the processed data vector (" << int(data.size()) << ") from postProcessingModule at the moduleIndex: " << moduleIndex << " is not equal to 1 even though it is in OutputModePredictedClassLabel!" << endl;
1407  return false;
1408  }
1409 
1410  //Update the predicted class label
1411  predictedClassLabel = (UINT)data[0];
1412  }
1413 
1414  }
1415  }
1416 
1417  //Update the context module
1418  //TODO
1419  predictionModuleIndex = END_OF_PIPELINE;
1420 
1421  return true;
1422 }
1423 
1424 bool GestureRecognitionPipeline::map(const VectorDouble &inputVector){
1425  return predict_regressifier( inputVector );
1426 }
1427 
1428 bool GestureRecognitionPipeline::predict_classifier(const VectorDouble &input){
1429 
1430  predictedClassLabel = 0;
1431  VectorDouble inputVector = input;
1432 
1433  //Update the context module
1434  predictionModuleIndex = START_OF_PIPELINE;
1435  if( contextModules[ START_OF_PIPELINE ].size() > 0 ){
1436  for(UINT moduleIndex=0; moduleIndex<contextModules[ START_OF_PIPELINE ].size(); moduleIndex++){
1437  if( !contextModules[ START_OF_PIPELINE ][moduleIndex]->process( inputVector ) ){
1438  errorLog << "predict_classifier(const VectorDouble &inputVector) - Context Module Failed at START_OF_PIPELINE. ModuleIndex: " << moduleIndex << endl;
1439  return false;
1440  }
1441  if( !contextModules[ START_OF_PIPELINE ][moduleIndex]->getOK() ){
1442  return true;
1443  }
1444  inputVector = contextModules[ START_OF_PIPELINE ][moduleIndex]->getProcessedData();
1445  }
1446  }
1447 
1448  //Perform any pre-processing
1449  if( getIsPreProcessingSet() ){
1450  for(UINT moduleIndex=0; moduleIndex<preProcessingModules.size(); moduleIndex++){
1451  if( !preProcessingModules[moduleIndex]->process( inputVector ) ){
1452  errorLog << "predict_classifier(const VectorDouble &inputVector) - Failed to PreProcess Input Vector. PreProcessingModuleIndex: " << moduleIndex << endl;
1453  return false;
1454  }
1455  inputVector = preProcessingModules[moduleIndex]->getProcessedData();
1456  }
1457  }
1458 
1459  //Update the context module
1460  predictionModuleIndex = AFTER_PREPROCESSING;
1461  if( contextModules[ AFTER_PREPROCESSING ].size() ){
1462  for(UINT moduleIndex=0; moduleIndex<contextModules[ AFTER_PREPROCESSING ].size(); moduleIndex++){
1463  if( !contextModules[ AFTER_PREPROCESSING ][moduleIndex]->process( inputVector ) ){
1464  errorLog << "predict_classifier(VectorDouble inputVector) - Context Module Failed at AFTER_PREPROCESSING. ModuleIndex: " << moduleIndex << endl;
1465  return false;
1466  }
1467  if( !contextModules[ AFTER_PREPROCESSING ][moduleIndex]->getOK() ){
1468  predictionModuleIndex = AFTER_PREPROCESSING;
1469  return false;
1470  }
1471  inputVector = contextModules[ AFTER_PREPROCESSING ][moduleIndex]->getProcessedData();
1472  }
1473  }
1474 
1475  //Perform any feature extraction
1476  if( getIsFeatureExtractionSet() ){
1477  for(UINT moduleIndex=0; moduleIndex<featureExtractionModules.size(); moduleIndex++){
1478  if( !featureExtractionModules[moduleIndex]->computeFeatures( inputVector ) ){
1479  errorLog << "predict_classifier(VectorDouble inputVector) - Failed to compute features from data. FeatureExtractionModuleIndex: " << moduleIndex << endl;
1480  return false;
1481  }
1482  inputVector = featureExtractionModules[moduleIndex]->getFeatureVector();
1483  }
1484  }
1485 
1486  //Update the context module
1487  predictionModuleIndex = AFTER_FEATURE_EXTRACTION;
1488  if( contextModules[ AFTER_FEATURE_EXTRACTION ].size() ){
1489  for(UINT moduleIndex=0; moduleIndex<contextModules[ AFTER_FEATURE_EXTRACTION ].size(); moduleIndex++){
1490  if( !contextModules[ AFTER_FEATURE_EXTRACTION ][moduleIndex]->process( inputVector ) ){
1491  errorLog << "predict_classifier(VectorDouble inputVector) - Context Module Failed at AFTER_FEATURE_EXTRACTION. ModuleIndex: " << moduleIndex << endl;
1492  return false;
1493  }
1494  if( !contextModules[ AFTER_FEATURE_EXTRACTION ][moduleIndex]->getOK() ){
1495  predictionModuleIndex = AFTER_FEATURE_EXTRACTION;
1496  return false;
1497  }
1498  inputVector = contextModules[ AFTER_FEATURE_EXTRACTION ][moduleIndex]->getProcessedData();
1499  }
1500  }
1501 
1502  //Perform the classification
1503  if( !classifier->predict(inputVector) ){
1504  errorLog << "predict_classifier(VectorDouble inputVector) - Prediction Failed! " << classifier->getLastErrorMessage() << endl;
1505  return false;
1506  }
1507  predictedClassLabel = classifier->getPredictedClassLabel();
1508 
1509  //Update the context module
1510  if( contextModules[ AFTER_CLASSIFIER ].size() ){
1511  for(UINT moduleIndex=0; moduleIndex<contextModules[ AFTER_CLASSIFIER ].size(); moduleIndex++){
1512  if( !contextModules[ AFTER_CLASSIFIER ][moduleIndex]->process( vector<double>(1,predictedClassLabel) ) ){
1513  errorLog << "predict_classifier(VectorDouble inputVector) - Context Module Failed at AFTER_CLASSIFIER. ModuleIndex: " << moduleIndex << endl;
1514  return false;
1515  }
1516  if( !contextModules[ AFTER_CLASSIFIER ][moduleIndex]->getOK() ){
1517  predictionModuleIndex = AFTER_CLASSIFIER;
1518  return false;
1519  }
1520  predictedClassLabel = (UINT)contextModules[ AFTER_CLASSIFIER ][moduleIndex]->getProcessedData()[0];
1521  }
1522  }
1523 
1524  //Perform any post processing
1525  predictionModuleIndex = AFTER_CLASSIFIER;
1526  if( getIsPostProcessingSet() ){
1527 
1528  if( pipelineMode != CLASSIFICATION_MODE){
1529  errorLog << "predict_classifier(VectorDouble inputVector) - Pipeline Mode Is Not in CLASSIFICATION_MODE!" << endl;
1530  return false;
1531  }
1532 
1533  VectorDouble data;
1534  for(UINT moduleIndex=0; moduleIndex<postProcessingModules.size(); moduleIndex++){
1535 
1536  //Select which input we should give the postprocessing module
1537  if( postProcessingModules[moduleIndex]->getIsPostProcessingInputModePredictedClassLabel() ){
1538  //Set the input
1539  data.resize(1);
1540  data[0] = predictedClassLabel;
1541 
1542  //Verify that the input size is OK
1543  if( data.size() != postProcessingModules[moduleIndex]->getNumInputDimensions() ){
1544  errorLog << "predict_classifier(VectorDouble inputVector) - The size of the data vector (" << int(data.size()) << ") does not match that of the postProcessingModule (" << postProcessingModules[moduleIndex]->getNumInputDimensions() << ") at the moduleIndex: " << moduleIndex << endl;
1545  return false;
1546  }
1547 
1548  //Postprocess the data
1549  if( !postProcessingModules[moduleIndex]->process( data ) ){
1550  errorLog << "predict_classifier(VectorDouble inputVector) - Failed to post process data. PostProcessing moduleIndex: " << moduleIndex << endl;
1551  return false;
1552  }
1553 
1554  //Select which output we should update
1555  data = postProcessingModules[moduleIndex]->getProcessedData();
1556  }
1557 
1558  //Select which output we should update
1559  if( postProcessingModules[moduleIndex]->getIsPostProcessingOutputModePredictedClassLabel() ){
1560  //Get the processed predicted class label
1561  data = postProcessingModules[moduleIndex]->getProcessedData();
1562 
1563  //Verify that the output size is OK
1564  if( data.size() != 1 ){
1565  errorLog << "predict_classifier(VectorDouble inputVector) - The size of the processed data vector (" << int(data.size()) << ") from postProcessingModule at the moduleIndex: " << moduleIndex << " is not equal to 1 even though it is in OutputModePredictedClassLabel!" << endl;
1566  return false;
1567  }
1568 
1569  //Update the predicted class label
1570  predictedClassLabel = (UINT)data[0];
1571  }
1572 
1573  }
1574  }
1575 
1576  //Update the context module
1577  predictionModuleIndex = END_OF_PIPELINE;
1578  if( contextModules[ END_OF_PIPELINE ].size() ){
1579  for(UINT moduleIndex=0; moduleIndex<contextModules[ END_OF_PIPELINE ].size(); moduleIndex++){
1580  if( !contextModules[ END_OF_PIPELINE ][moduleIndex]->process( vector<double>(1,predictedClassLabel) ) ){
1581  errorLog << "predict_classifier(VectorDouble inputVector) - Context Module Failed at END_OF_PIPELINE. ModuleIndex: " << moduleIndex << endl;
1582  return false;
1583  }
1584  if( !contextModules[ END_OF_PIPELINE ][moduleIndex]->getOK() ){
1585  predictionModuleIndex = END_OF_PIPELINE;
1586  return false;
1587  }
1588  predictedClassLabel = (UINT)contextModules[ END_OF_PIPELINE ][moduleIndex]->getProcessedData()[0];
1589  }
1590  }
1591 
1592  return true;
1593 }
1594 
1595 bool GestureRecognitionPipeline::predict_regressifier(const VectorDouble &input){
1596 
1597  VectorDouble inputVector = input;
1598 
1599  //Update the context module
1600  predictionModuleIndex = START_OF_PIPELINE;
1601  if( contextModules[ START_OF_PIPELINE ].size() ){
1602  for(UINT moduleIndex=0; moduleIndex<contextModules[ START_OF_PIPELINE ].size(); moduleIndex++){
1603  if( !contextModules[ START_OF_PIPELINE ][moduleIndex]->process( inputVector ) ){
1604  errorLog << "predict_regressifier(VectorDouble inputVector) - Context Module Failed at START_OF_PIPELINE. ModuleIndex: " << moduleIndex << endl;
1605  return false;
1606  }
1607  if( !contextModules[ START_OF_PIPELINE ][moduleIndex]->getOK() ){
1608  return true;
1609  }
1610  inputVector = contextModules[ START_OF_PIPELINE ][moduleIndex]->getProcessedData();
1611  }
1612  }
1613 
1614  //Perform any pre-processing
1615  if( getIsPreProcessingSet() ){
1616  for(UINT moduleIndex=0; moduleIndex<preProcessingModules.size(); moduleIndex++){
1617  if( !preProcessingModules[moduleIndex]->process( inputVector ) ){
1618  errorLog << "predict_regressifier(VectorDouble inputVector) - Failed to PreProcess Input Vector. PreProcessingModuleIndex: " << moduleIndex << endl;
1619  return false;
1620  }
1621  inputVector = preProcessingModules[moduleIndex]->getProcessedData();
1622  }
1623  }
1624 
1625  //Update the context module
1626  predictionModuleIndex = AFTER_PREPROCESSING;
1627  if( contextModules[ AFTER_PREPROCESSING ].size() ){
1628  for(UINT moduleIndex=0; moduleIndex<contextModules[ AFTER_PREPROCESSING ].size(); moduleIndex++){
1629  if( !contextModules[ AFTER_PREPROCESSING ][moduleIndex]->process( inputVector ) ){
1630  errorLog << "predict_regressifier(VectorDouble inputVector) - Context Module Failed at AFTER_PREPROCESSING. ModuleIndex: " << moduleIndex << endl;
1631  return false;
1632  }
1633  if( !contextModules[ AFTER_PREPROCESSING ][moduleIndex]->getOK() ){
1634  predictionModuleIndex = AFTER_PREPROCESSING;
1635  return false;
1636  }
1637  inputVector = contextModules[ AFTER_PREPROCESSING ][moduleIndex]->getProcessedData();
1638  }
1639  }
1640 
1641  //Perform any feature extraction
1642  if( getIsFeatureExtractionSet() ){
1643  for(UINT moduleIndex=0; moduleIndex<featureExtractionModules.size(); moduleIndex++){
1644  if( !featureExtractionModules[moduleIndex]->computeFeatures( inputVector ) ){
1645  errorLog << "predict_regressifier(VectorDouble inputVector) - Failed to compute features from data. FeatureExtractionModuleIndex: " << moduleIndex << endl;
1646  return false;
1647  }
1648  inputVector = featureExtractionModules[moduleIndex]->getFeatureVector();
1649  }
1650  }
1651 
1652  //Update the context module
1653  predictionModuleIndex = AFTER_FEATURE_EXTRACTION;
1654  if( contextModules[ AFTER_FEATURE_EXTRACTION ].size() ){
1655  for(UINT moduleIndex=0; moduleIndex<contextModules[ AFTER_FEATURE_EXTRACTION ].size(); moduleIndex++){
1656  if( !contextModules[ AFTER_FEATURE_EXTRACTION ][moduleIndex]->process( inputVector ) ){
1657  errorLog << "predict_regressifier(VectorDouble inputVector) - Context Module Failed at AFTER_FEATURE_EXTRACTION. ModuleIndex: " << moduleIndex << endl;
1658  return false;
1659  }
1660  if( !contextModules[ AFTER_FEATURE_EXTRACTION ][moduleIndex]->getOK() ){
1661  predictionModuleIndex = AFTER_FEATURE_EXTRACTION;
1662  return false;
1663  }
1664  inputVector = contextModules[ AFTER_FEATURE_EXTRACTION ][moduleIndex]->getProcessedData();
1665  }
1666  }
1667 
1668  //Perform the regression
1669  if( !regressifier->predict(inputVector) ){
1670  errorLog << "predict_regressifier(VectorDouble inputVector) - Prediction Failed! " << regressifier->getLastErrorMessage() << endl;
1671  return false;
1672  }
1673  regressionData = regressifier->getRegressionData();
1674 
1675  //Update the context module
1676  if( contextModules[ AFTER_CLASSIFIER ].size() ){
1677  for(UINT moduleIndex=0; moduleIndex<contextModules[ AFTER_CLASSIFIER ].size(); moduleIndex++){
1678  if( !contextModules[ AFTER_CLASSIFIER ][moduleIndex]->process( regressionData ) ){
1679  errorLog << "predict_regressifier(VectorDouble inputVector) - Context Module Failed at AFTER_CLASSIFIER. ModuleIndex: " << moduleIndex << endl;
1680  return false;
1681  }
1682  if( !contextModules[ AFTER_CLASSIFIER ][moduleIndex]->getOK() ){
1683  predictionModuleIndex = AFTER_CLASSIFIER;
1684  return false;
1685  }
1686  regressionData = contextModules[ AFTER_CLASSIFIER ][moduleIndex]->getProcessedData();
1687  }
1688  }
1689 
1690  //Perform any post processing
1691  predictionModuleIndex = AFTER_CLASSIFIER;
1692  if( getIsPostProcessingSet() ){
1693 
1694  if( pipelineMode != REGRESSION_MODE ){
1695  errorLog << "predict_regressifier(VectorDouble inputVector) - Pipeline Mode Is Not In RegressionMode!" << endl;
1696  return false;
1697  }
1698 
1699  for(UINT moduleIndex=0; moduleIndex<postProcessingModules.size(); moduleIndex++){
1700  if( regressionData.size() != postProcessingModules[moduleIndex]->getNumInputDimensions() ){
1701  errorLog << "predict_regressifier(VectorDouble inputVector) - The size of the regression vector (" << int(regressionData.size()) << ") does not match that of the postProcessingModule (" << postProcessingModules[moduleIndex]->getNumInputDimensions() << ") at the moduleIndex: " << moduleIndex << endl;
1702  return false;
1703  }
1704 
1705  if( !postProcessingModules[moduleIndex]->process( regressionData ) ){
1706  errorLog << "predict_regressifier(VectorDouble inputVector) - Failed to post process data. PostProcessing moduleIndex: " << moduleIndex << endl;
1707  return false;
1708  }
1709  regressionData = postProcessingModules[moduleIndex]->getProcessedData();
1710  }
1711 
1712  }
1713 
1714  //Update the context module
1715  predictionModuleIndex = END_OF_PIPELINE;
1716  if( contextModules[ END_OF_PIPELINE ].size() ){
1717  for(UINT moduleIndex=0; moduleIndex<contextModules[ END_OF_PIPELINE ].size(); moduleIndex++){
1718  if( !contextModules[ END_OF_PIPELINE ][moduleIndex]->process( inputVector ) ){
1719  errorLog << "predict_regressifier(VectorDouble inputVector) - Context Module Failed at END_OF_PIPELINE. ModuleIndex: " << moduleIndex << endl;
1720  return false;
1721  }
1722  if( !contextModules[ END_OF_PIPELINE ][moduleIndex]->getOK() ){
1723  predictionModuleIndex = END_OF_PIPELINE;
1724  return false;
1725  }
1726  regressionData = contextModules[ END_OF_PIPELINE ][moduleIndex]->getProcessedData();
1727  }
1728  }
1729 
1730  return true;
1731 }
1732 
1733 bool GestureRecognitionPipeline::predict_clusterer(const VectorDouble &input){
1734 
1735  VectorDouble inputVector = input;
1736  predictedClusterLabel = 0;
1737 
1738  //Update the context module
1739  predictionModuleIndex = START_OF_PIPELINE;
1740  if( contextModules[ START_OF_PIPELINE ].size() ){
1741  for(UINT moduleIndex=0; moduleIndex<contextModules[ START_OF_PIPELINE ].size(); moduleIndex++){
1742  if( !contextModules[ START_OF_PIPELINE ][moduleIndex]->process( inputVector ) ){
1743  errorLog << "predict_clusterer(VectorDouble inputVector) - Context Module Failed at START_OF_PIPELINE. ModuleIndex: " << moduleIndex << endl;
1744  return false;
1745  }
1746  if( !contextModules[ START_OF_PIPELINE ][moduleIndex]->getOK() ){
1747  return true;
1748  }
1749  inputVector = contextModules[ START_OF_PIPELINE ][moduleIndex]->getProcessedData();
1750  }
1751  }
1752 
1753  //Perform any pre-processing
1754  if( getIsPreProcessingSet() ){
1755  for(UINT moduleIndex=0; moduleIndex<preProcessingModules.size(); moduleIndex++){
1756  if( !preProcessingModules[moduleIndex]->process( inputVector ) ){
1757  errorLog << "predict_clusterer(VectorDouble inputVector) - Failed to PreProcess Input Vector. PreProcessingModuleIndex: " << moduleIndex << endl;
1758  return false;
1759  }
1760  inputVector = preProcessingModules[moduleIndex]->getProcessedData();
1761  }
1762  }
1763 
1764  //Update the context module
1765  predictionModuleIndex = AFTER_PREPROCESSING;
1766  if( contextModules[ AFTER_PREPROCESSING ].size() ){
1767  for(UINT moduleIndex=0; moduleIndex<contextModules[ AFTER_PREPROCESSING ].size(); moduleIndex++){
1768  if( !contextModules[ AFTER_PREPROCESSING ][moduleIndex]->process( inputVector ) ){
1769  errorLog << "predict_clusterer(VectorDouble inputVector) - Context Module Failed at AFTER_PREPROCESSING. ModuleIndex: " << moduleIndex << endl;
1770  return false;
1771  }
1772  if( !contextModules[ AFTER_PREPROCESSING ][moduleIndex]->getOK() ){
1773  predictionModuleIndex = AFTER_PREPROCESSING;
1774  return false;
1775  }
1776  inputVector = contextModules[ AFTER_PREPROCESSING ][moduleIndex]->getProcessedData();
1777  }
1778  }
1779 
1780  //Perform any feature extraction
1781  if( getIsFeatureExtractionSet() ){
1782  for(UINT moduleIndex=0; moduleIndex<featureExtractionModules.size(); moduleIndex++){
1783  if( !featureExtractionModules[moduleIndex]->computeFeatures( inputVector ) ){
1784  errorLog << "predict_clusterer(VectorDouble inputVector) - Failed to compute features from data. FeatureExtractionModuleIndex: " << moduleIndex << endl;
1785  return false;
1786  }
1787  inputVector = featureExtractionModules[moduleIndex]->getFeatureVector();
1788  }
1789  }
1790 
1791  //Update the context module
1792  predictionModuleIndex = AFTER_FEATURE_EXTRACTION;
1793  if( contextModules[ AFTER_FEATURE_EXTRACTION ].size() ){
1794  for(UINT moduleIndex=0; moduleIndex<contextModules[ AFTER_FEATURE_EXTRACTION ].size(); moduleIndex++){
1795  if( !contextModules[ AFTER_FEATURE_EXTRACTION ][moduleIndex]->process( inputVector ) ){
1796  errorLog << "predict_clusterer(VectorDouble inputVector) - Context Module Failed at AFTER_FEATURE_EXTRACTION. ModuleIndex: " << moduleIndex << endl;
1797  return false;
1798  }
1799  if( !contextModules[ AFTER_FEATURE_EXTRACTION ][moduleIndex]->getOK() ){
1800  predictionModuleIndex = AFTER_FEATURE_EXTRACTION;
1801  return false;
1802  }
1803  inputVector = contextModules[ AFTER_FEATURE_EXTRACTION ][moduleIndex]->getProcessedData();
1804  }
1805  }
1806 
1807  //Perform the classification
1808  if( !clusterer->predict(inputVector) ){
1809  errorLog << "predict_clusterer(VectorDouble inputVector) - Prediction Failed! " << clusterer->getLastErrorMessage() << endl;
1810  return false;
1811  }
1812  predictedClusterLabel = clusterer->getPredictedClusterLabel();
1813 
1814  //Update the context module
1815  if( contextModules[ AFTER_CLASSIFIER ].size() ){
1816  for(UINT moduleIndex=0; moduleIndex<contextModules[ AFTER_CLASSIFIER ].size(); moduleIndex++){
1817  if( !contextModules[ AFTER_CLASSIFIER ][moduleIndex]->process( vector<double>(1,predictedClusterLabel) ) ){
1818  errorLog << "predict_clusterer(VectorDouble inputVector) - Context Module Failed at AFTER_CLASSIFIER. ModuleIndex: " << moduleIndex << endl;
1819  return false;
1820  }
1821  if( !contextModules[ AFTER_CLASSIFIER ][moduleIndex]->getOK() ){
1822  predictionModuleIndex = AFTER_CLASSIFIER;
1823  return false;
1824  }
1825  predictedClusterLabel = (UINT)contextModules[ AFTER_CLASSIFIER ][moduleIndex]->getProcessedData()[0];
1826  }
1827  }
1828 
1829  //Perform any post processing
1830  predictionModuleIndex = AFTER_CLASSIFIER;
1831  if( getIsPostProcessingSet() ){
1832 
1833  if( pipelineMode != CLASSIFICATION_MODE){
1834  errorLog << "predict_clusterer(VectorDouble inputVector) - Pipeline Mode Is Not in CLASSIFICATION_MODE!" << endl;
1835  return false;
1836  }
1837 
1838  VectorDouble data;
1839  for(UINT moduleIndex=0; moduleIndex<postProcessingModules.size(); moduleIndex++){
1840 
1841  //Select which input we should give the postprocessing module
1842  if( postProcessingModules[moduleIndex]->getIsPostProcessingInputModePredictedClassLabel() ){
1843  //Set the input
1844  data.resize(1);
1845  data[0] = predictedClusterLabel;
1846 
1847  //Verify that the input size is OK
1848  if( data.size() != postProcessingModules[moduleIndex]->getNumInputDimensions() ){
1849  errorLog << "predict_clusterer(VectorDouble inputVector) - The size of the data vector (" << int(data.size()) << ") does not match that of the postProcessingModule (" << postProcessingModules[moduleIndex]->getNumInputDimensions() << ") at the moduleIndex: " << moduleIndex << endl;
1850  return false;
1851  }
1852 
1853  //Postprocess the data
1854  if( !postProcessingModules[moduleIndex]->process( data ) ){
1855  errorLog << "predict_clusterer(VectorDouble inputVector) - Failed to post process data. PostProcessing moduleIndex: " << moduleIndex << endl;
1856  return false;
1857  }
1858 
1859  //Select which output we should update
1860  data = postProcessingModules[moduleIndex]->getProcessedData();
1861  }
1862 
1863  //Select which output we should update
1864  if( postProcessingModules[moduleIndex]->getIsPostProcessingOutputModePredictedClassLabel() ){
1865  //Get the processed predicted class label
1866  data = postProcessingModules[moduleIndex]->getProcessedData();
1867 
1868  //Verify that the output size is OK
1869  if( data.size() != 1 ){
1870  errorLog << "predict_clusterer(VectorDouble inputVector) - The size of the processed data vector (" << int(data.size()) << ") from postProcessingModule at the moduleIndex: " << moduleIndex << " is not equal to 1 even though it is in OutputModePredictedClassLabel!" << endl;
1871  return false;
1872  }
1873 
1874  //Update the predicted cluster label
1875  predictedClusterLabel = (UINT)data[0];
1876  }
1877 
1878  }
1879  }
1880 
1881  //Update the context module
1882  predictionModuleIndex = END_OF_PIPELINE;
1883  if( contextModules[ END_OF_PIPELINE ].size() ){
1884  for(UINT moduleIndex=0; moduleIndex<contextModules[ END_OF_PIPELINE ].size(); moduleIndex++){
1885  if( !contextModules[ END_OF_PIPELINE ][moduleIndex]->process( vector<double>(1,predictedClassLabel) ) ){
1886  errorLog << "predict_clusterer(VectorDouble inputVector) - Context Module Failed at END_OF_PIPELINE. ModuleIndex: " << moduleIndex << endl;
1887  return false;
1888  }
1889  if( !contextModules[ END_OF_PIPELINE ][moduleIndex]->getOK() ){
1890  predictionModuleIndex = END_OF_PIPELINE;
1891  return false;
1892  }
1893  predictedClusterLabel = (UINT)contextModules[ END_OF_PIPELINE ][moduleIndex]->getProcessedData()[0];
1894  }
1895  }
1896 
1897  return true;
1898 }
1899 
1901 
1902  //Reset any pre processing
1903  if( getIsPreProcessingSet() ){
1904  for(UINT moduleIndex=0; moduleIndex<preProcessingModules.size(); moduleIndex++){
1905  if( !preProcessingModules[ moduleIndex ]->reset() ){
1906  errorLog << "Failed To Reset PreProcessingModule " << moduleIndex << endl;
1907  return false;
1908  }
1909  }
1910  }
1911 
1912  //Reset any feature extraction
1913  if( getIsFeatureExtractionSet() ){
1914  for(UINT moduleIndex=0; moduleIndex<featureExtractionModules.size(); moduleIndex++){
1915  if( !featureExtractionModules[ moduleIndex ]->reset() ){
1916  errorLog << "Failed To Reset FeatureExtractionModule " << moduleIndex << endl;
1917  return false;
1918  }
1919  }
1920  }
1921 
1922  //Reset the classifier
1923  if( getIsClassifierSet() ){
1924  if( !classifier->reset() ){
1925  errorLog << "Failed To Reset Classifier! " << classifier->getLastErrorMessage() << endl;
1926  return false;
1927  }
1928  }
1929 
1930  //Reset the regressiier
1931  if( getIsRegressifierSet() ){
1932  if( !regressifier->reset() ){
1933  errorLog << "Failed To Reset Regressifier! " << regressifier->getLastErrorMessage() << endl;
1934  return false;
1935  }
1936  }
1937 
1938  //Reset the clusterer
1939  if( getIsClustererSet() ){
1940  if( !clusterer->reset() ){
1941  errorLog << "Failed To Reset clusterer! " << clusterer->getLastErrorMessage() << endl;
1942  return false;
1943  }
1944  }
1945 
1946  //Reset any post processing
1947  if( getIsPostProcessingSet() ){
1948  for(UINT moduleIndex=0; moduleIndex<postProcessingModules.size(); moduleIndex++){
1949  if( !postProcessingModules[ moduleIndex ]->reset() ){
1950  errorLog << "Failed To Reset PostProcessingModule " << moduleIndex << endl;
1951  return false;
1952  }
1953  }
1954  }
1955 
1956  return true;
1957 }
1958 
1959 bool GestureRecognitionPipeline::save(const string &filename) const {
1960  return savePipelineToFile( filename );
1961 }
1962 
1963 bool GestureRecognitionPipeline::savePipelineToFile(const string &filename) const {
1964 
1965  if( !initialized ){
1966  errorLog << "Failed to write pipeline to file as the pipeline has not been initialized yet!" << endl;
1967  return false;
1968  }
1969 
1970  fstream file;
1971 
1972  file.open(filename.c_str(), iostream::out );
1973 
1974  if( !file.is_open() ){
1975  errorLog << "Failed to open file with filename: " << filename << endl;
1976  return false;
1977  }
1978 
1979  //Write the pipeline header info
1980  file << "GRT_PIPELINE_FILE_V3.0\n";
1981  file << "PipelineMode: " << getPipelineModeAsString() << endl;
1982  file << "NumPreprocessingModules: " << getNumPreProcessingModules() << endl;
1983  file << "NumFeatureExtractionModules: " << getNumFeatureExtractionModules() << endl;
1984  file << "NumPostprocessingModules: " << getNumPostProcessingModules() << endl;
1985  file << "Trained: " << getTrained() << endl;
1986  file << "Info: " << info << endl;
1987 
1988  //Write the module datatype names
1989  file << "PreProcessingModuleDatatypes:";
1990  for(UINT i=0; i<getNumPreProcessingModules(); i++){
1991  file << "\t" << preProcessingModules[i]->getPreProcessingType();
1992  }
1993  file << endl;
1994 
1995  file << "FeatureExtractionModuleDatatypes:";
1996  for(UINT i=0; i<getNumFeatureExtractionModules(); i++){
1997  file << "\t" << featureExtractionModules[i]->getFeatureExtractionType();
1998  }
1999  file << endl;
2000 
2001  switch( pipelineMode ){
2002  case PIPELINE_MODE_NOT_SET:
2003  break;
2004  case CLASSIFICATION_MODE:
2005  if( getIsClassifierSet() ) file << "ClassificationModuleDatatype:\t" << classifier->getClassifierType() << endl;
2006  else file << "ClassificationModuleDatatype:\tCLASSIFIER_NOT_SET" << endl;
2007  break;
2008  case REGRESSION_MODE:
2009  if( getIsRegressifierSet() ) file << "RegressionModuleDatatype:\t" << regressifier->getRegressifierType() << endl;
2010  else file << "RegressionModuleDatatype:\tREGRESSIFIER_NOT_SET" << endl;
2011  break;
2012  case CLUSTER_MODE:
2013  if( getIsClustererSet() ) file << "ClusterModuleDatatype:\t" << clusterer->getClustererType() << endl;
2014  else file << "ClusterModuleDatatype:\tCLUSTERER_NOT_SET" << endl;
2015  break;
2016  default:
2017  break;
2018  }
2019 
2020  file << "PostProcessingModuleDatatypes:";
2021  for(UINT i=0; i<getNumPostProcessingModules(); i++){
2022  file << "\t" << postProcessingModules[i]->getPostProcessingType();
2023  }
2024  file << endl;
2025 
2026  //Write the preprocessing module data to the file
2027  for(UINT i=0; i<getNumPreProcessingModules(); i++){
2028  file << "PreProcessingModule_" << Util::intToString(i+1) << endl;
2029  if( !preProcessingModules[i]->saveModelToFile( file ) ){
2030  errorLog << "Failed to write preprocessing module " << i << " settings to file!" << endl;
2031  file.close();
2032  return false;
2033  }
2034  }
2035 
2036  //Write the feature extraction module data to the file
2037  for(UINT i=0; i<getNumFeatureExtractionModules(); i++){
2038  file << "FeatureExtractionModule_" << Util::intToString(i+1) << endl;
2039  if( !featureExtractionModules[i]->saveModelToFile( file ) ){
2040  errorLog << "Failed to write feature extraction module " << i << " settings to file!" << endl;
2041  file.close();
2042  return false;
2043  }
2044  }
2045 
2046  switch( pipelineMode ){
2047  case PIPELINE_MODE_NOT_SET:
2048  break;
2049  case CLASSIFICATION_MODE:
2050  if( getIsClassifierSet() ){
2051  if( !classifier->saveModelToFile( file ) ){
2052  errorLog << "Failed to write classifier model to file!" << endl;
2053  file.close();
2054  return false;
2055  }
2056  }
2057  break;
2058  case REGRESSION_MODE:
2059  if( getIsRegressifierSet() ){
2060  if( !regressifier->saveModelToFile( file ) ){
2061  errorLog << "Failed to write regressifier model to file!" << endl;
2062  file.close();
2063  return false;
2064  }
2065  }
2066  break;
2067  case CLUSTER_MODE:
2068  if( getIsClustererSet() ){
2069  if( !clusterer->saveModelToFile( file ) ){
2070  errorLog << "Failed to write clusterer model to file!" << endl;
2071  file.close();
2072  return false;
2073  }
2074  }
2075  break;
2076  default:
2077  break;
2078  }
2079 
2080  //Write the post processing module data to the file
2081  for(UINT i=0; i<getNumPostProcessingModules(); i++){
2082  file << "PostProcessingModule_" << Util::intToString(i+1) << endl;
2083  if( !postProcessingModules[i]->saveModelToFile( file ) ){
2084  errorLog <<"Failed to write post processing module " << i << " settings to file!" << endl;
2085  file.close();
2086  return false;
2087  }
2088  }
2089 
2090  //Close the file
2091  file.close();
2092 
2093  return true;
2094 }
2095 
2096 bool GestureRecognitionPipeline::load(const string &filename){
2097  return loadPipelineFromFile( filename );
2098 }
2099 
2101 
2102  fstream file;
2103 
2104  //Clear any previous setup
2105  clearAll();
2106 
2107  file.open(filename.c_str(), iostream::in );
2108 
2109  if( !file.is_open() ){
2110  errorLog << "loadPipelineFromFile(string filename) - Failed to open file with filename: " << filename << endl;
2111  return false;
2112  }
2113 
2114  string word;
2115 
2116  //Load the file header
2117  file >> word;
2118  if( word != "GRT_PIPELINE_FILE_V3.0" ){
2119  errorLog << "loadPipelineFromFile(string filename) - Failed to read file header" << endl;
2120  file.close();
2121  return false;
2122  }
2123 
2124  //Load the pipeline mode
2125  file >> word;
2126  if( word != "PipelineMode:" ){
2127  errorLog << "loadPipelineFromFile(string filename) - Failed to read PipelineMode" << endl;
2128  file.close();
2129  return false;
2130  }
2131  file >> word;
2132  pipelineMode = getPipelineModeFromString(word);
2133 
2134  //Load the NumPreprocessingModules
2135  file >> word;
2136  if( word != "NumPreprocessingModules:" ){
2137  errorLog << "loadPipelineFromFile(string filename) - Failed to read NumPreprocessingModules header" << endl;
2138  file.close();
2139  return false;
2140  }
2141  unsigned int numPreprocessingModules;
2142  file >> numPreprocessingModules;
2143 
2144  //Load the NumFeatureExtractionModules
2145  file >> word;
2146  if( word != "NumFeatureExtractionModules:" ){
2147  errorLog << "loadPipelineFromFile(string filename) - Failed to read NumFeatureExtractionModules header" << endl;
2148  file.close();
2149  return false;
2150  }
2151  unsigned int numFeatureExtractionModules;
2152  file >> numFeatureExtractionModules;
2153 
2154  //Load the NumPostprocessingModules
2155  file >> word;
2156  if( word != "NumPostprocessingModules:" ){
2157  errorLog << "loadPipelineFromFile(string filename) - Failed to read NumPostprocessingModules header" << endl;
2158  file.close();
2159  return false;
2160  }
2161  unsigned int numPostprocessingModules;
2162  file >> numPostprocessingModules;
2163 
2164  //Load if the pipeline has been trained
2165  file >> word;
2166  if( word != "Trained:" ){
2167  errorLog << "loadPipelineFromFile(string filename) - Failed to read Trained header" << endl;
2168  file.close();
2169  return false;
2170  }
2171  file >> trained;
2172 
2173  //Load the info
2174  file >> word;
2175  if( word != "Info:" ){
2176  errorLog << "loadPipelineFromFile(string filename) - Failed to read Info header" << endl;
2177  file.close();
2178  return false;
2179  }
2180  info = "";
2181  //Read the info text
2182  file >> word;
2183  while( word != "PreProcessingModuleDatatypes:" ){
2184  info += word;
2185  file >> word;
2186  }
2187 
2188  //Resize the modules
2189  if( numPreprocessingModules > 0 ) preProcessingModules.resize(numPreprocessingModules,NULL);
2190  if( numFeatureExtractionModules > 0 ) featureExtractionModules.resize(numFeatureExtractionModules,NULL);
2191  if( numPostprocessingModules > 0 ) postProcessingModules.resize(numPostprocessingModules,NULL);
2192 
2193  //Load the preprocessing module datatypes and initialize the modules
2194  if( word != "PreProcessingModuleDatatypes:" ){
2195  errorLog << "loadPipelineFromFile(string filename) - Failed to read PreProcessingModuleDatatypes" << endl;
2196  file.close();
2197  return false;
2198  }
2199  for(UINT i=0; i<numPreprocessingModules; i++){
2200  file >> word;
2201  preProcessingModules[i] = PreProcessing::createInstanceFromString( word );
2202  if( preProcessingModules[i] == NULL ){
2203  errorLog << "loadPipelineFromFile(string filename) - Failed to create preprocessing instance from string: " << word << endl;
2204  file.close();
2205  return false;
2206  }
2207  }
2208 
2209  //Load the feature extraction module datatypes and initialize the modules
2210  file >> word;
2211  if( word != "FeatureExtractionModuleDatatypes:" ){
2212  errorLog << "loadPipelineFromFile(string filename) - Failed to read FeatureExtractionModuleDatatypes" << endl;
2213  file.close();
2214  return false;
2215  }
2216  for(UINT i=0; i<numFeatureExtractionModules; i++){
2217  file >> word;
2218  featureExtractionModules[i] = FeatureExtraction::createInstanceFromString( word );
2219  if( featureExtractionModules[i] == NULL ){
2220  errorLog << "loadPipelineFromFile(string filename) - Failed to create feature extraction instance from string: " << word << endl;
2221  file.close();
2222  return false;
2223  }
2224  }
2225 
2226  switch( pipelineMode ){
2227  case PIPELINE_MODE_NOT_SET:
2228  break;
2229  case CLASSIFICATION_MODE:
2230  file >> word;
2231  if( word != "ClassificationModuleDatatype:" ){
2232  errorLog << "loadPipelineFromFile(string filename) - Failed to read ClassificationModuleDatatype" << endl;
2233  file.close();
2234  return false;
2235  }
2236  //Load the classifier type
2237  file >> word;
2238 
2239  //Initialize the classifier
2240  classifier = Classifier::createInstanceFromString( word );
2241  if( classifier == NULL ){
2242  errorLog << "loadPipelineFromFile(string filename) - Failed to create classifier instance from string: " << word << endl;
2243  file.close();
2244  return false;
2245  }
2246  break;
2247  case REGRESSION_MODE:
2248  file >> word;
2249  if( word != "RegressionModuleDatatype:" ){
2250  errorLog << "loadPipelineFromFile(string filename) - Failed to read RegressionModuleDatatype" << endl;
2251  file.close();
2252  return false;
2253  }
2254  //Load the regressifier type
2255  file >> word;
2256 
2257  //Initialize the regressifier
2258  regressifier = Regressifier::createInstanceFromString( word );
2259  if( regressifier == NULL ){
2260  errorLog << "loadPipelineFromFile(string filename) - Failed to create regressifier instance from string: " << word << endl;
2261  file.close();
2262  return false;
2263  }
2264  break;
2265  case CLUSTER_MODE:
2266  file >> word;
2267  if( word != "ClusterModuleDatatype:" ){
2268  errorLog << "loadPipelineFromFile(string filename) - Failed to read ClusterModuleDatatype" << endl;
2269  file.close();
2270  return false;
2271  }
2272  //Load the clusterer type
2273  file >> word;
2274 
2275  //Initialize the clusterer
2276  clusterer = Clusterer::createInstanceFromString( word );
2277  if( clusterer == NULL ){
2278  errorLog << "loadPipelineFromFile(string filename) - Failed to create clusterer instance from string: " << word << endl;
2279  file.close();
2280  return false;
2281  }
2282  break;
2283  default:
2284  break;
2285  }
2286 
2287  //Load the post processing module datatypes and initialize the modules
2288  file >> word;
2289  if( word != "PostProcessingModuleDatatypes:" ){
2290  errorLog << "loadPipelineFromFile(string filename) - Failed to read PostProcessingModuleDatatypes" << endl;
2291  file.close();
2292  return false;
2293  }
2294  for(UINT i=0; i<numPostprocessingModules; i++){
2295  file >> word;
2296  postProcessingModules[i] = PostProcessing::createInstanceFromString( word );
2297  }
2298 
2299  //Load the preprocessing module data from the file
2300  for(UINT i=0; i<numPreprocessingModules; i++){
2301  //Load the preprocessing module header
2302  file >> word;
2303  if( !preProcessingModules[i]->loadModelFromFile( file ) ){
2304  errorLog << "Failed to load preprocessing module " << i << " settings from file!" << endl;
2305  file.close();
2306  return false;
2307  }
2308  }
2309 
2310  //Load the feature extraction module data from the file
2311  for(UINT i=0; i<numFeatureExtractionModules; i++){
2312  //Load the feature extraction module header
2313  file >> word;
2314  if( !featureExtractionModules[i]->loadModelFromFile( file ) ){
2315  errorLog << "Failed to load feature extraction module " << i << " settings from file!" << endl;
2316  file.close();
2317  return false;
2318  }
2319  }
2320 
2321  //Load the classifier or regressifer data
2322  switch( pipelineMode ){
2323  case PIPELINE_MODE_NOT_SET:
2324  break;
2325  case CLASSIFICATION_MODE:
2326  if( !classifier->loadModelFromFile( file ) ){
2327  errorLog << "Failed to load classifier model from file!" << endl;
2328  file.close();
2329  return false;
2330  }
2331  break;
2332  case REGRESSION_MODE:
2333  if( !regressifier->loadModelFromFile( file ) ){
2334  errorLog << "Failed to load regressifier model from file!" << endl;
2335  file.close();
2336  return false;
2337  }
2338  break;
2339  case CLUSTER_MODE:
2340  if( !clusterer->loadModelFromFile( file ) ){
2341  errorLog << "Failed to load cluster model from file!" << endl;
2342  file.close();
2343  return false;
2344  }
2345  break;
2346  default:
2347  break;
2348  }
2349 
2350  //Load the post processing module data from the file
2351  for(UINT i=0; i<numPostprocessingModules; i++){
2352  //Load the post processing module header
2353  file >> word;
2354  if( !postProcessingModules[i]->loadModelFromFile( file ) ){
2355  errorLog << "Failed to load post processing module " << i << " settings from file!" << endl;
2356  file.close();
2357  return false;
2358  }
2359  }
2360 
2361  //Close the file
2362  file.close();
2363 
2364  //Set the expected input vector size
2365  inputVectorDimensions = 0;
2366 
2367  if( numPreprocessingModules > 0 ){
2368  inputVectorDimensions = preProcessingModules[0]->getNumInputDimensions();
2369  }else{
2370  if( numFeatureExtractionModules > 0 ){
2371  inputVectorDimensions = featureExtractionModules[0]->getNumInputDimensions();
2372  }else{
2373  switch( pipelineMode ){
2374  case PIPELINE_MODE_NOT_SET:
2375  break;
2376  case CLASSIFICATION_MODE:
2377  inputVectorDimensions = classifier->getNumInputDimensions();
2378  break;
2379  case REGRESSION_MODE:
2380  inputVectorDimensions = regressifier->getNumInputDimensions();
2381  break;
2382  case CLUSTER_MODE:
2383  inputVectorDimensions = clusterer->getNumInputDimensions();
2384  break;
2385  default:
2386  break;
2387  }
2388  }
2389  }
2390 
2391  return true;
2392 }
2393 
2394 bool GestureRecognitionPipeline::preProcessData(VectorDouble inputVector,bool computeFeatures){
2395 
2396  if( getIsPreProcessingSet() ){
2397  for(UINT moduleIndex=0; moduleIndex<preProcessingModules.size(); moduleIndex++){
2398 
2399  if( inputVector.size() != preProcessingModules[ moduleIndex ]->getNumInputDimensions() ){
2400  errorLog << "preProcessData(VectorDouble inputVector) - The size of the input vector (" << preProcessingModules[ moduleIndex ]->getNumInputDimensions() << ") does not match that of the PreProcessing Module at moduleIndex: " << moduleIndex << endl;
2401  return false;
2402  }
2403 
2404  if( !preProcessingModules[ moduleIndex ]->process( inputVector ) ){
2405  errorLog << "preProcessData(VectorDouble inputVector) - Failed To PreProcess Input Vector. PreProcessing moduleIndex: " << moduleIndex << endl;
2406  return false;
2407  }
2408  inputVector = preProcessingModules[ moduleIndex ]->getProcessedData();
2409  }
2410  }
2411 
2412  //Perform any feature extraction
2413  if( getIsFeatureExtractionSet() && computeFeatures ){
2414  for(UINT moduleIndex=0; moduleIndex<featureExtractionModules.size(); moduleIndex++){
2415  if( inputVector.size() != featureExtractionModules[ moduleIndex ]->getNumInputDimensions() ){
2416  errorLog << "preProcessData(VectorDouble inputVector) - The size of the input vector (" << featureExtractionModules[ moduleIndex ]->getNumInputDimensions() << ") does not match that of the FeatureExtraction Module at moduleIndex: " << moduleIndex << endl;
2417  return false;
2418  }
2419 
2420  if( !featureExtractionModules[ moduleIndex ]->computeFeatures( inputVector ) ){
2421  errorLog << "preProcessData(VectorDouble inputVector) - Failed To Compute Features from Input Vector. FeatureExtraction moduleIndex: " << moduleIndex << endl;
2422  return false;
2423  }
2424  inputVector = featureExtractionModules[ moduleIndex ]->getFeatureVector();
2425  }
2426  }
2427 
2428  return true;
2429 }
2430 
2433  return initialized;
2434 }
2435 
2437  return trained;
2438 }
2439 
2441  return preProcessingModules.size() > 0;
2442 }
2443 
2445  return featureExtractionModules.size() > 0;
2446 }
2447 
2449  return (classifier!=NULL);
2450 }
2451 
2453  return (regressifier!=NULL);
2454 }
2455 
2457  return (clusterer!=NULL);
2458 }
2459 
2461  return postProcessingModules.size() > 0;
2462 }
2463 
2465  for(UINT i=0; i<NUM_CONTEXT_LEVELS; i++){
2466  if( contextModules[i].size() > 0 ) return true;
2467  }
2468  return false;
2469 }
2470 
2472  return (pipelineMode!=PIPELINE_MODE_NOT_SET);
2473 }
2474 
2476  return (pipelineMode==CLASSIFICATION_MODE);
2477 }
2478 
2480  return pipelineMode==REGRESSION_MODE;
2481 }
2482 
2484 
2485  if( getIsPreProcessingSet() ){
2486  return preProcessingModules[0]->getNumInputDimensions();
2487  }
2488 
2489  if( getIsFeatureExtractionSet() ){
2490  return featureExtractionModules[0]->getNumInputDimensions();
2491  }
2492 
2494  return classifier->getNumInputFeatures();
2495  }
2497  return regressifier->getNumInputFeatures();
2498  }
2499  return 0;
2500 }
2501 
2503  if( getIsClassifierSet() ) return 1; //The output of the pipeline for classification will always be 1
2504  if( getIsRegressifierSet() ){
2505  return regressifier->getNumOutputDimensions();
2506  }
2507  return 0;
2508 }
2509 
2511  return getNumClasses();
2512 }
2513 
2515  UINT numClasses = 0;
2516  if( getIsClassifierSet() ){
2517  numClasses = classifier->getNumClasses();
2518  }
2519  if( getIsClustererSet() ){
2520  numClasses = clusterer->getNumClusters();
2521  }
2522  return numClasses;
2523 }
2524 
2526  return (UINT)preProcessingModules.size();
2527 }
2528 
2530  return (UINT)featureExtractionModules.size();
2531 }
2532 
2534  return (UINT)postProcessingModules.size();
2535 }
2536 
2538  return predictionModuleIndex;
2539 }
2540 
2542 
2543  if( getIsClassifierSet() ){
2544  return predictedClassLabel;
2545  }
2546  if( getIsClustererSet() ){
2547  return predictedClusterLabel;
2548  }
2549  return 0;
2550 }
2551 
2553  if( getIsClassifierSet() ){
2554  return classifier->getPredictedClassLabel();
2555  }
2556  if( getIsClustererSet() ){
2557  return clusterer->getPredictedClusterLabel();
2558  }
2559  return 0;
2560 }
2561 
2563  return numTrainingSamples;
2564 }
2565 
2567  return numTestSamples;
2568 }
2569 
2571  if( getIsClassifierSet() ){
2572  return classifier->getMaximumLikelihood();
2573  }
2574  if( getIsClustererSet() ){
2575  return clusterer->getMaximumLikelihood();
2576  }
2577  return 0;
2578 }
2579 
2581  if( getIsClassifierSet() ){
2582  return classifier->getPhase();
2583  }
2584  return 0;
2585 }
2586 
2588  return (getIsClassifierSet()||getIsRegressifierSet() ? testAccuracy : 0);
2589 }
2590 
2592  return testAccuracy;
2593 }
2594 
2596  return testRMSError;
2597 }
2598 
2600  return testSquaredError;
2601 }
2602 
2603 double GestureRecognitionPipeline::getTestFMeasure(const UINT classLabel) const{
2604 
2605  if( !getIsClassifierSet() ) return -1;
2606  if( getClassLabels().size() != testFMeasure.size() ) return -1;
2607 
2608  for(UINT i=0; i<testFMeasure.size(); i++){
2609  if( getClassLabels()[i] == classLabel ){
2610  return testFMeasure[i];
2611  }
2612  }
2613  return -1;
2614 }
2615 
2616 double GestureRecognitionPipeline::getTestPrecision(const UINT classLabel) const{
2617 
2618  if( !getIsClassifierSet() ) return -1;
2619  if( getClassLabels().size() != testPrecision.size() ) return -1;
2620 
2621  for(UINT i=0; i<testPrecision.size(); i++){
2622  if( getClassLabels()[i] == classLabel ){
2623  return testPrecision[i];
2624  }
2625  }
2626  return -1;
2627 }
2628 
2629 double GestureRecognitionPipeline::getTestRecall(const UINT classLabel) const{
2630 
2631  if( !getIsClassifierSet() ) return -1;
2632  if( getClassLabels().size() != testRecall.size() ) return -1;
2633 
2634  for(UINT i=0; i<testRecall.size(); i++){
2635  if( getClassLabels()[i] == classLabel ){
2636  return testRecall[i];
2637  }
2638  }
2639  return -1;
2640 }
2641 
2643  return testRejectionPrecision;
2644 }
2645 
2647  return testRejectionRecall;
2648 }
2649 
2651  return testTime;
2652 }
2653 
2655  return trainingTime;
2656 }
2657 
2659  return getIsRegressifierSet() ? regressifier->getRootMeanSquaredTrainingError() : 0;
2660 }
2661 
2663  return getIsRegressifierSet() ? regressifier->getTotalSquaredTrainingError() : 0;
2664 }
2665 
2667  return testConfusionMatrix;
2668 }
2669 
2671  TestResult testResults;
2672  testResults.numTrainingSamples = numTrainingSamples;
2673  testResults.numTestSamples = numTestSamples;
2674  testResults.accuracy = testAccuracy;
2675  testResults.rmsError = testRMSError;
2676  testResults.totalSquaredError = testSquaredError;
2677  testResults.trainingTime = trainingTime;
2678  testResults.testTime = testTime;
2679  testResults.rejectionPrecision = testRejectionPrecision;
2680  testResults.rejectionRecall = testRejectionRecall;
2681  testResults.precision = testPrecision;
2682  testResults.recall = testRecall;
2683  testResults.fMeasure = testFMeasure;
2684  testResults.confusionMatrix = testConfusionMatrix;
2685  return testResults;
2686 }
2687 
2689  return testPrecision;
2690 }
2691 
2693  return testRecall;
2694 }
2695 
2697  return testFMeasure;
2698 }
2699 
2701  if( getIsClassifierSet() ){ return classifier->getClassLikelihoods(); }
2702  if( getIsClustererSet() ){ return clusterer->getClusterLikelihoods(); }
2703  else{ return VectorDouble(); }
2704 }
2705 
2707  if( getIsClassifierSet() ){ return classifier->getClassDistances(); }
2708  if( getIsClustererSet() ){ return clusterer->getClusterDistances(); }
2709  else{ return VectorDouble(); }
2710 }
2711 
2713  if( getIsClassifierSet() ){ return classifier->getNullRejectionThresholds(); }
2714  else{ return VectorDouble(); }
2715 }
2716 
2718  return regressionData;
2719 }
2720 
2722  if( getIsRegressifierSet() ) {
2723  return regressifier->getRegressionData();
2724  }
2725  return VectorDouble();
2726 }
2727 
2729  if( getIsPreProcessingSet() ){
2730  return preProcessingModules[ preProcessingModules.size()-1 ]->getProcessedData();
2731  }
2732  return VectorDouble();
2733 }
2734 
2735 VectorDouble GestureRecognitionPipeline::getPreProcessedData(const UINT moduleIndex) const{
2736  if( getIsPreProcessingSet() ){
2737  if( moduleIndex < preProcessingModules.size() ){
2738  return preProcessingModules[ moduleIndex ]->getProcessedData();
2739  }
2740  }
2741  return VectorDouble();
2742 }
2743 
2745  if( getIsFeatureExtractionSet() ){
2746  return featureExtractionModules[ featureExtractionModules.size()-1 ]->getFeatureVector();
2747  }
2748  return VectorDouble();
2749 }
2750 
2751 VectorDouble GestureRecognitionPipeline::getFeatureExtractionData(const UINT moduleIndex) const{
2752  if( getIsFeatureExtractionSet() ){
2753  if( moduleIndex < featureExtractionModules.size() ){
2754  return featureExtractionModules[ moduleIndex ]->getFeatureVector();
2755  }
2756  }
2757  warningLog << "getFeatureExtractionData(UINT moduleIndex) - Failed to get class labels!" << endl;
2758  return VectorDouble();
2759 }
2760 
2762  if( getIsClassifierSet() ){
2763  return classifier->getClassLabels();
2764  }
2765  if( getIsClustererSet() ){
2766  return clusterer->getClusterLabels();
2767  }
2768  warningLog << "getClassLabels() - Failed to get class labels!" << endl;
2769  return vector< UINT>();
2770 }
2771 
2772 vector< TestInstanceResult > GestureRecognitionPipeline::getTestInstanceResults() const{
2773  return testResults;
2774 }
2775 
2777  return crossValidationResults;
2778 }
2779 
2781  if( moduleIndex < preProcessingModules.size() ){
2782  return preProcessingModules[ moduleIndex ];
2783  }
2784  warningLog << "getPreProcessingModule(const UINT moduleIndex) - Failed to get pre processing module!" << endl;
2785  return NULL;
2786 }
2787 
2789  if( moduleIndex < featureExtractionModules.size() ){
2790  return featureExtractionModules[ moduleIndex ];
2791  }
2792  warningLog << "getFeatureExtractionModule(const UINT moduleIndex) - Failed to get feature extraction module!" << endl;
2793  return NULL;
2794 }
2795 
2797  return classifier;
2798 }
2799 
2801  return regressifier;
2802 }
2803 
2805  return clusterer;
2806 }
2807 
2809  if( moduleIndex < postProcessingModules.size() ){
2810  return postProcessingModules[ moduleIndex ];
2811  }
2812  warningLog << "getPostProcessingModule(UINT moduleIndex) - Failed to get post processing module!" << endl;
2813  return NULL;
2814 }
2815 
2816 Context* GestureRecognitionPipeline::getContextModule(UINT contextLevel,UINT moduleIndex) const{
2817  if( contextLevel < contextModules.size() ){
2818  if( moduleIndex < contextModules[ contextLevel ].size() ){
2819  return contextModules[ contextLevel ][ moduleIndex ];
2820  }
2821  }
2822  warningLog << "getContextModule(UINT contextLevel,UINT moduleIndex) - Failed to get context module!" << endl;
2823  return NULL;
2824 }
2825 
2829 
2830 bool GestureRecognitionPipeline::addPreProcessingModule(const PreProcessing &preProcessingModule,UINT insertIndex){
2831 
2832  //Validate the insertIndex is valid
2833  if( insertIndex != INSERT_AT_END_INDEX && insertIndex >= preProcessingModules.size() ){
2834  errorLog << "addPreProcessingModule(const PreProcessing &preProcessingModule) - Invalid insertIndex value!" << endl;
2835  return false;
2836  }
2837 
2838  //Create a new instance of the preProcessing and then clone the values across from the reference preProcessing
2839  PreProcessing *newInstance = preProcessingModule.createNewInstance();
2840 
2841  //Verify that the clone was successful
2842  if( !newInstance->deepCopyFrom( &preProcessingModule ) ){
2843  delete newInstance;
2844  newInstance = NULL;
2845  errorLog << "addPreProcessingModule(const PreProcessing &preProcessingModule) - PreProcessing Module Not Set!" << endl;
2846  return false;
2847  }
2848 
2849  //Add the new instance to the preProcessingModules
2850  vector< PreProcessing* >::iterator iter = preProcessingModules.begin();
2851 
2852  if( insertIndex == INSERT_AT_END_INDEX ) iter = preProcessingModules.end();
2853  else iter = preProcessingModules.begin() + insertIndex;
2854 
2855  preProcessingModules.insert(iter, newInstance);
2856 
2857  //The pipeline has been changed, so flag that the pipeline is no longer trained
2858  trained = false;
2859 
2860  return true;
2861 }
2862 
2865  return addPreProcessingModule( preProcessingModule );
2866 }
2867 
2868 bool GestureRecognitionPipeline::addFeatureExtractionModule(const FeatureExtraction &featureExtractionModule,UINT insertIndex){
2869 
2870  //Validate the insertIndex is valid
2871  if( insertIndex != INSERT_AT_END_INDEX && insertIndex >= featureExtractionModules.size() ){
2872  errorLog << "addFeatureExtractionModule(const FeatureExtraction &featureExtractionModule) - Invalid insertIndex value!" << endl;
2873  return false;
2874  }
2875 
2876  //Create a new instance of the preProcessing and then clone the values across from the reference preProcessing
2877  FeatureExtraction *newInstance = featureExtractionModule.createNewInstance();
2878 
2879  //Verify that the clone was successful
2880  if( !newInstance->deepCopyFrom( &featureExtractionModule ) ){
2881  delete newInstance;
2882  newInstance = NULL;
2883  errorLog << "addFeatureExtractionModule(const FeatureExtraction &featureExtractionModule - FeatureExtraction Module Not Set!" << endl;
2884  return false;
2885  }
2886 
2887  //Add the new instance to the preProcessingModules
2888  vector< FeatureExtraction* >::iterator iter = featureExtractionModules.begin();
2889 
2890  if( insertIndex == INSERT_AT_END_INDEX ) iter = featureExtractionModules.end();
2891  else iter = featureExtractionModules.begin() + insertIndex;
2892 
2893  featureExtractionModules.insert(iter, newInstance);
2894 
2895  //The pipeline has been changed, so flag that the pipeline is no longer trained
2896  trained = false;
2897 
2898  return true;
2899 }
2900 
2903  return addFeatureExtractionModule( featureExtractionModule );
2904 }
2905 
2907 
2908  //Delete any previous classifier, regressifier or clusterer
2909  deleteClassifier();
2910  deleteRegressifier();
2911  deleteClusterer();
2912 
2913  //Create a new instance of the classifier and then clone the values across from the reference classifier
2914  this->classifier = classifier.createNewInstance();
2915 
2916  if( this->classifier == NULL ){
2917  errorLog << "setClassifier(const Classifier classifier) - Classifier Module Not Set!" << endl;
2918  return false;
2919  }
2920 
2921  //Deep copy the data from the rhs classifier into this classifier
2922  if( !this->classifier->deepCopyFrom( &classifier ) ){
2923  deleteClassifier();
2924  pipelineMode = PIPELINE_MODE_NOT_SET;
2925  errorLog << "setClassifier(const Classifier classifier) - Classifier Module Not Set!" << endl;
2926  return false;
2927  }
2928 
2929  //Set the mode of the pipeline to classification mode
2930  pipelineMode = CLASSIFICATION_MODE;
2931 
2932  //Flag that the key part of the pipeline has now been initialized
2933  initialized = true;
2934 
2935  //If there is no preprocessing / feature extraction and the classifier is trained, then flag the pipeline is trained
2936  //Otherwise the user needs to train the pipeline
2937  if( !getIsPreProcessingSet() && !getIsFeatureExtractionSet() && classifier.getTrained() ){
2938  inputVectorDimensions = classifier.getNumInputDimensions();
2939  trained = true;
2940  }else trained = false;
2941 
2942  return true;
2943 }
2944 
2946 
2947  //Delete any previous classifier, regressifier or clusterer
2948  deleteClassifier();
2949  deleteRegressifier();
2950  deleteClusterer();
2951 
2952  //Set the mode of the pipeline to regression mode
2953  pipelineMode = REGRESSION_MODE;
2954 
2955  //Create a new instance of the regressifier and then clone the values across from the reference regressifier
2956  this->regressifier = regressifier.createNewInstance();
2957 
2958  //Validate that the regressifier was cloned correctly
2959  if( !this->regressifier->deepCopyFrom( &regressifier ) ){
2960  deleteRegressifier();
2961  pipelineMode = PIPELINE_MODE_NOT_SET;
2962  errorLog << "setRegressifier(const Regressifier &regressifier) - Regressifier Module Not Set!" << endl;
2963  return false;
2964  }
2965 
2966  //Flag that the key part of the pipeline has now been initialized
2967  initialized = true;
2968 
2969  //If there is no preprocessing / feature extraction and the regressifier is trained, then flag the pipeline is trained
2970  //Otherwise the user needs to train the pipeline
2972  trained = regressifier.getTrained();
2973  }else trained = false;
2974 
2975  return true;
2976 }
2977 
2979 
2980  //Delete any previous classifier, regressifier or clusterer
2981  deleteClassifier();
2982  deleteRegressifier();
2983  deleteClusterer();
2984 
2985  //Set the mode of the pipeline to cluster mode
2986  pipelineMode = CLUSTER_MODE;
2987 
2988  //Create a new instance of the clusterer and then clone the values across from the reference clusterer
2989  this->clusterer = clusterer.createNewInstance();
2990 
2991  //Validate that the regressifier was cloned correctly
2992  if( !this->clusterer->deepCopyFrom( &clusterer ) ){
2993  deleteClusterer();
2994  pipelineMode = PIPELINE_MODE_NOT_SET;
2995  errorLog << "setClusterer(const Clusterer &clusterer) - Clusterer Module Not Set!" << endl;
2996  return false;
2997  }
2998 
2999  //Flag that the key part of the pipeline has now been initialized
3000  initialized = true;
3001 
3002  //If there is no preprocessing / feature extraction and the regressifier is trained, then flag the pipeline is trained
3003  //Otherwise the user needs to train the pipeline
3005  trained = clusterer.getTrained();
3006  }else trained = false;
3007 
3008  return true;
3009 }
3010 
3011 bool GestureRecognitionPipeline::addPostProcessingModule(const PostProcessing &postProcessingModule,UINT insertIndex){
3012 
3013  //Validate the insertIndex is valid
3014  if( insertIndex != INSERT_AT_END_INDEX && insertIndex >= postProcessingModules.size() ){
3015  errorLog << "addPostProcessingModule((const PostProcessing &postProcessingModule) - Invalid insertIndex value!" << endl;
3016  return false;
3017  }
3018 
3019  //Create a new instance of the preProcessing and then clone the values across from the reference preProcessing
3020  PostProcessing *newInstance = postProcessingModule.createNewInstance();
3021 
3022  //Verify that the clone was successful
3023  if( !newInstance->deepCopyFrom( &postProcessingModule ) ){
3024  delete newInstance;
3025  newInstance = NULL;
3026  errorLog << "addPostProcessingModule(const PostProcessing &postProcessingModule) - PostProcessing Module Not Set!" << endl;
3027  return false;
3028  }
3029 
3030  //Add the new instance to the postProcessingModules
3031  vector< PostProcessing* >::iterator iter = postProcessingModules.begin();
3032 
3033  if( insertIndex == INSERT_AT_END_INDEX ) iter = postProcessingModules.end();
3034  else iter = postProcessingModules.begin() + insertIndex;
3035 
3036  postProcessingModules.insert(iter, newInstance);
3037 
3038  //The pipeline has been changed, so flag that the pipeline is no longer trained
3039  trained = false;
3040 
3041  return true;
3042 }
3043 
3046  return addPostProcessingModule( postProcessingModule );
3047 }
3048 
3049 bool GestureRecognitionPipeline::addContextModule(const Context &contextModule,UINT contextLevel,UINT insertIndex){
3050 
3051  //Validate the contextLevel is valid
3052  if( contextLevel >= contextModules.size() ){
3053  errorLog << "addContextModule(...) - Invalid contextLevel value!" << endl;
3054  return false;
3055  }
3056 
3057  //Validate the insertIndex is valid
3058  if( insertIndex != INSERT_AT_END_INDEX && insertIndex >= contextModules[contextLevel].size() ){
3059  errorLog << "addContextModule(...) - Invalid insertIndex value!" << endl;
3060  return false;
3061  }
3062 
3063  //Create a new instance of the preProcessing and then clone the values across from the reference preProcessing
3064  Context *newInstance = contextModule.createNewInstance();
3065 
3066  //Verify that the clone was successful
3067  if( !newInstance->deepCopyFrom( &contextModule ) ){
3068  delete newInstance;
3069  newInstance = NULL;
3070  errorLog << "addContextModule(...) - Context Module Not Set!" << endl;
3071  return false;
3072  }
3073 
3074  //Add the new instance to the contextModules
3075  vector< Context* >::iterator iter = contextModules[ contextLevel ].begin();
3076 
3077  if( insertIndex == INSERT_AT_END_INDEX ) iter = contextModules[ contextLevel ].end();
3078  else iter = contextModules[ contextLevel ].begin() + insertIndex;
3079 
3080  contextModules[ contextLevel ].insert(iter, newInstance);
3081 
3082  return true;
3083 }
3084 
3085 bool GestureRecognitionPipeline::updateContextModule(bool value,UINT contextLevel,UINT moduleIndex){
3086 
3087  //Validate the contextLevel is valid
3088  if( contextLevel >= contextModules.size() ){
3089  errorLog << "updateContextModule(...) - Context Level is out of bounds!" << endl;
3090  return false;
3091  }
3092 
3093  //Validate the moduleIndex is valid
3094  if( moduleIndex >= contextModules[contextLevel].size() ){
3095  errorLog << "updateContextModule(...) - Invalid contextLevel value!" << endl;
3096  return false;
3097  }
3098 
3099  return contextModules[contextLevel][moduleIndex]->updateContext( value );
3100 }
3101 
3103  deleteAllPreProcessingModules();
3104  return true;
3105 }
3106 
3108  if( moduleIndex >= preProcessingModules.size() ){
3109  errorLog << "removePreProcessingModule(UINT moduleIndex) - Invalid moduleIndex " << moduleIndex << ". The size of the preProcessingModules vector is " << int(preProcessingModules.size()) << endl;
3110  return false;
3111  }
3112 
3113  //Delete the module
3114  delete preProcessingModules[ moduleIndex ];
3115  preProcessingModules[ moduleIndex ] = NULL;
3116  preProcessingModules.erase( preProcessingModules.begin() + moduleIndex );
3117 
3118  //The pipeline has been changed, so flag that the pipeline is no longer trained
3119  trained = false;
3120 
3121  return true;
3122 }
3123 
3125  deleteAllFeatureExtractionModules();
3126  return true;
3127 }
3128 
3130  if( moduleIndex >= featureExtractionModules.size() ){
3131  errorLog << "removeFeatureExtractionModule(UINT moduleIndex) - Invalid moduleIndex " << moduleIndex << ". The size of the featureExtractionModules vector is " << int(featureExtractionModules.size()) << endl;
3132  return false;
3133  }
3134 
3135  //Delete the module
3136  delete featureExtractionModules[ moduleIndex ];
3137  featureExtractionModules[ moduleIndex ] = NULL;
3138  featureExtractionModules.erase( featureExtractionModules.begin() + moduleIndex );
3139 
3140  //The pipeline has been changed, so flag that the pipeline is no longer trained
3141  trained = false;
3142 
3143  return true;
3144 }
3145 
3147  deleteAllPostProcessingModules();
3148  return true;
3149 }
3150 
3152  if( moduleIndex >= postProcessingModules.size() ){
3153  errorLog << "removePostProcessingModule(UINT moduleIndex) - Invalid moduleIndex " << moduleIndex << ". The size of the postProcessingModules vector is " << int(postProcessingModules.size()) << endl;
3154  return false;
3155  }
3156 
3157  //Delete the module
3158  delete postProcessingModules[ moduleIndex ];
3159  postProcessingModules[ moduleIndex ] = NULL;
3160  postProcessingModules.erase( postProcessingModules.begin() + moduleIndex );
3161 
3162  //The pipeline has been changed, so flag that the pipeline is no longer trained
3163  trained = false;
3164 
3165  return true;
3166 }
3167 
3168 bool GestureRecognitionPipeline::removeContextModule(UINT contextLevel,UINT moduleIndex){
3169  if( contextLevel >= NUM_CONTEXT_LEVELS ){
3170  errorLog << "removeContextModule(UINT contextLevel,UINT moduleIndex) - Invalid moduleIndex " << moduleIndex << " is out of bounds!" << endl;
3171  return false;
3172  }
3173 
3174  if( moduleIndex >= contextModules[contextLevel].size() ){
3175  errorLog << "removePostProcessingModule(UINT moduleIndex) - Invalid moduleIndex " << moduleIndex << ". The size of the contextModules vector at context level " << " is " << int(contextModules[contextLevel].size()) << endl;
3176  return false;
3177  }
3178 
3179  //Delete the module
3180  delete contextModules[contextLevel][moduleIndex];
3181  contextModules[contextLevel][moduleIndex] = NULL;
3182  contextModules[contextLevel].erase( contextModules[contextLevel].begin() + moduleIndex );
3183  return true;
3184 }
3185 
3187  deleteAllContextModules();
3188  return true;
3189 }
3190 
3192 
3193  clearTestResults();
3196  removeClassifier();
3200 
3201  return true;
3202 }
3203 
3205 
3206  numTestSamples = 0;
3207  testAccuracy = 0;
3208  testRMSError = 0;
3209  testSquaredError = 0;
3210  testTime = 0;
3211  testFMeasure.clear();
3212  testPrecision.clear();
3213  testRecall.clear();
3214  testRejectionPrecision = 0;
3215  testRejectionRecall = 0;
3216  testConfusionMatrix.clear();
3217  testResults.clear();
3218  crossValidationResults.clear();
3219 
3220  return true;
3221 }
3222 
3223 bool GestureRecognitionPipeline::setInfo(const string info){
3224  this->info = info;
3225  return true;
3226 }
3227 
3231 
3232 void GestureRecognitionPipeline::deleteAllPreProcessingModules(){
3233  if( preProcessingModules.size() != 0 ){
3234  for(UINT i=0; i<preProcessingModules.size(); i++){
3235  delete preProcessingModules[i];
3236  preProcessingModules[i] = NULL;
3237  }
3238  preProcessingModules.clear();
3239  trained = false;
3240  }
3241 }
3242 
3243 void GestureRecognitionPipeline::deleteAllFeatureExtractionModules(){
3244  if( featureExtractionModules.size() != 0 ){
3245  for(UINT i=0; i<featureExtractionModules.size(); i++){
3246  delete featureExtractionModules[i];
3247  featureExtractionModules[i] = NULL;
3248  }
3249  featureExtractionModules.clear();
3250  trained = false;
3251  }
3252 }
3253 
3254 void GestureRecognitionPipeline::deleteClassifier(){
3255  if( classifier != NULL ){
3256  delete classifier;
3257  classifier = NULL;
3258  }
3259  trained = false;
3260  initialized = false;
3261 }
3262 
3263 void GestureRecognitionPipeline::deleteRegressifier(){
3264  if( regressifier != NULL ){
3265  delete regressifier;
3266  regressifier = NULL;
3267  }
3268  trained = false;
3269  initialized = false;
3270 }
3271 
3272 void GestureRecognitionPipeline::deleteClusterer(){
3273  if( clusterer != NULL ){
3274  delete clusterer;
3275  clusterer = NULL;
3276  }
3277  trained = false;
3278  initialized = false;
3279 }
3280 
3281 void GestureRecognitionPipeline::deleteAllPostProcessingModules(){
3282  if( postProcessingModules.size() != 0 ){
3283  for(UINT i=0; i<postProcessingModules.size(); i++){
3284  delete postProcessingModules[i];
3285  postProcessingModules[i] = NULL;
3286  }
3287  postProcessingModules.clear();
3288  trained = false;
3289  }
3290 }
3291 
3292 void GestureRecognitionPipeline::deleteAllContextModules(){
3293  for(UINT i=0; i<contextModules.size(); i++){
3294  for(UINT j=0; j<contextModules[i].size(); j++){
3295  delete contextModules[i][j];
3296  contextModules[i][j] = NULL;
3297  }
3298  contextModules[i].clear();
3299  }
3300 }
3301 
3302 bool GestureRecognitionPipeline::updateTestMetrics(const UINT classLabel,const UINT predictedClassLabel,VectorDouble &precisionCounter,VectorDouble &recallCounter,double &rejectionPrecisionCounter,double &rejectionRecallCounter,VectorDouble &confusionMatrixCounter){
3303 
3304  //Find the index of the classLabel
3305  UINT predictedClassLabelIndex =0;
3306  bool predictedClassLabelIndexFound = false;
3307  if( predictedClassLabel != 0 ){
3308  for(UINT k=0; k<getNumClassesInModel(); k++){
3309  if( predictedClassLabel == classifier->getClassLabels()[k] ){
3310  predictedClassLabelIndex = k;
3311  predictedClassLabelIndexFound = true;
3312  break;
3313  }
3314  }
3315 
3316  if( !predictedClassLabelIndexFound ){
3317  errorLog << "Failed to find class label index for label: " << predictedClassLabel << endl;
3318  return false;
3319  }
3320  }
3321 
3322  //Find the index of the class label
3323  UINT actualClassLabelIndex = 0;
3324  if( classLabel != 0 ){
3325  for(UINT k=0; k<getNumClassesInModel(); k++){
3326  if( classLabel == classifier->getClassLabels()[k] ){
3327  actualClassLabelIndex = k;
3328  break;
3329  }
3330  }
3331  }
3332 
3333  //Update the classification accuracy
3334  if( classLabel == predictedClassLabel ){
3335  testAccuracy++;
3336  }
3337 
3338  //Update the precision
3339  if( predictedClassLabel != 0 ){
3340  if( classLabel == predictedClassLabel ){
3341  //Update the precision value
3342  testPrecision[ predictedClassLabelIndex ]++;
3343  }
3344  //Update the precision counter
3345  precisionCounter[ predictedClassLabelIndex ]++;
3346  }
3347 
3348  //Update the recall
3349  if( classLabel != 0 ){
3350  if( classLabel == predictedClassLabel ){
3351  //Update the recall value
3352  testRecall[ predictedClassLabelIndex ]++;
3353  }
3354  //Update the recall counter
3355  recallCounter[ actualClassLabelIndex ]++;
3356  }
3357 
3358  //Update the rejection precision
3359  if( predictedClassLabel == 0 ){
3360  if( classLabel == 0 ) testRejectionPrecision++;
3361  rejectionPrecisionCounter++;
3362  }
3363 
3364  //Update the rejection recall
3365  if( classLabel == 0 ){
3366  if( predictedClassLabel == 0 ) testRejectionRecall++;
3367  rejectionRecallCounter++;
3368  }
3369 
3370  //Update the confusion matrix
3371  if( classifier->getNullRejectionEnabled() ){
3372  if( classLabel == 0 ) actualClassLabelIndex = 0;
3373  else actualClassLabelIndex++;
3374  if( predictedClassLabel == 0 ) predictedClassLabelIndex = 0;
3375  else predictedClassLabelIndex++;
3376  }
3377  testConfusionMatrix[ actualClassLabelIndex ][ predictedClassLabelIndex ]++;
3378  confusionMatrixCounter[ actualClassLabelIndex ]++;
3379 
3380  return true;
3381 }
3382 
3383 bool GestureRecognitionPipeline::computeTestMetrics(VectorDouble &precisionCounter,VectorDouble &recallCounter,double &rejectionPrecisionCounter,double &rejectionRecallCounter,VectorDouble &confusionMatrixCounter,const UINT numTestSamples){
3384 
3385  //Compute the test metrics
3386  testAccuracy = testAccuracy/double(numTestSamples) * 100.0;
3387 
3388  for(UINT k=0; k<getNumClassesInModel(); k++){
3389  if( precisionCounter[k] > 0 ) testPrecision[k] /= precisionCounter[k];
3390  else testPrecision[k] = 0;
3391  if( recallCounter[k] > 0 ) testRecall[k] /= recallCounter[k];
3392  else testRecall[k] = 0;
3393 
3394  if( precisionCounter[k] + recallCounter[k] > 0 )
3395  testFMeasure[k] = 2 * ((testPrecision[k]*testRecall[k])/(testPrecision[k]+testRecall[k]));
3396  else testFMeasure[k] = 0;
3397  }
3398  if( rejectionPrecisionCounter > 0 ) testRejectionPrecision /= rejectionPrecisionCounter;
3399  if( rejectionRecallCounter > 0 ) testRejectionRecall /= rejectionRecallCounter;
3400 
3401 
3402  for(UINT r=0; r<confusionMatrixCounter.size(); r++){
3403  if( confusionMatrixCounter[r] > 0 ){
3404  for(UINT c=0; c<testConfusionMatrix.getNumCols(); c++){
3405  testConfusionMatrix[r][c] /= confusionMatrixCounter[r];
3406  }
3407  }
3408  }
3409 
3410  return true;
3411 }
3412 
3414  string model = "";
3415 
3416  switch( pipelineMode ){
3417  case PIPELINE_MODE_NOT_SET:
3418  break;
3419  case CLASSIFICATION_MODE:
3420  if( getIsClassifierSet() ){
3421  model += "Classifier: " + classifier->getClassifierType() + "\n";
3422  model += classifier->getModelAsString();
3423  }
3424  break;
3425  case REGRESSION_MODE:
3426  if( getIsRegressifierSet() ){
3427  model += "Regressifier: " + regressifier->getRegressifierType() + "\n";
3428  model += regressifier->getModelAsString();
3429  }
3430  break;
3431  default:
3432  break;
3433  }
3434 
3435  return model;
3436 }
3437 
3439  switch( pipelineMode ){
3440  case PIPELINE_MODE_NOT_SET:
3441  return "PIPELINE_MODE_NOT_SET";
3442  break;
3443  case CLASSIFICATION_MODE:
3444  return "CLASSIFICATION_MODE";
3445  break;
3446  case REGRESSION_MODE:
3447  return "REGRESSION_MODE";
3448  break;
3449  default:
3450  return "ERROR_UNKNWON_PIPELINE_MODE";
3451  break;
3452  }
3453 
3454  return "ERROR_UNKNWON_PIPELINE_MODE";
3455 }
3456 
3457 string GestureRecognitionPipeline::getInfo() const{
3458  return info;
3459 }
3460 
3461 UINT GestureRecognitionPipeline::getPipelineModeFromString(string pipelineModeAsString) const{
3462  if( pipelineModeAsString == "PIPELINE_MODE_NOT_SET" ){
3463  return PIPELINE_MODE_NOT_SET;
3464  }
3465  if( pipelineModeAsString == "CLASSIFICATION_MODE" ){
3466  return CLASSIFICATION_MODE;
3467  }
3468  if( pipelineModeAsString == "REGRESSION_MODE" ){
3469  return REGRESSION_MODE;
3470  }
3471  return PIPELINE_MODE_NOT_SET;
3472 }
3473 
3474 } //End of namespace GRT
3475 
UINT getNumSamples() const
virtual bool saveModelToFile(string filename) const
Definition: MLBase.cpp:135
static std::string toString(const int &i)
Definition: Util.cpp:65
static Regressifier * createInstanceFromString(string const &regressifierType)
string getLastErrorMessage() const
Definition: GRTBase.cpp:54
static Classifier * createInstanceFromString(string const &classifierType)
Definition: Classifier.cpp:27
bool map(const VectorDouble &inputVector)
bool setAllowNullGestureClass(bool allowNullGestureClass)
bool getTimeseriesCompatible() const
Definition: Classifier.h:243
bool setRegressifier(const Regressifier &regressifier)
double getPhase() const
Definition: Classifier.cpp:180
double getRootMeanSquaredTrainingError() const
Definition: MLBase.cpp:215
bool setAllValues(const T &value)
Definition: Matrix.h:335
virtual bool deepCopyFrom(const Classifier *classifier)
Definition: Classifier.h:61
VectorDouble getRegressionData() const
double getMaximumLikelihood() const
Definition: Clusterer.cpp:237
virtual bool loadModelFromFile(string filename)
Definition: MLBase.cpp:157
Context * getContextModule(const UINT contextLevel, const UINT moduleIndex) const
Definition: AdaBoost.cpp:25
bool test(const ClassificationData &testData)
Clusterer * createNewInstance() const
Definition: Clusterer.cpp:35
bool setPostProcessingModule(const PostProcessing &postProcessingModule)
ClassificationData getTrainingFoldData(const UINT foldIndex) const
bool push_back(const std::vector< T > &sample)
Definition: Matrix.h:390
virtual bool reset()
Definition: Clusterer.cpp:125
bool setInputAndTargetDimensions(const UINT numInputDimensions, const UINT numTargetDimensions)
bool setNumDimensions(UINT numDimensions)
unsigned int getNumCols() const
Definition: Matrix.h:538
bool addPostProcessingModule(const PostProcessing &postProcessingModule, UINT insertIndex=INSERT_AT_END_INDEX)
bool addSample(const VectorDouble &sample)
virtual bool reset()
static std::string intToString(const int &i)
Definition: Util.cpp:53
virtual UINT getNumClasses() const
Definition: Classifier.cpp:189
virtual bool train(ClassificationData trainingData)
Definition: MLBase.cpp:80
VectorDouble getClassLikelihoods() const
Definition: Classifier.cpp:206
UINT getNumInputFeatures() const
Definition: MLBase.cpp:186
vector< ClassTracker > getClassTracker() const
vector< UINT > getClusterLabels() const
Definition: Clusterer.cpp:253
UINT getNumInputDimensions() const
Definition: MLBase.cpp:188
virtual bool deepCopyFrom(const FeatureExtraction *rhs)
virtual bool deepCopyFrom(const PreProcessing *rhs)
Definition: PreProcessing.h:57
VectorDouble getClassDistances() const
Definition: Classifier.cpp:211
static Clusterer * createInstanceFromString(string const &ClustererType)
Definition: Clusterer.cpp:27
bool save(const string &filename) const
double getMaximumLikelihood() const
Definition: Classifier.cpp:175
This file contains the GestureRecognitionPipeline class.
double getTotalSquaredTrainingError() const
Definition: MLBase.cpp:219
UINT getNumSamples() const
bool addContextModule(const Context &contextModule, UINT contextLevel, UINT insertIndex=INSERT_AT_END_INDEX)
bool loadPipelineFromFile(const string &filename)
vector< TestResult > getCrossValidationResults() const
Regressifier * createNewInstance() const
bool start()
Definition: Timer.h:59
bool setFeatureExtractionModule(const FeatureExtraction &featureExtractionModule)
signed long getMilliSeconds() const
Definition: Timer.h:100
virtual bool predict(VectorDouble inputVector)
Definition: MLBase.cpp:104
bool removePostProcessingModule(const UINT moduleIndex)
VectorDouble getClusterLikelihoods() const
Definition: Clusterer.cpp:245
string getRegressifierType() const
Context * createNewInstance() const
Definition: Context.cpp:36
string getClustererType() const
Definition: Clusterer.cpp:257
virtual bool deepCopyFrom(const Clusterer *Clusterer)
Definition: Clusterer.h:58
virtual bool train_(MatrixDouble &trainingData)
Definition: Clusterer.cpp:111
bool addPreProcessingModule(const PreProcessing &preProcessingModule, UINT insertIndex=INSERT_AT_END_INDEX)
bool setClusterer(const Clusterer &clusterer)
bool savePipelineToFile(const string &filename) const
RegressionData getTrainingFoldData(const UINT foldIndex) const
virtual bool reset()
Definition: Classifier.cpp:121
void clear()
Definition: Matrix.h:511
PreProcessing * createNewInstance() const
static PostProcessing * createInstanceFromString(string const &postProcessingType)
VectorDouble getNullRejectionThresholds() const
Definition: Classifier.cpp:216
bool getNullRejectionEnabled() const
Definition: Classifier.cpp:167
bool train(const ClassificationData &trainingData)
bool predict(const VectorDouble &inputVector)
bool spiltDataIntoKFolds(const UINT K)
UINT getPredictedClassLabel() const
Definition: Classifier.cpp:201
Classifier * createNewInstance() const
Definition: Classifier.cpp:35
bool addFeatureExtractionModule(const FeatureExtraction &featureExtractionModule, UINT insertIndex=INSERT_AT_END_INDEX)
unsigned int getNumRows() const
Definition: Matrix.h:531
UINT getNumDimensions() const
bool getTrained() const
Definition: MLBase.cpp:223
PostProcessing * createNewInstance() const
UINT getNumTargetDimensions() const
bool addSample(const VectorDouble &inputVector, const VectorDouble &targetVector)
bool setPreProcessingModule(const PreProcessing &preProcessingModule)
string getClassifierType() const
Definition: Classifier.cpp:159
bool setClassifier(const Classifier &classifier)
FeatureExtraction * createNewInstance() const
UINT getNumOutputDimensions() const
Definition: MLBase.cpp:190
UINT getNumInputDimensions() const
bool preProcessData(VectorDouble inputVector, bool computeFeatures=true)
virtual bool deepCopyFrom(const Regressifier *regressifier)
Definition: Regressifier.h:63
ClassificationData getTestFoldData(const UINT foldIndex) const
VectorDouble getClusterDistances() const
Definition: Clusterer.cpp:249
bool spiltDataIntoKFolds(const UINT K, const bool useStratifiedSampling=false)
vector< UINT > getClassLabels() const
Definition: Classifier.cpp:221
RegressionData getTestFoldData(const UINT foldIndex) const
UINT getPipelineModeFromString(string pipelineMode) const
TimeSeriesClassificationData getTrainingFoldData(const UINT foldIndex) const
bool addSample(UINT classLabel, const VectorDouble &sample)
GestureRecognitionPipeline & operator=(const GestureRecognitionPipeline &rhs)
bool spiltDataIntoKFolds(const UINT K, const bool useStratifiedSampling=false)
std::vector< T > getRowVector(const unsigned int r) const
Definition: Matrix.h:173
virtual string getModelAsString() const
Definition: MLBase.cpp:176
FeatureExtraction * getFeatureExtractionModule(const UINT moduleIndex) const
bool notifyTestResultsObservers(const TestInstanceResult &data)
Definition: MLBase.cpp:318
UINT getPredictedClusterLabel() const
Definition: Clusterer.cpp:234
vector< TestInstanceResult > getTestInstanceResults() const
virtual bool deepCopyFrom(const PostProcessing *postProcessing)
PreProcessing * getPreProcessingModule(const UINT moduleIndex) const
bool removeContextModule(const UINT contextLevel, const UINT moduleIndex)
static PreProcessing * createInstanceFromString(string const &preProcessingType)
UINT getNumClusters() const
Definition: Clusterer.cpp:232
virtual bool resize(const unsigned int r, const unsigned int c)
Definition: Matrix.h:234
PostProcessing * getPostProcessingModule(UINT moduleIndex) const
TimeSeriesClassificationData getTestFoldData(const UINT foldIndex) const
virtual bool train_(ClassificationData &trainingData)
Definition: MLBase.cpp:82
bool updateContextModule(bool value, UINT contextLevel=0, UINT moduleIndex=0)