GestureRecognitionToolkit  Version: 1.0 Revision: 04-03-15
The Gesture Recognition Toolkit (GRT) is a cross-platform, open-source, c++ machine learning library for real-time gesture recognition.
ZeroCrossingCounter.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 "ZeroCrossingCounter.h"
22 
23 namespace GRT{
24 
25 //Register the ZeroCrossingCounter module with the FeatureExtraction base class
26 RegisterFeatureExtractionModule< ZeroCrossingCounter > ZeroCrossingCounter::registerModule("ZeroCrossingCounter");
27 
28 ZeroCrossingCounter::ZeroCrossingCounter(UINT searchWindowSize,double deadZoneThreshold,UINT numDimensions,UINT featureMode){
29 
30  classType = "ZeroCrossingCounter";
31  featureExtractionType = classType;
32  debugLog.setProceedingText("[DEBUG ZeroCrossingCounter]");
33  errorLog.setProceedingText("[ERROR ZeroCrossingCounter]");
34  warningLog.setProceedingText("[WARNING ZeroCrossingCounter]");
35 
36  init(searchWindowSize,deadZoneThreshold,numDimensions,featureMode);
37 }
38 
40 
41  classType = "ZeroCrossingCounter";
42  featureExtractionType = classType;
43  debugLog.setProceedingText("[DEBUG ZeroCrossingCounter]");
44  errorLog.setProceedingText("[ERROR ZeroCrossingCounter]");
45  warningLog.setProceedingText("[WARNING ZeroCrossingCounter]");
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){
58  this->featureMode = rhs.featureMode;
60  this->derivative = rhs.derivative;
61  this->deadZone = rhs.deadZone;
62  this->dataBuffer = rhs.dataBuffer;
63 
65  }
66  return *this;
67 }
68 
70 
71  if( featureExtraction == NULL ) return false;
72 
73  if( this->getFeatureExtractionType() == featureExtraction->getFeatureExtractionType() ){
74  //Invoke the equals operator to copy the data from the rhs instance to this instance
75  *this = *(ZeroCrossingCounter*)featureExtraction;
76  return true;
77  }
78 
79  errorLog << "clone(FeatureExtraction *featureExtraction) - FeatureExtraction Types Do Not Match!" << endl;
80 
81  return false;
82 }
83 
84 bool ZeroCrossingCounter::computeFeatures(const VectorDouble &inputVector){
85 
86  if( !initialized ){
87  errorLog << "computeFeatures(const VectorDouble &inputVector) - Not initialized!" << endl;
88  return false;
89  }
90 
91  if( inputVector.size() != numInputDimensions ){
92  errorLog << "computeFeatures(const VectorDouble &inputVector) - The size of the inputVector (" << inputVector.size() << ") does not match that of the filter (" << numInputDimensions << ")!" << endl;
93  return false;
94  }
95 
96  update( inputVector );
97 
98  return true;
99 }
100 
102  if( initialized ){
103  return init( searchWindowSize, deadZoneThreshold, numInputDimensions, featureMode );
104  }
105  return false;
106 }
107 
108 bool ZeroCrossingCounter::saveModelToFile(string filename) const{
109 
110  std::fstream file;
111  file.open(filename.c_str(), std::ios::out);
112 
113  if( !saveModelToFile( file ) ){
114  return false;
115  }
116 
117  file.close();
118 
119  return true;
120 }
121 
123 
124  std::fstream file;
125  file.open(filename.c_str(), std::ios::in);
126 
127  if( !loadModelFromFile( file ) ){
128  return false;
129  }
130 
131  //Close the file
132  file.close();
133 
134  return true;
135 }
136 
137 bool ZeroCrossingCounter::saveModelToFile(fstream &file) const{
138 
139  if( !file.is_open() ){
140  errorLog << "saveModelToFile(fstream &file) - The file is not open!" << endl;
141  return false;
142  }
143 
144  //Write the file header
145  file << "GRT_ZERO_CROSSING_COUNTER_FILE_V1.0" << endl;
146 
147  //Save the base settings to the file
149  errorLog << "saveFeatureExtractionSettingsToFile(fstream &file) - Failed to save base feature extraction settings to file!" << endl;
150  return false;
151  }
152 
153  //Write the zero crossing counter settings
154  file << "SearchWindowSize: " << searchWindowSize << endl;
155  file << "FeatureMode: " << featureMode << endl;
156  file << "DeadZoneThreshold: " << deadZoneThreshold << endl;
157 
158  return true;
159 }
160 
162 
163  if( !file.is_open() ){
164  errorLog << "loadModelFromFile(fstream &file) - The file is not open!" << endl;
165  return false;
166  }
167 
168  string word;
169 
170  //Load the header
171  file >> word;
172 
173  if( word != "GRT_ZERO_CROSSING_COUNTER_FILE_V1.0" ){
174  errorLog << "loadModelFromFile(fstream &file) - Invalid file format!" << endl;
175  return false;
176  }
177 
179  errorLog << "loadFeatureExtractionSettingsFromFile(fstream &file) - Failed to load base feature extraction settings from file!" << endl;
180  return false;
181  }
182 
183  file >> word;
184  if( word != "SearchWindowSize:" ){
185  errorLog << "loadModelFromFile(fstream &file) - Failed to read SearchWindowSize header!" << endl;
186  return false;
187  }
188  file >> searchWindowSize;
189 
190  file >> word;
191  if( word != "FeatureMode:" ){
192  errorLog << "loadModelFromFile(fstream &file) - Failed to read FeatureMode header!" << endl;
193  return false;
194  }
195  file >> featureMode;
196 
197  file >> word;
198  if( word != "DeadZoneThreshold:" ){
199  errorLog << "loadModelFromFile(fstream &file) - Failed to read DeadZoneThreshold header!" << endl;
200  return false;
201  }
202  file >> deadZoneThreshold;
203 
204  //Init the ZeroCrossingCounter module to ensure everything is initialized correctly
205  return init(searchWindowSize,deadZoneThreshold,numInputDimensions,featureMode);
206 }
207 
208 bool ZeroCrossingCounter::init(UINT searchWindowSize,double deadZoneThreshold,UINT numDimensions,UINT featureMode){
209 
210  initialized = false;
211  featureDataReady = false;
212 
213  if( searchWindowSize == 0 ){
214  errorLog << "init(UINT searchWindowSize,double deadZoneThreshold,UINT numDimensions,UINT featureMode) - The searchWindowSize must be greater than zero!" << endl;
215  return false;
216  }
217 
218  if( deadZoneThreshold < 0 ){
219  errorLog << "init(UINT searchWindowSize,double deadZoneThreshold,UINT numDimensions,UINT featureMode) - The deadZoneThreshold must be greater than zero!" << endl;
220  return false;
221  }
222 
223  if( numDimensions == 0 ){
224  errorLog << "init(UINT searchWindowSize,double deadZoneThreshold,UINT numDimensions,UINT featureMode) - The numDimensions must be greater than zero!" << endl;
225  return false;
226  }
227 
228  if( featureMode != INDEPENDANT_FEATURE_MODE && featureMode != COMBINED_FEATURE_MODE ){
229  errorLog << "init(UINT searchWindowSize,double deadZoneThreshold,UINT numDimensions,UINT featureMode) - Unkown feature mode!" << endl;
230  return false;
231  }
232 
233  //Setup the search variables
234  this->searchWindowSize = searchWindowSize;
235  this->featureMode = featureMode;
236  this->deadZoneThreshold = deadZoneThreshold;
237  numInputDimensions = numDimensions;
238  numOutputDimensions = (featureMode == INDEPENDANT_FEATURE_MODE ? TOTAL_NUM_ZERO_CROSSING_FEATURES * numInputDimensions : TOTAL_NUM_ZERO_CROSSING_FEATURES);
239  derivative.init(Derivative::FIRST_DERIVATIVE, 1.0, numInputDimensions, true, 5);
240  deadZone.init(-deadZoneThreshold,deadZoneThreshold,numInputDimensions);
241  dataBuffer.resize( searchWindowSize, vector< double >(numInputDimensions,NAN) );
242  featureVector.resize(numOutputDimensions,0);
243 
244  //Flag that the zero crossing counter has been initialized
245  initialized = true;
246 
247  return true;
248 }
249 
250 
251 VectorDouble ZeroCrossingCounter::update(double x){
252  return update(VectorDouble(1,x));
253 }
254 
255 VectorDouble ZeroCrossingCounter::update(const VectorDouble &x){
256 
257  if( !initialized ){
258  errorLog << "update(const VectorDouble &x) - Not Initialized!" << endl;
259  return vector<double>();
260  }
261 
262  if( x.size() != numInputDimensions ){
263  errorLog << "update(const VectorDouble &x)- The Number Of Input Dimensions (" << numInputDimensions << ") does not match the size of the input vector (" << x.size() << ")!" << endl;
264  return vector<double>();
265  }
266 
267  //Clear the feature vector
268  std::fill(featureVector.begin(),featureVector.end(),0);
269 
270  //Update the derivative data and
272 
273  //Dead zone the derivative data
275 
276  //Add the deadzone data to the buffer
278 
279  //Search the buffer for the zero crossing features
280  for(UINT j=0; j<numInputDimensions; j++){
281  UINT colIndex = (featureMode == INDEPENDANT_FEATURE_MODE ? (TOTAL_NUM_ZERO_CROSSING_FEATURES*j) : 0);
282  for(UINT i=1; i<dataBuffer.getSize(); i++){
283  //Search for a zero crossing
284  if( (dataBuffer[i][j] > 0 && dataBuffer[i-1][j] <= 0) || (dataBuffer[i][j] < 0 && dataBuffer[i-1][j] >= 0) ){
285  //Update the zero crossing count
286  featureVector[ NUM_ZERO_CROSSINGS_COUNTED + colIndex ]++;
287 
288  //Update the magnitude, search the last 5 values around the zero crossing to make sure we get the maxima of the peak
289  double maxValue = 0;
290  UINT searchSize = i > 5 ? 5 : i;
291  for(UINT n=0; n<searchSize; n++){
292  double value = fabs( dataBuffer[ i-n ][j] );
293  if( value > maxValue ) maxValue = value;
294  }
295  featureVector[ ZERO_CROSSING_MAGNITUDE + colIndex ] += maxValue;
296  }
297  }
298  }
299 
300  //Flag that the feature data has been computed
301  featureDataReady = true;
302 
303  return featureVector;
304 }
305 
306 bool ZeroCrossingCounter::setSearchWindowSize(UINT searchWindowSize){
307  if( searchWindowSize > 0 ){
308  this->searchWindowSize = searchWindowSize;
309  if( initialized ) return reset();
310  return true;
311  }
312  errorLog << "setSearchWindowSize(UINT searchWindowSize) - The searchWindowSize must be larger than zero!" << endl;
313  return false;
314 }
315 
316 bool ZeroCrossingCounter::setDeadZoneThreshold(UINT deadZoneThreshold){
317  if( deadZoneThreshold > 0 ){
318  this->deadZoneThreshold = deadZoneThreshold;
319  if( initialized ) return reset();
320  return true;
321  }
322  errorLog << "setDeadZoneThreshold(UINT deadZoneThreshold) - The deadZoneThreshold must be larger than zero!" << endl;
323  return false;
324 }
325 
326 bool ZeroCrossingCounter::setFeatureMode(UINT featureMode){
327  if( featureMode == INDEPENDANT_FEATURE_MODE || featureMode == COMBINED_FEATURE_MODE ){
328  this->featureMode = featureMode;
329  if( initialized ) return reset();
330  return true;
331  }
332  errorLog << "setFeatureMode(UINT featureMode) - Unkown feature mode!" << endl;
333  return false;
334 
335 }
336 
337 }//End of namespace GRT
virtual bool saveModelToFile(string filename) const
bool init(double lowerLimit, double upperLimit, UINT numDimensions)
Definition: DeadZone.cpp:208
VectorDouble update(double x)
Definition: AdaBoost.cpp:25
virtual bool computeFeatures(const VectorDouble &inputVector)
double filter(const double x)
Definition: DeadZone.cpp:233
virtual bool loadModelFromFile(string filename)
string getFeatureExtractionType() const
double deadZoneThreshold
The threshold value used for the dead zone filter.
CircularBuffer< VectorDouble > dataBuffer
A buffer used to store the previous derivative data.
bool push_back(const T &value)
bool init(UINT derivativeOrder, double delta, UINT numDimensions, bool filterData, UINT filterSize)
Definition: Derivative.cpp:249
bool setSearchWindowSize(UINT searchWindowSize)
bool resize(const unsigned int newBufferSize)
bool loadFeatureExtractionSettingsFromFile(fstream &file)
unsigned int getSize() const
bool setFeatureMode(UINT featureMode)
VectorDouble getProcessedData() const
virtual bool deepCopyFrom(const FeatureExtraction *featureExtraction)
bool setDeadZoneThreshold(UINT deadZoneThreshold)
bool saveFeatureExtractionSettingsToFile(fstream &file) const
DeadZone deadZone
Used to remove small amounts of noise from the data.
ZeroCrossingCounter & operator=(const ZeroCrossingCounter &rhs)
ZeroCrossingCounter(UINT searchWindowSize=20, double deadZoneThreshold=0.01, UINT numDimensions=1, UINT featureMode=INDEPENDANT_FEATURE_MODE)
Derivative derivative
Used to compute the derivative of the input signal.
double computeDerivative(const double x)
Definition: Derivative.cpp:290
bool copyBaseVariables(const FeatureExtraction *featureExtractionModule)
UINT featureMode
The featureMode controls how the features are added to the feature vector.
UINT searchWindowSize
The size of the search window, i.e. the amount of previous data stored and searched.