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.
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 GRT_BEGIN_NAMESPACE
24 
25 //Register the ZeroCrossingCounter module with the FeatureExtraction base class
26 RegisterFeatureExtractionModule< ZeroCrossingCounter > ZeroCrossingCounter::registerModule("ZeroCrossingCounter");
27 
28 ZeroCrossingCounter::ZeroCrossingCounter(UINT searchWindowSize,Float 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!" << std::endl;
80 
81  return false;
82 }
83 
85 
86  if( !initialized ){
87  errorLog << "computeFeatures(const VectorFloat &inputVector) - Not initialized!" << std::endl;
88  return false;
89  }
90 
91  if( inputVector.size() != numInputDimensions ){
92  errorLog << "computeFeatures(const VectorFloat &inputVector) - The size of the inputVector (" << inputVector.size() << ") does not match that of the filter (" << numInputDimensions << ")!" << std::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( std::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 
122 bool ZeroCrossingCounter::loadModelFromFile( std::string filename ){
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( std::fstream &file ) const{
138 
139  if( !file.is_open() ){
140  errorLog << "saveModelToFile(fstream &file) - The file is not open!" << std::endl;
141  return false;
142  }
143 
144  //Write the file header
145  file << "GRT_ZERO_CROSSING_COUNTER_FILE_V1.0" << std::endl;
146 
147  //Save the base settings to the file
149  errorLog << "saveFeatureExtractionSettingsToFile(fstream &file) - Failed to save base feature extraction settings to file!" << std::endl;
150  return false;
151  }
152 
153  //Write the zero crossing counter settings
154  file << "SearchWindowSize: " << searchWindowSize << std::endl;
155  file << "FeatureMode: " << featureMode << std::endl;
156  file << "DeadZoneThreshold: " << deadZoneThreshold << std::endl;
157 
158  return true;
159 }
160 
161 bool ZeroCrossingCounter::loadModelFromFile( std::fstream &file ){
162 
163  if( !file.is_open() ){
164  errorLog << "loadModelFromFile(fstream &file) - The file is not open!" << std::endl;
165  return false;
166  }
167 
168  std::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!" << std::endl;
175  return false;
176  }
177 
179  errorLog << "loadFeatureExtractionSettingsFromFile(fstream &file) - Failed to load base feature extraction settings from file!" << std::endl;
180  return false;
181  }
182 
183  file >> word;
184  if( word != "SearchWindowSize:" ){
185  errorLog << "loadModelFromFile(fstream &file) - Failed to read SearchWindowSize header!" << std::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!" << std::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!" << std::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,Float deadZoneThreshold,UINT numDimensions,UINT featureMode){
209 
210  initialized = false;
211  featureDataReady = false;
212 
213  if( searchWindowSize == 0 ){
214  errorLog << "init(UINT searchWindowSize,Float deadZoneThreshold,UINT numDimensions,UINT featureMode) - The searchWindowSize must be greater than zero!" << std::endl;
215  return false;
216  }
217 
218  if( deadZoneThreshold < 0 ){
219  errorLog << "init(UINT searchWindowSize,Float deadZoneThreshold,UINT numDimensions,UINT featureMode) - The deadZoneThreshold must be greater than zero!" << std::endl;
220  return false;
221  }
222 
223  if( numDimensions == 0 ){
224  errorLog << "init(UINT searchWindowSize,Float deadZoneThreshold,UINT numDimensions,UINT featureMode) - The numDimensions must be greater than zero!" << std::endl;
225  return false;
226  }
227 
228  if( featureMode != INDEPENDANT_FEATURE_MODE && featureMode != COMBINED_FEATURE_MODE ){
229  errorLog << "init(UINT searchWindowSize,Float deadZoneThreshold,UINT numDimensions,UINT featureMode) - Unkown feature mode!" << std::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, VectorFloat(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 
252  return update(VectorFloat(1,x));
253 }
254 
256 
257  if( !initialized ){
258  errorLog << "update(const VectorFloat &x) - Not Initialized!" << std::endl;
259  return VectorFloat();
260  }
261 
262  if( x.getSize() != numInputDimensions ){
263  errorLog << "update(const VectorFloat &x)- The Number Of Input Dimensions (" << numInputDimensions << ") does not match the size of the input vector (" << x.getSize() << ")!" << std::endl;
264  return VectorFloat();
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  Float maxValue = 0;
290  UINT searchSize = i > 5 ? 5 : i;
291  for(UINT n=0; n<searchSize; n++){
292  Float 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!" << std::endl;
313  return false;
314 }
315 
316 bool ZeroCrossingCounter::setFeatureMode(UINT featureMode){
317  if( featureMode == INDEPENDANT_FEATURE_MODE || featureMode == COMBINED_FEATURE_MODE ){
318  this->featureMode = featureMode;
319  if( initialized ) return reset();
320  return true;
321  }
322  errorLog << "setFeatureMode(UINT featureMode) - Unkown feature mode!" << std::endl;
323  return false;
324 }
325 
326 bool ZeroCrossingCounter::setDeadZoneThreshold(Float deadZoneThreshold){
327  if( deadZoneThreshold > 0 ){
328  this->deadZoneThreshold = deadZoneThreshold;
329  if( initialized ) return reset();
330  return true;
331  }
332  errorLog << "setDeadZoneThreshold(Float deadZoneThreshold) - The deadZoneThreshold must be larger than zero!" << std::endl;
333  return false;
334 }
335 
336 GRT_END_NAMESPACE
bool push_back(const T &value)
bool setDeadZoneThreshold(Float deadZoneThreshold)
DeadZone deadZone
Used to remove small amounts of noise from the data.
VectorFloat update(Float x)
bool saveFeatureExtractionSettingsToFile(std::fstream &file) const
virtual bool resize(const unsigned int size)
Definition: Vector.h:133
virtual bool deepCopyFrom(const FeatureExtraction *featureExtraction)
Float filter(const Float x)
Definition: DeadZone.cpp:233
bool init(UINT derivativeOrder, Float delta, UINT numDimensions, bool filterData, UINT filterSize)
Definition: Derivative.cpp:249
Float computeDerivative(const Float x)
Definition: Derivative.cpp:290
unsigned int getSize() const
Definition: Vector.h:193
CircularBuffer< VectorFloat > dataBuffer
A buffer used to store the previous derivative data.
std::string getFeatureExtractionType() const
virtual bool saveModelToFile(std::string filename) const
UINT searchWindowSize
The size of the search window, i.e. the amount of previous data stored and searched.
bool init(Float lowerLimit, Float upperLimit, UINT numDimensions)
Definition: DeadZone.cpp:208
ZeroCrossingCounter & operator=(const ZeroCrossingCounter &rhs)
virtual bool computeFeatures(const VectorFloat &inputVector)
UINT featureMode
The featureMode controls how the features are added to the feature vector.
bool setSearchWindowSize(UINT searchWindowSize)
VectorFloat getProcessedData() const
virtual bool loadModelFromFile(std::string filename)
bool loadFeatureExtractionSettingsFromFile(std::fstream &file)
Float deadZoneThreshold
The threshold value used for the dead zone filter.
Derivative derivative
Used to compute the derivative of the input signal.
bool copyBaseVariables(const FeatureExtraction *featureExtractionModule)
bool setFeatureMode(UINT featureMode)
unsigned int getSize() const
ZeroCrossingCounter(UINT searchWindowSize=20, Float deadZoneThreshold=0.01, UINT numDimensions=1, UINT featureMode=INDEPENDANT_FEATURE_MODE)
bool resize(const unsigned int newBufferSize)