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