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