GestureRecognitionToolkit  Version: 0.1.0
The Gesture Recognition Toolkit (GRT) is a cross-platform, open-source, c++ machine learning library for real-time gesture recognition.
TimeDomainFeatures.cpp
1 /*
2  GRT MIT License
3  Copyright (c) <2012> <Nicholas Gillian, Media Lab, MIT>
4 
5  Permission is hereby granted, free of charge, to any person obtaining a copy of this software
6  and associated documentation files (the "Software"), to deal in the Software without restriction,
7  including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
9  subject to the following conditions:
10 
11  The above copyright notice and this permission notice shall be included in all copies or substantial
12  portions of the Software.
13 
14  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include "TimeDomainFeatures.h"
22 
23 GRT_BEGIN_NAMESPACE
24 
25 //Register the TimeDomainFeatures module with the FeatureExtraction base class
26 RegisterFeatureExtractionModule< TimeDomainFeatures > TimeDomainFeatures::registerModule("TimeDomainFeatures");
27 
28 TimeDomainFeatures::TimeDomainFeatures(UINT bufferLength,UINT numFrames,UINT numDimensions,bool offsetInput,bool useMean,bool useStdDev,bool useEuclideanNorm,bool useRMS){
29 
30  classType = "TimeDomainFeatures";
31  featureExtractionType = classType;
32  debugLog.setProceedingText("[DEBUG TimeDomainFeatures]");
33  errorLog.setProceedingText("[ERROR TimeDomainFeatures]");
34  warningLog.setProceedingText("[WARNING TimeDomainFeatures]");
35 
36  init(bufferLength,numFrames,numDimensions,offsetInput,useMean,useStdDev,useEuclideanNorm,useRMS);
37 }
38 
39 TimeDomainFeatures::TimeDomainFeatures(const TimeDomainFeatures &rhs){
40 
41  classType = "TimeDomainFeatures";
42  featureExtractionType = classType;
43  debugLog.setProceedingText("[DEBUG TimeDomainFeatures]");
44  errorLog.setProceedingText("[ERROR TimeDomainFeatures]");
45  warningLog.setProceedingText("[WARNING TimeDomainFeatures]");
46 
47  //Invoke the equals operator to copy the data from the rhs instance to this instance
48  *this = rhs;
49 }
50 
52 
53 }
54 
56  if(this!=&rhs){
57  this->bufferLength = rhs.bufferLength;
58  this->numFrames = rhs.numFrames;
59  this->offsetInput = rhs.offsetInput;
60  this->useMean = rhs.useMean;
61  this->useStdDev = rhs.useStdDev;
62  this->useEuclideanNorm = rhs.useEuclideanNorm;
63  this->useRMS = rhs.useRMS;
64  this->dataBuffer = rhs.dataBuffer;
65 
66  //Copy the base variables
68  }
69  return *this;
70 }
71 
72 bool TimeDomainFeatures::deepCopyFrom(const FeatureExtraction *featureExtraction){
73 
74  if( featureExtraction == NULL ) return false;
75 
76  if( this->getFeatureExtractionType() == featureExtraction->getFeatureExtractionType() ){
77 
78  //Invoke the equals operator to copy the data from the rhs instance to this instance
79  *this = *(TimeDomainFeatures*)featureExtraction;
80 
81  return true;
82  }
83 
84  errorLog << "clone(FeatureExtraction *featureExtraction) - FeatureExtraction Types Do Not Match!" << std::endl;
85 
86  return false;
87 }
88 
90 
91  if( !initialized ){
92  errorLog << "computeFeatures(const VectorFloat &inputVector) - Not initialized!" << std::endl;
93  return false;
94  }
95 
96  if( inputVector.size() != numInputDimensions ){
97  errorLog << "computeFeatures(const VectorFloat &inputVector) - The size of the inputVector (" << inputVector.size() << ") does not match that of the filter (" << numInputDimensions << ")!" << std::endl;
98  return false;
99  }
100 
101  featureVector = update( inputVector );
102 
103  return true;
104 }
105 
107  if( initialized ){
108  return init(bufferLength,numFrames,numInputDimensions,offsetInput,useMean,useStdDev,useEuclideanNorm,useRMS);
109  }
110  return false;
111 }
112 
113 bool TimeDomainFeatures::saveModelToFile( std::string filename ) const{
114 
115  std::fstream file;
116  file.open(filename.c_str(), std::ios::out);
117 
118  if( !saveModelToFile( file ) ){
119  return false;
120  }
121 
122  file.close();
123 
124  return true;
125 }
126 
127 bool TimeDomainFeatures::loadModelFromFile( std::string filename ){
128 
129  std::fstream file;
130  file.open(filename.c_str(), std::ios::in);
131 
132  if( !loadModelFromFile( file ) ){
133  return false;
134  }
135 
136  //Close the file
137  file.close();
138 
139  return true;
140 }
141 
142 bool TimeDomainFeatures::saveModelToFile( std::fstream &file ) const{
143 
144  if( !file.is_open() ){
145  errorLog << "saveModelToFile(fstream &file) - The file is not open!" << std::endl;
146  return false;
147  }
148 
149  //Write the file header
150  file << "GRT_TIME_DOMAIN_FEATURES_FILE_V1.0" << std::endl;
151 
152  //Save the base settings to the file
154  errorLog << "saveFeatureExtractionSettingsToFile(fstream &file) - Failed to save base feature extraction settings to file!" << std::endl;
155  return false;
156  }
157 
158  //Write the time domain settings to the file
159  file << "BufferLength: " << bufferLength << std::endl;
160  file << "NumFrames: " << numFrames << std::endl;
161  file << "OffsetInput: " << offsetInput << std::endl;
162  file << "UseMean: " << useMean << std::endl;
163  file << "UseStdDev: " << useStdDev << std::endl;
164  file << "UseEuclideanNorm: " << useEuclideanNorm << std::endl;
165  file << "UseRMS: " << useRMS << std::endl;
166 
167  return true;
168 }
169 
170 bool TimeDomainFeatures::loadModelFromFile( std::fstream &file ){
171 
172  if( !file.is_open() ){
173  errorLog << "loadModelFromFile(fstream &file) - The file is not open!" << std::endl;
174  return false;
175  }
176 
177  std::string word;
178 
179  //Load the header
180  file >> word;
181 
182  if( word != "GRT_TIME_DOMAIN_FEATURES_FILE_V1.0" ){
183  errorLog << "loadModelFromFile(fstream &file) - Invalid file format!" << std::endl;
184  return false;
185  }
186 
188  errorLog << "loadFeatureExtractionSettingsFromFile(fstream &file) - Failed to load base feature extraction settings from file!" << std::endl;
189  return false;
190  }
191 
192  //Load the BufferLength
193  file >> word;
194  if( word != "BufferLength:" ){
195  errorLog << "loadModelFromFile(fstream &file) - Failed to read BufferLength header!" << std::endl;
196  return false;
197  }
198  file >> bufferLength;
199 
200  //Load the NumFrames
201  file >> word;
202  if( word != "NumFrames:" ){
203  errorLog << "loadModelFromFile(fstream &file) - Failed to read NumFrames header!" << std::endl;
204  return false;
205  }
206  file >> numFrames;
207 
208  //Load the OffsetInput
209  file >> word;
210  if( word != "OffsetInput:" ){
211  errorLog << "loadModelFromFile(fstream &file) - Failed to read OffsetInput header!" << std::endl;
212  return false;
213  }
214  file >> offsetInput;
215 
216  //Load the UseMean
217  file >> word;
218  if( word != "UseMean:" ){
219  errorLog << "loadModelFromFile(fstream &file) - Failed to read UseMean header!" << std::endl;
220  return false;
221  }
222  file >> useMean;
223 
224  //Load the UseStdDev
225  file >> word;
226  if( word != "UseStdDev:" ){
227  errorLog << "loadModelFromFile(fstream &file) - Failed to read UseStdDev header!" << std::endl;
228  return false;
229  }
230  file >> useStdDev;
231 
232  //Load the UseEuclideanNorm
233  file >> word;
234  if( word != "UseEuclideanNorm:" ){
235  errorLog << "loadModelFromFile(fstream &file) - Failed to read UseEuclideanNorm header!" << std::endl;
236  return false;
237  }
238  file >> useEuclideanNorm;
239 
240  //Load the UseRMS
241  file >> word;
242  if( word != "UseRMS:" ){
243  errorLog << "loadModelFromFile(fstream &file) - Failed to read UseRMS header!" << std::endl;
244  return false;
245  }
246  file >> useRMS;
247 
248  //Init the TimeDomainFeatures module to ensure everything is initialized correctly
249  return init(bufferLength,numFrames,numInputDimensions,offsetInput,useMean,useStdDev,useEuclideanNorm,useRMS);
250 }
251 
252 bool TimeDomainFeatures::init(UINT bufferLength,UINT numFrames,UINT numDimensions,bool offsetInput,bool useMean,bool useStdDev,bool useEuclideanNorm,bool useRMS){
253 
254  initialized = false;
255 
256  if( numFrames > bufferLength ){
257  errorLog << "init(...) - The number of numFrames parameter can not be larger than the buffer length parameter!" << std::endl;
258  return false;
259  }
260  if( bufferLength % numFrames != 0 ){
261  errorLog << "init(...) - The buffer length parameter must be divisible with no remainders by the number of numFrames parameter!" << std::endl;
262  return false;
263  }
264 
265  this->bufferLength = bufferLength;
266  this->numFrames = numFrames;
267  this->numInputDimensions = numDimensions;
268  this->offsetInput = offsetInput;
269  this->useMean = useMean;
270  this->useStdDev = useStdDev;
271  this->useEuclideanNorm = useEuclideanNorm;
272  this->useRMS = useRMS;
273  featureDataReady = false;
274 
275  //Set the number of output dimensions
276  numOutputDimensions = 0;
277  if( useMean ){
278  numOutputDimensions += numInputDimensions*numFrames;
279  }
280  if( useStdDev ){
281  numOutputDimensions += numInputDimensions*numFrames;
282  }
283  if( useEuclideanNorm ){
284  numOutputDimensions += numInputDimensions*numFrames;
285  }
286  if( useRMS ){
287  numOutputDimensions += numInputDimensions*numFrames;
288  }
289  if( numOutputDimensions == 0 ){
290  errorLog << "init(...) - The numOutputDimensions is zero!" << std::endl;
291  return false;
292  }
293 
294  //Resize the feature vector
295  featureVector.resize(numOutputDimensions);
296 
297  //Resize the raw data buffer
298  dataBuffer.resize( bufferLength, VectorFloat(numInputDimensions,0) );
299 
300  //Flag that the time domain features has been initialized
301  initialized = true;
302 
303  return true;
304 }
305 
306 
308  return update(VectorFloat(1,x));
309 }
310 
312 
313  if( !initialized ){
314  errorLog << "update(const VectorFloat &x) - Not Initialized!" << std::endl;
315  return VectorFloat();
316  }
317 
318  if( x.getSize() != numInputDimensions ){
319  errorLog << "update(const VectorFloat &x)- The Number Of Input Dimensions (" << numInputDimensions << ") does not match the size of the input vector (" << x.getSize() << ")!" << std::endl;
320  return VectorFloat();
321  }
322 
323  //Add the new data to the data buffer
324  dataBuffer.push_back( x );
325 
326  //Only flag that the feature data is ready if the data is full
327  if( dataBuffer.getBufferFilled() ){
328  featureDataReady = true;
329  }else featureDataReady = false;
330 
331  MatrixFloat meanFeatures(numInputDimensions,numFrames);
332  MatrixFloat stdDevFeatures(numInputDimensions,numFrames);
333  MatrixFloat normFeatures(numInputDimensions,numFrames);
334  MatrixFloat rmsFeatures(numInputDimensions,numFrames);
335  MatrixFloat data(bufferLength,numInputDimensions);
336 
337  if( offsetInput ){
338  for(UINT n=0; n<numInputDimensions; n++){
339  data[0][n] = dataBuffer[0][n];
340  for(UINT i=1; i<bufferLength; i++){
341  data[i][n] = dataBuffer[i][n]-dataBuffer[0][n];
342  }
343  }
344  }else{
345  for(UINT n=0; n<numInputDimensions; n++){
346  for(UINT i=0; i<bufferLength; i++){
347  data[i][n] = dataBuffer[i][n];
348  }
349  }
350  }
351 
352  if( useMean || useStdDev ){ meanFeatures.setAllValues(0); stdDevFeatures.setAllValues(0); }
353  if( useEuclideanNorm ) normFeatures.setAllValues(0);
354  if( useRMS ) rmsFeatures.setAllValues(0);
355 
356  UINT frameSize = bufferLength / numFrames;
357  UINT frame = 0;
358  UINT index = 0;
359  for(UINT n=0; n<numInputDimensions; n++){
360  frame = 0;
361  index = 0;
362  for(UINT i=0; i<bufferLength; i++){
363  //Update the mean
364  meanFeatures[n][frame] += data[i][n];
365 
366  //Update the norm features
367  if( useEuclideanNorm )
368  normFeatures[n][frame] += data[i][n]*data[i][n];
369 
370  //Update the rms features
371  if( useRMS )
372  rmsFeatures[n][frame] += data[i][n]*data[i][n];
373 
374  if( ++index == frameSize ){
375  frame++;
376  index = 0;
377  }
378  }
379 
380  //Update the mean
381  for(UINT j=0; j<numFrames; j++){
382  meanFeatures[n][j] /= frameSize;
383  }
384 
385  //Update the std dev if needed
386  if( useStdDev ){
387  frame = 0;
388  index = 0;
389  for(UINT i=0; i<bufferLength; i++){
390  stdDevFeatures[n][frame] += (data[i][n]-meanFeatures[n][frame]) * (data[i][n]-meanFeatures[n][frame]);
391  if( ++index == frameSize ){
392  frame++;
393  index = 0;
394  }
395  }
396  Float norm = frameSize>1 ? frameSize-1 : 1;
397  for(UINT j=0; j<numFrames; j++){
398  stdDevFeatures[n][j] = sqrt( stdDevFeatures[n][j]/norm );
399  }
400  }
401 
402  //Update the euclidean norm if needed
403  if( useEuclideanNorm ){
404  for(UINT j=0; j<numFrames; j++){
405  normFeatures[n][j] = sqrt( normFeatures[n][j] );
406  }
407  }
408 
409  //Update the rms if needed
410  if( useRMS ){
411  for(UINT j=0; j<numFrames; j++){
412  rmsFeatures[n][j] = sqrt( rmsFeatures[n][j] / frameSize );
413  }
414  }
415  }
416 
417  //Update the features
418  index = 0;
419  frame = 0;
420  for(UINT n=0; n<numInputDimensions; n++){
421  for(UINT j=0; j<numFrames; j++){
422  if( useMean ){
423  featureVector[index++] = meanFeatures[n][j];
424  }
425  if( useStdDev ){
426  featureVector[index++] = stdDevFeatures[n][j];
427  }
428  if( useEuclideanNorm ){
429  featureVector[index++] = normFeatures[n][j];
430  }
431  if( useRMS ){
432  featureVector[index++] = rmsFeatures[n][j];
433  }
434  }
435  }
436 
437  return featureVector;
438 }
439 
441  if( initialized ){
442  return dataBuffer;
443  }
445 }
446 
448  return dataBuffer;
449 }
450 
451 GRT_END_NAMESPACE
bool push_back(const T &value)
bool saveFeatureExtractionSettingsToFile(std::fstream &file) const
bool getBufferFilled() const
virtual bool saveModelToFile(std::string filename) const
virtual bool resize(const unsigned int size)
Definition: Vector.h:133
virtual bool computeFeatures(const VectorFloat &inputVector)
CircularBuffer< VectorFloat > getBufferData()
virtual bool loadModelFromFile(std::string filename)
VectorFloat update(Float x)
unsigned int getSize() const
Definition: Vector.h:193
std::string getFeatureExtractionType() const
bool setAllValues(const T &value)
Definition: Matrix.h:336
bool loadFeatureExtractionSettingsFromFile(std::fstream &file)
bool copyBaseVariables(const FeatureExtraction *featureExtractionModule)
This class implements the TimeDomainFeatures feature extraction module.
virtual bool deepCopyFrom(const FeatureExtraction *featureExtraction)
TimeDomainFeatures & operator=(const TimeDomainFeatures &rhs)
bool resize(const unsigned int newBufferSize)