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.
FFTFeatures.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 "FFTFeatures.h"
23 
24 GRT_BEGIN_NAMESPACE
25 
26 //Register the FFTFeatures module with the FeatureExtraction base class
27 RegisterFeatureExtractionModule< FFTFeatures > FFTFeatures::registerModule("FFTFeatures");
28 
29 bool sortIndexDoubleDecendingValue(IndexedDouble i,IndexedDouble j) { return (i.value<j.value); }
30 
31 FFTFeatures::FFTFeatures(UINT fftWindowSize,UINT numChannelsInFFTSignal,bool computeMaxFreqFeature,bool computeMaxFreqSpectrumRatio,bool computeCentroidFeature,bool computeTopNFreqFeatures,UINT N){
32 
33  classType = "FFTFeatures";
34  featureExtractionType = classType;
35 
36  debugLog.setProceedingText("[DEBUG FFTFeatures]");
37  errorLog.setProceedingText("[ERROR FFTFeatures]");
38  warningLog.setProceedingText("[WARNING FFTFeatures]");
39  initialized = false;
40  featureDataReady = false;
41 
42  init(fftWindowSize,numChannelsInFFTSignal,computeMaxFreqFeature,computeMaxFreqSpectrumRatio,computeCentroidFeature,computeTopNFreqFeatures,N);
43 }
44 
46 
47  classType = "FFTFeatures";
48  featureExtractionType = classType;
49 
50  debugLog.setProceedingText("[DEBUG FFTFeatures]");
51  errorLog.setProceedingText("[ERROR FFTFeatures]");
52  warningLog.setProceedingText("[WARNING FFTFeatures]");
53 
54  //Invoke the equals operator to copy the data from the rhs instance to this instance
55  *this = rhs;
56 }
57 
59 
60 }
61 
63  if( this != &rhs ){
64  this->fftWindowSize = rhs.fftWindowSize;
65  this->numChannelsInFFTSignal = rhs.numChannelsInFFTSignal;
66  this->computeMaxFreqFeature = rhs.computeMaxFreqFeature;
67  this->computeMaxFreqSpectrumRatio = rhs.computeMaxFreqSpectrumRatio;
68  this->computeCentroidFeature = rhs.computeCentroidFeature;
69  this->computeTopNFreqFeatures = rhs.computeTopNFreqFeatures;
70  this->N = rhs.N;
71  this->maxFreqFeature = rhs.maxFreqFeature;
72  this->maxFreqSpectrumRatio = rhs.maxFreqSpectrumRatio;
73  this->centroidFeature = rhs.centroidFeature;
74 
76  }
77  return *this;
78 }
79 
80 //Clone method
81 bool FFTFeatures::deepCopyFrom(const FeatureExtraction *featureExtraction){
82 
83  if( featureExtraction == NULL ) return false;
84 
85  if( this->getFeatureExtractionType() == featureExtraction->getFeatureExtractionType() ){
86 
87  //Invoke the equals operator to copy the data from the rhs instance to this instance
88  *this = *(FFTFeatures*)featureExtraction;
89 
90  return true;
91  }
92 
93  errorLog << "clone(FeatureExtraction *featureExtraction) - FeatureExtraction Types Do Not Match!" << std::endl;
94 
95  return false;
96 }
97 
98 bool FFTFeatures::saveModelToFile( std::string filename ) const{
99 
100  std::fstream file;
101  file.open(filename.c_str(), std::ios::out);
102 
103  if( !saveModelToFile( file ) ){
104  return false;
105  }
106 
107  file.close();
108 
109  return true;
110 }
111 
112 bool FFTFeatures::loadModelFromFile( std::string filename ){
113 
114  std::fstream file;
115  file.open(filename.c_str(), std::ios::in);
116 
117  if( !loadModelFromFile( file ) ){
118  return false;
119  }
120 
121  //Close the file
122  file.close();
123 
124  return true;
125 }
126 
127 bool FFTFeatures::saveModelToFile( std::fstream &file ) const{
128 
129  if( !file.is_open() ){
130  errorLog << "saveModelToFile(fstream &file) - The file is not open!" << std::endl;
131  return false;
132  }
133 
134  //Write the file header
135  file << "GRT_FFT_FEATURES_FILE_V1.0" << std::endl;
136 
137  //Save the base settings to the file
139  errorLog << "saveFeatureExtractionSettingsToFile(fstream &file) - Failed to save base feature extraction settings to file!" << std::endl;
140  return false;
141  }
142 
143  //Write the FFT features settings
144  file << "FFTWindowSize: " << fftWindowSize << std::endl;
145  file << "NumChannelsInFFTSignal: " << numChannelsInFFTSignal << std::endl;
146  file << "ComputeMaxFreqFeature: " << computeMaxFreqFeature << std::endl;
147  file << "ComputeMaxFreqSpectrumRatio: " << computeMaxFreqSpectrumRatio << std::endl;
148  file << "ComputeCentroidFeature: " << computeCentroidFeature << std::endl;
149  file << "ComputeTopNFreqFeatures: " << computeTopNFreqFeatures << std::endl;
150  file << "N: " << N << std::endl;
151 
152  return true;
153 }
154 
155 bool FFTFeatures::loadModelFromFile( std::fstream &file ){
156 
157  if( !file.is_open() ){
158  errorLog << "loadModelFromFile(fstream &file) - The file is not open!" << std::endl;
159  return false;
160  }
161 
162  std::string word;
163 
164  //Load the header
165  file >> word;
166 
167  if( word != "GRT_FFT_FEATURES_FILE_V1.0" ){
168  errorLog << "loadModelFromFile(fstream &file) - Invalid file format!" << std::endl;
169  return false;
170  }
171 
173  errorLog << "loadFeatureExtractionSettingsFromFile(fstream &file) - Failed to load base feature extraction settings from file!" << std::endl;
174  return false;
175  }
176 
177  //Load the FFTWindowSize
178  file >> word;
179  if( word != "FFTWindowSize:" ){
180  errorLog << "loadModelFromFile(fstream &file) - Failed to read FFTWindowSize header!" << std::endl;
181  return false;
182  }
183  file >> fftWindowSize;
184 
185  //Load the NumOutputDimensions
186  file >> word;
187  if( word != "NumChannelsInFFTSignal:" ){
188  errorLog << "loadModelFromFile(fstream &file) - Failed to read NumChannelsInFFTSignal header!" << std::endl;
189  return false;
190  }
191  file >> numChannelsInFFTSignal;
192 
193  file >> word;
194  if( word != "ComputeMaxFreqFeature:" ){
195  errorLog << "loadModelFromFile(fstream &file) - Failed to read ComputeMaxFreqFeature header!" << std::endl;
196  return false;
197  }
198  file >> computeMaxFreqFeature;
199 
200  file >> word;
201  if( word != "ComputeMaxFreqSpectrumRatio:" ){
202  errorLog << "loadModelFromFile(fstream &file) - Failed to read ComputeMaxFreqSpectrumRatio header!" << std::endl;
203  return false;
204  }
205  file >> computeMaxFreqSpectrumRatio;
206 
207  file >> word;
208  if( word != "ComputeCentroidFeature:" ){
209  errorLog << "loadModelFromFile(fstream &file) - Failed to read ComputeCentroidFeature header!" << std::endl;
210  return false;
211  }
212  file >> computeCentroidFeature;
213 
214  file >> word;
215  if( word != "ComputeTopNFreqFeatures:" ){
216  errorLog << "loadModelFromFile(fstream &file) - Failed to read ComputeTopNFreqFeatures header!" << std::endl;
217  return false;
218  }
219  file >> computeTopNFreqFeatures;
220 
221  file >> word;
222  if( word != "N:" ){
223  errorLog << "loadModelFromFile(fstream &file) - Failed to read N header!" << std::endl;
224  return false;
225  }
226  file >> N;
227 
228  //Init the FFTFeatures module to ensure everything is initialized correctly
229  return init(fftWindowSize,numChannelsInFFTSignal,computeMaxFreqFeature,computeMaxFreqSpectrumRatio,computeCentroidFeature,computeTopNFreqFeatures,N);
230 }
231 
232 bool FFTFeatures::init(UINT fftWindowSize,UINT numChannelsInFFTSignal,bool computeMaxFreqFeature,bool computeMaxFreqSpectrumRatio,bool computeCentroidFeature,bool computeTopNFreqFeatures,UINT N){
233 
234  initialized = false;
235  featureDataReady = false;
236  maxFreqFeature = 0;
237  centroidFeature = 0;
238  numInputDimensions = 0;
239  numOutputDimensions = 0;
240  featureVector.clear();
241  topNFreqFeatures.clear();
242 
243  this->fftWindowSize = fftWindowSize;
244  this->numChannelsInFFTSignal = numChannelsInFFTSignal;
245  this->computeMaxFreqFeature = computeMaxFreqFeature;
246  this->computeMaxFreqSpectrumRatio = computeMaxFreqSpectrumRatio;
247  this->computeCentroidFeature = computeCentroidFeature;
248  this->computeTopNFreqFeatures = computeTopNFreqFeatures;
249  this->N = N;
250 
251  numInputDimensions = fftWindowSize*numChannelsInFFTSignal;
252  numOutputDimensions = 0;
253  if( computeMaxFreqFeature ) numOutputDimensions += 1;
254  if( computeMaxFreqSpectrumRatio ) numOutputDimensions += 1;
255  if( computeCentroidFeature ) numOutputDimensions += 1;
256  if( computeTopNFreqFeatures ){
257  numOutputDimensions += N;
258  topNFreqFeatures.resize(N,0);
259  }
260  numOutputDimensions *= numChannelsInFFTSignal;
261 
262  //Resize the feature vector
263  featureVector.resize(numOutputDimensions,0);
264 
265  initialized = true;
266 
267  return true;
268 }
269 
270 bool FFTFeatures::computeFeatures(const VectorFloat &inputVector){
271 
272  if( !initialized ){
273  errorLog << "computeFeatures(const VectorFloat &inputVector) - Not initialized!" << std::endl;
274  return false;
275  }
276 
277  //The input vector should be the magnitude data from an FFT
278  if( inputVector.getSize() != fftWindowSize*numChannelsInFFTSignal ){
279  errorLog << "computeFeatures(const VectorFloat &inputVector) - The size of the inputVector (" << inputVector.getSize() << ") does not match the expected size! Verify that the FFT module that generated this inputVector has a window size of " << fftWindowSize << " and the number of input channels is: " << numChannelsInFFTSignal << ". Also verify that only the magnitude values are being computed (and not the phase)." << std::endl;
280  return false;
281  }
282 
283  featureDataReady = false;
284 
285  UINT featureIndex = 0;
286  IndexedDouble maxFreq(0,0);
287  Vector< IndexedDouble > fftMagData(fftWindowSize);
288 
289  for(UINT i=0; i<numChannelsInFFTSignal; i++){
290  Float spectrumSum = 0;
291  maxFreq.value = 0;
292  maxFreq.index = 0;
293  centroidFeature = 0;
294 
295  for(UINT n=0; n<fftWindowSize; n++){
296 
297  //Find the max freq
298  if( inputVector[i*fftWindowSize + n] > maxFreq.value ){
299  maxFreq.value = inputVector[i*fftWindowSize + n];
300  maxFreq.index = n;
301  }
302 
303  centroidFeature += (n+1) * inputVector[i*fftWindowSize + n];
304 
305  spectrumSum += inputVector[i*fftWindowSize + n];
306 
307  //Copy the magnitude data so we can sort it later if needed
308  fftMagData[n].value = inputVector[i*fftWindowSize + n];
309  fftMagData[n].index = n;
310  }
311 
312  maxFreqFeature = maxFreq.index;
313  maxFreqSpectrumRatio = spectrumSum > 0 ? maxFreq.value/spectrumSum : 0;
314  centroidFeature = spectrumSum > 0 ? centroidFeature/spectrumSum : 0;
315 
316  if( computeMaxFreqFeature ){
317  featureVector[ featureIndex++ ] = maxFreqFeature;
318  }
319 
320  if( computeMaxFreqSpectrumRatio ){
321  featureVector[ featureIndex++ ] = maxFreqSpectrumRatio;
322  }
323 
324  if( computeCentroidFeature ){
325  featureVector[ featureIndex++ ] = centroidFeature;
326  }
327 
328  if( computeTopNFreqFeatures ){
329 
330  sort(fftMagData.begin(),fftMagData.end(),sortIndexDoubleDecendingValue);
331  for(UINT n=0; n<N; n++){
332  topNFreqFeatures[n] = fftMagData[n].index;
333  }
334 
335  for(UINT n=0; n<N; n++){
336  featureVector[ featureIndex++ ] = topNFreqFeatures[n];
337  }
338  }
339  }
340 
341  //Flag that the features are ready
342  featureDataReady = true;
343 
344  return true;
345 }
346 
348  if( initialized ) return init(fftWindowSize,numChannelsInFFTSignal,computeMaxFreqFeature,computeMaxFreqSpectrumRatio,computeCentroidFeature,computeTopNFreqFeatures,N);
349  return false;
350 }
351 
352 GRT_END_NAMESPACE
virtual bool saveModelToFile(std::string filename) const
Definition: FFTFeatures.cpp:98
virtual ~FFTFeatures(void)
Definition: FFTFeatures.cpp:58
bool saveFeatureExtractionSettingsToFile(std::fstream &file) const
virtual bool resize(const unsigned int size)
Definition: Vector.h:133
UINT getSize() const
Definition: Vector.h:191
std::string getFeatureExtractionType() const
This class implements the FFTFeatures featue extraction module.
FFTFeatures(UINT fftWindowSize=512, UINT numChannelsInFFTSignal=1, bool computeMaxFreqFeature=true, bool computeMaxFreqSpectrumRatio=true, bool computeCentroidFeature=true, bool computeTopNFreqFeatures=true, UINT N=10)
Definition: FFTFeatures.cpp:31
virtual bool deepCopyFrom(const FeatureExtraction *featureExtraction)
Definition: FFTFeatures.cpp:81
virtual bool computeFeatures(const VectorFloat &inputVector)
virtual bool reset()
bool loadFeatureExtractionSettingsFromFile(std::fstream &file)
virtual bool loadModelFromFile(std::string filename)
bool copyBaseVariables(const FeatureExtraction *featureExtractionModule)
FFTFeatures & operator=(const FFTFeatures &rhs)
Definition: FFTFeatures.cpp:62