GestureRecognitionToolkit  Version: 0.2.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 #define GRT_DLL_EXPORTS
22 #include "TimeDomainFeatures.h"
23 
24 GRT_BEGIN_NAMESPACE
25 
26 //Register the TimeDomainFeatures module with the FeatureExtraction base class
27 RegisterFeatureExtractionModule< TimeDomainFeatures > TimeDomainFeatures::registerModule("TimeDomainFeatures");
28 
29 TimeDomainFeatures::TimeDomainFeatures(UINT bufferLength,UINT numFrames,UINT numDimensions,bool offsetInput,bool useMean,bool useStdDev,bool useEuclideanNorm,bool useRMS){
30 
31  classType = "TimeDomainFeatures";
32  featureExtractionType = classType;
33  debugLog.setProceedingText("[DEBUG TimeDomainFeatures]");
34  errorLog.setProceedingText("[ERROR TimeDomainFeatures]");
35  warningLog.setProceedingText("[WARNING TimeDomainFeatures]");
36 
37  init(bufferLength,numFrames,numDimensions,offsetInput,useMean,useStdDev,useEuclideanNorm,useRMS);
38 }
39 
40 TimeDomainFeatures::TimeDomainFeatures(const TimeDomainFeatures &rhs){
41 
42  classType = "TimeDomainFeatures";
43  featureExtractionType = classType;
44  debugLog.setProceedingText("[DEBUG TimeDomainFeatures]");
45  errorLog.setProceedingText("[ERROR TimeDomainFeatures]");
46  warningLog.setProceedingText("[WARNING TimeDomainFeatures]");
47 
48  //Invoke the equals operator to copy the data from the rhs instance to this instance
49  *this = rhs;
50 }
51 
53 
54 }
55 
57  if(this!=&rhs){
58  this->bufferLength = rhs.bufferLength;
59  this->numFrames = rhs.numFrames;
60  this->offsetInput = rhs.offsetInput;
61  this->useMean = rhs.useMean;
62  this->useStdDev = rhs.useStdDev;
63  this->useEuclideanNorm = rhs.useEuclideanNorm;
64  this->useRMS = rhs.useRMS;
65  this->dataBuffer = rhs.dataBuffer;
66 
67  //Copy the base variables
69  }
70  return *this;
71 }
72 
73 bool TimeDomainFeatures::deepCopyFrom(const FeatureExtraction *featureExtraction){
74 
75  if( featureExtraction == NULL ) return false;
76 
77  if( this->getFeatureExtractionType() == featureExtraction->getFeatureExtractionType() ){
78 
79  //Invoke the equals operator to copy the data from the rhs instance to this instance
80  *this = *(TimeDomainFeatures*)featureExtraction;
81 
82  return true;
83  }
84 
85  errorLog << "clone(FeatureExtraction *featureExtraction) - FeatureExtraction Types Do Not Match!" << std::endl;
86 
87  return false;
88 }
89 
91 
92  if( !initialized ){
93  errorLog << "computeFeatures(const VectorFloat &inputVector) - Not initialized!" << std::endl;
94  return false;
95  }
96 
97  if( inputVector.size() != numInputDimensions ){
98  errorLog << "computeFeatures(const VectorFloat &inputVector) - The size of the inputVector (" << inputVector.size() << ") does not match that of the filter (" << numInputDimensions << ")!" << std::endl;
99  return false;
100  }
101 
102  featureVector = update( inputVector );
103 
104  return true;
105 }
106 
108  if( initialized ){
109  return init(bufferLength,numFrames,numInputDimensions,offsetInput,useMean,useStdDev,useEuclideanNorm,useRMS);
110  }
111  return false;
112 }
113 
114 bool TimeDomainFeatures::saveModelToFile( std::string filename ) const{
115 
116  std::fstream file;
117  file.open(filename.c_str(), std::ios::out);
118 
119  if( !saveModelToFile( file ) ){
120  return false;
121  }
122 
123  file.close();
124 
125  return true;
126 }
127 
128 bool TimeDomainFeatures::loadModelFromFile( std::string filename ){
129 
130  std::fstream file;
131  file.open(filename.c_str(), std::ios::in);
132 
133  if( !loadModelFromFile( file ) ){
134  return false;
135  }
136 
137  //Close the file
138  file.close();
139 
140  return true;
141 }
142 
143 bool TimeDomainFeatures::saveModelToFile( std::fstream &file ) const{
144 
145  if( !file.is_open() ){
146  errorLog << "saveModelToFile(fstream &file) - The file is not open!" << std::endl;
147  return false;
148  }
149 
150  //Write the file header
151  file << "GRT_TIME_DOMAIN_FEATURES_FILE_V1.0" << std::endl;
152 
153  //Save the base settings to the file
155  errorLog << "saveFeatureExtractionSettingsToFile(fstream &file) - Failed to save base feature extraction settings to file!" << std::endl;
156  return false;
157  }
158 
159  //Write the time domain settings to the file
160  file << "BufferLength: " << bufferLength << std::endl;
161  file << "NumFrames: " << numFrames << std::endl;
162  file << "OffsetInput: " << offsetInput << std::endl;
163  file << "UseMean: " << useMean << std::endl;
164  file << "UseStdDev: " << useStdDev << std::endl;
165  file << "UseEuclideanNorm: " << useEuclideanNorm << std::endl;
166  file << "UseRMS: " << useRMS << std::endl;
167 
168  return true;
169 }
170 
171 bool TimeDomainFeatures::loadModelFromFile( std::fstream &file ){
172 
173  if( !file.is_open() ){
174  errorLog << "loadModelFromFile(fstream &file) - The file is not open!" << std::endl;
175  return false;
176  }
177 
178  std::string word;
179 
180  //Load the header
181  file >> word;
182 
183  if( word != "GRT_TIME_DOMAIN_FEATURES_FILE_V1.0" ){
184  errorLog << "loadModelFromFile(fstream &file) - Invalid file format!" << std::endl;
185  return false;
186  }
187 
189  errorLog << "loadFeatureExtractionSettingsFromFile(fstream &file) - Failed to load base feature extraction settings from file!" << std::endl;
190  return false;
191  }
192 
193  //Load the BufferLength
194  file >> word;
195  if( word != "BufferLength:" ){
196  errorLog << "loadModelFromFile(fstream &file) - Failed to read BufferLength header!" << std::endl;
197  return false;
198  }
199  file >> bufferLength;
200 
201  //Load the NumFrames
202  file >> word;
203  if( word != "NumFrames:" ){
204  errorLog << "loadModelFromFile(fstream &file) - Failed to read NumFrames header!" << std::endl;
205  return false;
206  }
207  file >> numFrames;
208 
209  //Load the OffsetInput
210  file >> word;
211  if( word != "OffsetInput:" ){
212  errorLog << "loadModelFromFile(fstream &file) - Failed to read OffsetInput header!" << std::endl;
213  return false;
214  }
215  file >> offsetInput;
216 
217  //Load the UseMean
218  file >> word;
219  if( word != "UseMean:" ){
220  errorLog << "loadModelFromFile(fstream &file) - Failed to read UseMean header!" << std::endl;
221  return false;
222  }
223  file >> useMean;
224 
225  //Load the UseStdDev
226  file >> word;
227  if( word != "UseStdDev:" ){
228  errorLog << "loadModelFromFile(fstream &file) - Failed to read UseStdDev header!" << std::endl;
229  return false;
230  }
231  file >> useStdDev;
232 
233  //Load the UseEuclideanNorm
234  file >> word;
235  if( word != "UseEuclideanNorm:" ){
236  errorLog << "loadModelFromFile(fstream &file) - Failed to read UseEuclideanNorm header!" << std::endl;
237  return false;
238  }
239  file >> useEuclideanNorm;
240 
241  //Load the UseRMS
242  file >> word;
243  if( word != "UseRMS:" ){
244  errorLog << "loadModelFromFile(fstream &file) - Failed to read UseRMS header!" << std::endl;
245  return false;
246  }
247  file >> useRMS;
248 
249  //Init the TimeDomainFeatures module to ensure everything is initialized correctly
250  return init(bufferLength,numFrames,numInputDimensions,offsetInput,useMean,useStdDev,useEuclideanNorm,useRMS);
251 }
252 
253 bool TimeDomainFeatures::init(UINT bufferLength,UINT numFrames,UINT numDimensions,bool offsetInput,bool useMean,bool useStdDev,bool useEuclideanNorm,bool useRMS){
254 
255  initialized = false;
256 
257  if( numFrames > bufferLength ){
258  errorLog << "init(...) - The number of numFrames parameter can not be larger than the buffer length parameter!" << std::endl;
259  return false;
260  }
261  if( bufferLength % numFrames != 0 ){
262  errorLog << "init(...) - The buffer length parameter must be divisible with no remainders by the number of numFrames parameter!" << std::endl;
263  return false;
264  }
265 
266  this->bufferLength = bufferLength;
267  this->numFrames = numFrames;
268  this->numInputDimensions = numDimensions;
269  this->offsetInput = offsetInput;
270  this->useMean = useMean;
271  this->useStdDev = useStdDev;
272  this->useEuclideanNorm = useEuclideanNorm;
273  this->useRMS = useRMS;
274  featureDataReady = false;
275 
276  //Set the number of output dimensions
277  numOutputDimensions = 0;
278  if( useMean ){
279  numOutputDimensions += numInputDimensions*numFrames;
280  }
281  if( useStdDev ){
282  numOutputDimensions += numInputDimensions*numFrames;
283  }
284  if( useEuclideanNorm ){
285  numOutputDimensions += numInputDimensions*numFrames;
286  }
287  if( useRMS ){
288  numOutputDimensions += numInputDimensions*numFrames;
289  }
290  if( numOutputDimensions == 0 ){
291  errorLog << "init(...) - The numOutputDimensions is zero!" << std::endl;
292  return false;
293  }
294 
295  //Resize the feature vector
296  featureVector.resize(numOutputDimensions);
297 
298  //Resize the raw data buffer
299  dataBuffer.resize( bufferLength, VectorFloat(numInputDimensions,0) );
300 
301  //Flag that the time domain features has been initialized
302  initialized = true;
303 
304  return true;
305 }
306 
307 
309  return update(VectorFloat(1,x));
310 }
311 
313 
314  if( !initialized ){
315  errorLog << "update(const VectorFloat &x) - Not Initialized!" << std::endl;
316  return VectorFloat();
317  }
318 
319  if( x.getSize() != numInputDimensions ){
320  errorLog << "update(const VectorFloat &x)- The Number Of Input Dimensions (" << numInputDimensions << ") does not match the size of the input vector (" << x.getSize() << ")!" << std::endl;
321  return VectorFloat();
322  }
323 
324  //Add the new data to the data buffer
325  dataBuffer.push_back( x );
326 
327  //Only flag that the feature data is ready if the data is full
328  if( dataBuffer.getBufferFilled() ){
329  featureDataReady = true;
330  }else featureDataReady = false;
331 
332  MatrixFloat meanFeatures(numInputDimensions,numFrames);
333  MatrixFloat stdDevFeatures(numInputDimensions,numFrames);
334  MatrixFloat normFeatures(numInputDimensions,numFrames);
335  MatrixFloat rmsFeatures(numInputDimensions,numFrames);
336  MatrixFloat data(bufferLength,numInputDimensions);
337 
338  if( offsetInput ){
339  for(UINT n=0; n<numInputDimensions; n++){
340  data[0][n] = dataBuffer[0][n];
341  for(UINT i=1; i<bufferLength; i++){
342  data[i][n] = dataBuffer[i][n]-dataBuffer[0][n];
343  }
344  }
345  }else{
346  for(UINT n=0; n<numInputDimensions; n++){
347  for(UINT i=0; i<bufferLength; i++){
348  data[i][n] = dataBuffer[i][n];
349  }
350  }
351  }
352 
353  if( useMean || useStdDev ){ meanFeatures.setAllValues(0); stdDevFeatures.setAllValues(0); }
354  if( useEuclideanNorm ) normFeatures.setAllValues(0);
355  if( useRMS ) rmsFeatures.setAllValues(0);
356 
357  UINT frameSize = bufferLength / numFrames;
358  UINT frame = 0;
359  UINT index = 0;
360  for(UINT n=0; n<numInputDimensions; n++){
361  frame = 0;
362  index = 0;
363  for(UINT i=0; i<bufferLength; i++){
364  //Update the mean
365  meanFeatures[n][frame] += data[i][n];
366 
367  //Update the norm features
368  if( useEuclideanNorm )
369  normFeatures[n][frame] += data[i][n]*data[i][n];
370 
371  //Update the rms features
372  if( useRMS )
373  rmsFeatures[n][frame] += data[i][n]*data[i][n];
374 
375  if( ++index == frameSize ){
376  frame++;
377  index = 0;
378  }
379  }
380 
381  //Update the mean
382  for(UINT j=0; j<numFrames; j++){
383  meanFeatures[n][j] /= frameSize;
384  }
385 
386  //Update the std dev if needed
387  if( useStdDev ){
388  frame = 0;
389  index = 0;
390  for(UINT i=0; i<bufferLength; i++){
391  stdDevFeatures[n][frame] += (data[i][n]-meanFeatures[n][frame]) * (data[i][n]-meanFeatures[n][frame]);
392  if( ++index == frameSize ){
393  frame++;
394  index = 0;
395  }
396  }
397  Float norm = frameSize>1 ? frameSize-1 : 1;
398  for(UINT j=0; j<numFrames; j++){
399  stdDevFeatures[n][j] = sqrt( stdDevFeatures[n][j]/norm );
400  }
401  }
402 
403  //Update the euclidean norm if needed
404  if( useEuclideanNorm ){
405  for(UINT j=0; j<numFrames; j++){
406  normFeatures[n][j] = sqrt( normFeatures[n][j] );
407  }
408  }
409 
410  //Update the rms if needed
411  if( useRMS ){
412  for(UINT j=0; j<numFrames; j++){
413  rmsFeatures[n][j] = sqrt( rmsFeatures[n][j] / frameSize );
414  }
415  }
416  }
417 
418  //Update the features
419  index = 0;
420  frame = 0;
421  for(UINT n=0; n<numInputDimensions; n++){
422  for(UINT j=0; j<numFrames; j++){
423  if( useMean ){
424  featureVector[index++] = meanFeatures[n][j];
425  }
426  if( useStdDev ){
427  featureVector[index++] = stdDevFeatures[n][j];
428  }
429  if( useEuclideanNorm ){
430  featureVector[index++] = normFeatures[n][j];
431  }
432  if( useRMS ){
433  featureVector[index++] = rmsFeatures[n][j];
434  }
435  }
436  }
437 
438  return featureVector;
439 }
440 
442  if( initialized ){
443  return dataBuffer;
444  }
446 }
447 
449  return dataBuffer;
450 }
451 
452 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)
UINT getSize() const
Definition: Vector.h:191
CircularBuffer< VectorFloat > getBufferData()
virtual bool loadModelFromFile(std::string filename)
VectorFloat update(Float x)
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)