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