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.
ThresholdCrossingDetector.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
23 
24 GRT_BEGIN_NAMESPACE
25 
26 ThresholdCrossingDetector::ThresholdCrossingDetector(UINT analysisMode,UINT thresholdCrossingMode,UINT detectionTimeoutMode,Float lowerThreshold,Float upperThreshold,Float hysteresisThreshold,UINT searchWindowSize,UINT searchTimeoutDuration,UINT offsetFilterSize){
27 
28  this->analysisMode = analysisMode;
29  this->thresholdCrossingMode = thresholdCrossingMode;
30  this->detectionTimeoutMode = detectionTimeoutMode;
31  this->searchWindowSize = searchWindowSize;
32  this->searchTimeoutDuration = searchTimeoutDuration;
33  this->offsetFilterSize = offsetFilterSize;
34  this->lowerThreshold = lowerThreshold;
35  this->upperThreshold = upperThreshold;
36  this->hysteresisThreshold = hysteresisThreshold;
37 
38  enableSearch = false;
39  thresholdCrossingDetected = false;
40  analysisValue = 0;
41  searchWindowIndex = 0;
42  currentSearchState = SEARCHING_FOR_FIRST_THRESHOLD_CROSSING;
43 
44  reset();
45 }
46 
48  this->analysisValue = rhs.analysisValue;
49  this->lowerThreshold = rhs.lowerThreshold;
50  this->upperThreshold = rhs.upperThreshold;
51  this->hysteresisThreshold = rhs.hysteresisThreshold;
52  this->enableSearch = rhs.enableSearch;
53  this->thresholdCrossingDetected = rhs.thresholdCrossingDetected;
54  this->analysisMode = rhs.analysisMode;
55  this->thresholdCrossingMode = rhs.thresholdCrossingMode;
56  this->searchTimeoutCounter = rhs.searchTimeoutCounter;
57  this->searchTimeoutDuration = rhs.searchTimeoutDuration;
58  this->searchWindowSize = rhs.searchWindowSize;
59  this->searchWindowIndex = rhs.searchWindowIndex;
60  this->offsetFilterSize = rhs.offsetFilterSize;
61  this->currentSearchState = rhs.currentSearchState;
62  this->movingAverageFilter = rhs.movingAverageFilter;
63  this->derivative = rhs.derivative;
64 }
65 
67 
68 }
69 
71  if(this!=&rhs){
72  this->analysisValue = rhs.analysisValue;
73  this->lowerThreshold = rhs.lowerThreshold;
74  this->upperThreshold = rhs.upperThreshold;
75  this->hysteresisThreshold = rhs.hysteresisThreshold;
76  this->enableSearch = rhs.enableSearch;
77  this->thresholdCrossingDetected = rhs.thresholdCrossingDetected;
78  this->analysisMode = rhs.analysisMode;
79  this->thresholdCrossingMode = rhs.thresholdCrossingMode;
80  this->searchTimeoutCounter = rhs.searchTimeoutCounter;
81  this->searchTimeoutDuration = rhs.searchTimeoutDuration;
82  this->searchWindowSize = rhs.searchWindowSize;
83  this->searchWindowIndex = rhs.searchWindowIndex;
84  this->offsetFilterSize = rhs.offsetFilterSize;
85  this->currentSearchState = rhs.currentSearchState;
86  this->movingAverageFilter = rhs.movingAverageFilter;
87  this->derivative = rhs.derivative;
88  }
89  return *this;
90 }
91 
92 bool ThresholdCrossingDetector::update( const Float x ){
93 
94  thresholdCrossingDetected = false;
95 
96  Float deriv = derivative.computeDerivative( x );
97  Float offset = movingAverageFilter.filter( x );
98 
99  //If the search is disabled then we stop here
100  if( !enableSearch ){ return thresholdCrossingDetected; }
101 
102  //Perform the search
103  analysisValue = 0;
104  bool upperThresholdCrossingFound = false;
105  bool lowerThresholdCrossingFound = false;
106 
107  switch( analysisMode ){
108  case RAW_DATA_ANALYSIS_MODE:
109  analysisValue = x;
110  break;
111  case MOVING_OFFSET_ANALYSIS_MODE:
112  analysisValue = x - offset;
113  break;
114  case DERIVATIVE_ANALYSIS_MODE:
115  analysisValue = deriv;
116  break;
117  }
118 
119  //Check to see if we should start searching again
120  if( currentSearchState == NO_SEARCH_GATE_TIME_OUT ){
121 
122  switch( detectionTimeoutMode ){
123  case TIMEOUT_COUNTER:
124  // searchTimeoutDuration is cast because of a C4018 warning on visual (signed/unsigned incompatibility)
125  if (searchTimeoutCounter.getMilliSeconds() >= (signed long)searchTimeoutDuration){
126  currentSearchState = SEARCHING_FOR_FIRST_THRESHOLD_CROSSING;
127  searchTimeoutCounter.stop();
128  }else return false;
129  break;
130  case HYSTERESIS_THRESHOLD:
131  switch ( thresholdCrossingMode ) {
132  case UPPER_THRESHOLD_CROSSING:
133  if( analysisValue <= hysteresisThreshold ){
134  currentSearchState = SEARCHING_FOR_FIRST_THRESHOLD_CROSSING;
135  }else return false;
136  break;
137  case LOWER_THRESHOLD_CROSSING:
138  if( analysisValue >= hysteresisThreshold ){
139  currentSearchState = SEARCHING_FOR_FIRST_THRESHOLD_CROSSING;
140  }else return false;
141  break;
142  default:
143  break;
144  }
145 
146  break;
147  }
148 
149  }
150 
151  if( thresholdCrossingMode == UPPER_THRESHOLD_CROSSING || thresholdCrossingMode == LOWER_THRESHOLD_CROSSING || thresholdCrossingMode == UPPER_OR_LOWER_THRESHOLD_CROSSING ){
152  //Has the deriv of the input passed either threshold
153  switch ( thresholdCrossingMode ) {
154  case UPPER_THRESHOLD_CROSSING:
155  if( analysisValue >= upperThreshold ){
156  upperThresholdCrossingFound = true;
157  thresholdCrossingDetected = true;
158  currentSearchState = NO_SEARCH_GATE_TIME_OUT;
159  searchTimeoutCounter.start();
160  }
161  break;
162  case LOWER_THRESHOLD_CROSSING:
163  if( analysisValue <= lowerThreshold ){
164  lowerThresholdCrossingFound = true;
165  thresholdCrossingDetected = true;
166  currentSearchState = NO_SEARCH_GATE_TIME_OUT;
167  searchTimeoutCounter.start();
168  }
169  break;
170  case UPPER_OR_LOWER_THRESHOLD_CROSSING:
171  if( analysisValue >= upperThreshold ){
172  upperThresholdCrossingFound = true;
173  thresholdCrossingDetected = true;
174  currentSearchState = NO_SEARCH_GATE_TIME_OUT;
175  searchTimeoutCounter.start();
176  }else if( analysisValue <= lowerThreshold ){
177  lowerThresholdCrossingFound = true;
178  thresholdCrossingDetected = true;
179  currentSearchState = NO_SEARCH_GATE_TIME_OUT;
180  searchTimeoutCounter.start();
181  }
182  break;
183  default:
184  break;
185  }
186  return thresholdCrossingDetected ? true : false;
187  }else{
188 
189  //Check to make sure the search has not timed out
190  if( currentSearchState == SEARCHING_FOR_SECOND_THRESHOLD_CROSSING ){
191  if( ++searchWindowIndex == searchWindowSize ){
192  currentSearchState = SEARCHING_FOR_FIRST_THRESHOLD_CROSSING;
193  searchWindowIndex = 0;
194  }
195  }
196 
197  //If we are in the NO_SEARCH_GATE_TIME_OUT state then we need to update the counter
198  if( currentSearchState == NO_SEARCH_GATE_TIME_OUT ){
199  // searchTimeoutDuration is cast because of a C4018 warning on visual (signed/unsigned incompatibility)
200  if (searchTimeoutCounter.getMilliSeconds() >= (signed long)searchTimeoutDuration){
201  currentSearchState = SEARCHING_FOR_FIRST_THRESHOLD_CROSSING;
202  searchTimeoutCounter.stop();
203  }
204  }
205 
206  //Has the deriv of the input passed either threshold
207  if( analysisValue >= upperThreshold ){ upperThresholdCrossingFound = true; }
208  if( analysisValue <= lowerThreshold ){ lowerThresholdCrossingFound = true; }
209  if( !upperThresholdCrossingFound && !lowerThresholdCrossingFound &&
210  currentSearchState != NO_SEARCH_GATE_TIME_OUT ){ return false; }
211 
212  switch ( currentSearchState ) {
213  case SEARCHING_FOR_FIRST_THRESHOLD_CROSSING:
214  if( thresholdCrossingMode == UPPER_THEN_LOWER_THRESHOLD_CROSSING && upperThresholdCrossingFound ){
215  searchWindowIndex = 0;
216  currentSearchState = SEARCHING_FOR_SECOND_THRESHOLD_CROSSING;
217  return false;
218  }
219  if( thresholdCrossingMode == LOWER_THEN_UPPER_THRESHOLD_CROSSING && lowerThresholdCrossingFound ){
220  searchWindowIndex = 0;
221  currentSearchState = SEARCHING_FOR_SECOND_THRESHOLD_CROSSING;
222  return false;
223  }
224  break;
225  case SEARCHING_FOR_SECOND_THRESHOLD_CROSSING:
226  if( thresholdCrossingMode == UPPER_THEN_LOWER_THRESHOLD_CROSSING && lowerThresholdCrossingFound ){
227  currentSearchState = NO_SEARCH_GATE_TIME_OUT;
228  searchWindowIndex = 0;
229  searchTimeoutCounter.start();
230  thresholdCrossingDetected = true;
231  break;
232  }
233  if( thresholdCrossingMode == LOWER_THEN_UPPER_THRESHOLD_CROSSING && upperThresholdCrossingFound ){
234  currentSearchState = NO_SEARCH_GATE_TIME_OUT;
235  searchWindowIndex = 0;
236  searchTimeoutCounter.start();
237  thresholdCrossingDetected = true;
238  break;
239  }
240  break;
241  default:
242  break;
243  }
244  }
245 
246  return thresholdCrossingDetected ? true : false;
247 }
248 
250 
251  //Reset the derivative
252  derivative.init(Derivative::FIRST_DERIVATIVE, 1, 1, true, 5);
253 
254  movingAverageFilter.init(offsetFilterSize, 1);
255 
256  //Set the search state
257  currentSearchState = NO_SEARCH_GATE_TIME_OUT;
258 
259  //Enable future searches
260  enableSearch = true;
261  thresholdCrossingDetected = false;
262  analysisValue = 0;
263  searchWindowIndex = 0;
264  searchTimeoutCounter.stop();
265 
266  return true;
267 }
268 
270  currentSearchState = NO_SEARCH_GATE_TIME_OUT;
271  searchTimeoutCounter.start();
272  return true;
273 }
274 
276  return thresholdCrossingDetected;
277 }
278 
280  return enableSearch;
281 }
282 
284  return analysisMode;
285 }
286 
288  return thresholdCrossingMode;
289 }
290 
292  return searchWindowSize;
293 }
294 
296  return offsetFilterSize;
297 }
298 
300  return searchWindowIndex;
301 }
302 
304  return (UINT)searchTimeoutCounter.getMilliSeconds();
305 }
306 
308  return searchTimeoutDuration;
309 }
310 
312  return analysisValue;
313 }
314 
316  return upperThreshold;
317 }
318 
320  return lowerThreshold;
321 }
322 
324  return hysteresisThreshold;
325 }
326 
327 bool ThresholdCrossingDetector::setEnableSearch(const bool enableSearch){
328  this->enableSearch = enableSearch;
329  return true;
330 }
331 
332 bool ThresholdCrossingDetector::setAnalysisMode(const UINT analysisMode){
333  this->analysisMode = analysisMode;
334  return reset();
335 }
336 
337 bool ThresholdCrossingDetector::setThresholdCrossingMode(const UINT thresholdCrossingMode){
338  this->thresholdCrossingMode = thresholdCrossingMode;
339  return reset();
340 }
341 
342 bool ThresholdCrossingDetector::setDetectionTimeoutMode(const UINT detectionTimeoutMode){
343  this->detectionTimeoutMode = detectionTimeoutMode;
344  return reset();
345 }
346 
347 bool ThresholdCrossingDetector::setSearchWindowSize(const UINT searchWindowSize){
348  this->searchWindowSize = searchWindowSize;
349  return reset();
350 }
351 
352 bool ThresholdCrossingDetector::setOffsetFilterSize(const UINT offsetFilterSize){
353  this->offsetFilterSize = offsetFilterSize;
354  return reset();
355 }
356 
357 bool ThresholdCrossingDetector::setSearchTimeoutDuration(const UINT searchTimeoutDuration){
358  this->searchTimeoutDuration = searchTimeoutDuration;
359  return reset();
360 }
361 
362 bool ThresholdCrossingDetector::setLowerThreshold(const Float lowerThreshold){
363  this->lowerThreshold = lowerThreshold;
364  return reset();
365 }
366 
367 bool ThresholdCrossingDetector::setUpperThreshold(const Float upperThreshold){
368  this->upperThreshold = upperThreshold;
369  return reset();
370 }
371 
372 bool ThresholdCrossingDetector::setHysteresisThreshold(const Float hysteresisThreshold){
373  this->hysteresisThreshold = hysteresisThreshold;
374  return reset();
375 }
376 
377 GRT_END_NAMESPACE
bool setUpperThreshold(const Float upperThreshold)
bool init(UINT filterSize, UINT numDimensions)
bool setOffsetFilterSize(const UINT offsetFilterSize)
bool setSearchWindowSize(const UINT searchWindowSize)
bool init(UINT derivativeOrder, Float delta, UINT numDimensions, bool filterData, UINT filterSize)
Definition: Derivative.cpp:214
bool setDetectionTimeoutMode(const UINT detectionTimeoutMode)
This class implements a threshold crossing detector.
bool setHysteresisThreshold(const Float hysteresisThreshold)
signed long getMilliSeconds()
Definition: Timer.h:117
Float computeDerivative(const Float x)
Definition: Derivative.cpp:255
bool setAnalysisMode(const UINT analysisMode)
bool setLowerThreshold(const Float lowerThreshold)
Float filter(const Float x)
ThresholdCrossingDetector & operator=(const ThresholdCrossingDetector &rhs)
bool setEnableSearch(const bool enableSearch)
bool setThresholdCrossingMode(const UINT thresholdCrossingMode)
bool setSearchTimeoutDuration(const UINT searchTimeoutDuration)
bool start()
Definition: Timer.h:64
ThresholdCrossingDetector(UINT analysisMode=RAW_DATA_ANALYSIS_MODE, UINT thresholdCrossingMode=UPPER_THRESHOLD_CROSSING, UINT detectionTimeoutMode=TIMEOUT_COUNTER, Float lowerThreshold=-1, Float upperThreshold=1, Float hysteresisThreshold=0, UINT searchWindowSize=20, UINT searchTimeoutDuration=1000, UINT offsetFilterSize=10)
bool stop()
Definition: Timer.h:105