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.
SavitzkyGolayFilter.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 "SavitzkyGolayFilter.h"
23 
24 GRT_BEGIN_NAMESPACE
25 
26 //Register the SavitzkyGolayFilter module with the PreProcessing base class
27 RegisterPreProcessingModule< SavitzkyGolayFilter > SavitzkyGolayFilter::registerModule("SavitzkyGolayFilter");
28 
29 SavitzkyGolayFilter::SavitzkyGolayFilter(UINT numLeftHandPoints,UINT numRightHandPoints,UINT derivativeOrder,UINT smoothingPolynomialOrder,UINT numDimensions){
30 
31  classType = "SavitzkyGolayFilter";
32  preProcessingType = classType;
33  debugLog.setProceedingText("[DEBUG SavitzkyGolayFilter]");
34  errorLog.setProceedingText("[ERROR SavitzkyGolayFilter]");
35  warningLog.setProceedingText("[WARNING SavitzkyGolayFilter]");
36  init(numLeftHandPoints,numRightHandPoints,derivativeOrder,smoothingPolynomialOrder,numDimensions);
37 }
38 
40 
41  this->numPoints = rhs.numPoints;
42  this->numLeftHandPoints = rhs.numLeftHandPoints;
43  this->numRightHandPoints = rhs.numRightHandPoints;
44  this->derivativeOrder = rhs.derivativeOrder;
45  this->smoothingPolynomialOrder = rhs.smoothingPolynomialOrder;
46  this->data = rhs.data;
47  this->yy = rhs.yy;
48  this->coeff = rhs.coeff;
49 
50  classType = "SavitzkyGolayFilter";
51  preProcessingType = classType;
52  debugLog.setProceedingText("[DEBUG SavitzkyGolayFilter]");
53  errorLog.setProceedingText("[ERROR SavitzkyGolayFilter]");
54  warningLog.setProceedingText("[WARNING SavitzkyGolayFilter]");
55 
57 }
58 
60 
61 }
62 
64  if(this!=&rhs){
65  this->numPoints = rhs.numPoints;
66  this->numLeftHandPoints = rhs.numLeftHandPoints;
67  this->numRightHandPoints = rhs.numRightHandPoints;
68  this->derivativeOrder = rhs.derivativeOrder;
69  this->smoothingPolynomialOrder = rhs.smoothingPolynomialOrder;
70  this->data = rhs.data;
71  this->yy = rhs.yy;
72  this->coeff = rhs.coeff;
74  }
75  return *this;
76 }
77 
79 
80  if( preProcessing == NULL ) return false;
81 
82  if( this->getPreProcessingType() == preProcessing->getPreProcessingType() ){
83 
84  SavitzkyGolayFilter *ptr = (SavitzkyGolayFilter*)preProcessing;
85 
86  //Clone the SavitzkyGolayFilter values
87  this->numPoints = ptr->numPoints;
88  this->numLeftHandPoints = ptr->numLeftHandPoints;
89  this->numRightHandPoints = ptr->numRightHandPoints;
90  this->derivativeOrder = ptr->derivativeOrder;
91  this->smoothingPolynomialOrder = ptr->smoothingPolynomialOrder;
92  this->data = ptr->data;
93  this->yy = ptr->yy;
94  this->coeff = ptr->coeff;
95 
96  //Clone the base class variables
97  return copyBaseVariables( preProcessing );
98  }
99 
100  errorLog << "clone(PreProcessing *preProcessing) - PreProcessing Types Do Not Match!" << std::endl;
101 
102  return false;
103 }
104 
105 bool SavitzkyGolayFilter::process(const VectorFloat &inputVector){
106 
107  if( !initialized ){
108  errorLog << "process(const VectorFloat &inputVector) - Not initialized!" << std::endl;
109  return false;
110  }
111 
112  if( inputVector.size() != numInputDimensions ){
113  errorLog << "process(const VectorFloat &inputVector) - The size of the inputVector (" << inputVector.size() << ") does not match that of the filter (" << numInputDimensions << ")!" << std::endl;
114  return false;
115  }
116 
117  processedData = filter( inputVector );
118 
119  if( processedData.size() == numOutputDimensions ) return true;
120  return false;
121 
122 }
123 
125  if( initialized ){
126  data.setAllValues(VectorFloat(numInputDimensions,0));
127  yy.clear();
128  yy.resize(numInputDimensions,0);
129  processedData.clear();
130  processedData.resize(numInputDimensions,0);
131  return true;
132  }
133  return false;
134 }
135 
136 bool SavitzkyGolayFilter::save(std::fstream &file) const{
137 
138  if( !file.is_open() ){
139  errorLog << "save(std::fstream &file) - The file is not open!" << std::endl;
140  return false;
141  }
142 
143  file << "GRT_SAVITZKY_GOLAY_FILTER_FILE_V1.0" << std::endl;
144 
145  file << "NumInputDimensions: " << numInputDimensions << std::endl;
146  file << "NumOutputDimensions: " << numOutputDimensions << std::endl;
147  file << "NumPoints: " << numPoints << std::endl;
148  file << "NumLeftHandPoints: " << numLeftHandPoints << std::endl;
149  file << "NumRightHandPoints: " << numRightHandPoints << std::endl;
150  file << "DerivativeOrder: " << derivativeOrder << std::endl;
151  file << "SmoothingPolynomialOrder: " << smoothingPolynomialOrder << std::endl;
152 
153  return true;
154 }
155 
156 bool SavitzkyGolayFilter::load(std::fstream &file){
157 
158  if( !file.is_open() ){
159  errorLog << "load(std::fstream &file) - The file is not open!" << std::endl;
160  return false;
161  }
162 
163  std::string word;
164 
165  //Load the header
166  file >> word;
167 
168  if( word != "GRT_SAVITZKY_GOLAY_FILTER_FILE_V1.0" ){
169  errorLog << "load(std::fstream &file) - Invalid file format!" << std::endl;
170  return false;
171  }
172 
173  //Load the number of input dimensions
174  file >> word;
175  if( word != "NumInputDimensions:" ){
176  errorLog << "load(std::fstream &file) - Failed to read NumInputDimensions header!" << std::endl;
177  return false;
178  }
179  file >> numInputDimensions;
180 
181  //Load the number of output dimensions
182  file >> word;
183  if( word != "NumOutputDimensions:" ){
184  errorLog << "load(std::fstream &file) - Failed to read NumOutputDimensions header!" << std::endl;
185  return false;
186  }
187  file >> numOutputDimensions;
188 
189  //Load the numPoints
190  file >> word;
191  if( word != "NumPoints:" ){
192  errorLog << "load(std::fstream &file) - Failed to read NumPoints header!" << std::endl;
193  return false;
194  }
195  file >> numPoints;
196 
197  //Load the NumLeftHandPoints
198  file >> word;
199  if( word != "NumLeftHandPoints:" ){
200  errorLog << "load(std::fstream &file) - Failed to read NumLeftHandPoints header!" << std::endl;
201  return false;
202  }
203  file >> numLeftHandPoints;
204 
205  //Load the NumRightHandPoints
206  file >> word;
207  if( word != "NumRightHandPoints:" ){
208  errorLog << "load(std::fstream &file) - Failed to read numRightHandPoints header!" << std::endl;
209  return false;
210  }
211  file >> numRightHandPoints;
212 
213  //Load the DerivativeOrder
214  file >> word;
215  if( word != "DerivativeOrder:" ){
216  errorLog << "load(std::fstream &file) - Failed to read DerivativeOrder header!" << std::endl;
217  return false;
218  }
219  file >> derivativeOrder;
220 
221  //Load the SmoothingPolynomialOrder
222  file >> word;
223  if( word != "SmoothingPolynomialOrder:" ){
224  errorLog << "load(std::fstream &file) - Failed to read SmoothingPolynomialOrder header!" << std::endl;
225  return false;
226  }
227  file >> smoothingPolynomialOrder;
228 
229  //Init the filter module to ensure everything is initialized correctly
230  return init(numLeftHandPoints,numRightHandPoints,derivativeOrder,smoothingPolynomialOrder,numInputDimensions);
231 }
232 
233 bool SavitzkyGolayFilter::init(UINT numLeftHandPoints,UINT numRightHandPoints,UINT derivativeOrder,UINT smoothingPolynomialOrder,UINT numDimensions){
234 
235  initialized = false;
236 
237  if( numDimensions == 0 ){
238  errorLog << "init(Float filterFactor,Float gain,UINT numDimensions) - NumDimensions must be greater than 0!" << std::endl;
239  return false;
240  }
241 
242  this->numPoints = numLeftHandPoints+numRightHandPoints+1;
243  this->numLeftHandPoints = numLeftHandPoints;
244  this->numRightHandPoints = numRightHandPoints;
245  this->derivativeOrder = derivativeOrder;
246  this->smoothingPolynomialOrder = smoothingPolynomialOrder;
247  coeff.resize(numPoints);
248  this->numInputDimensions = numDimensions;
249  this->numOutputDimensions = numDimensions;
250  yy.clear();
251  yy.resize(numDimensions,0);
252  processedData.clear();
253  processedData.resize(numDimensions,0);
254  data.resize(numPoints,VectorFloat(numDimensions,0));
255 
256  if( !calCoeff() ){
257  errorLog << "init(UINT NL,UINT NR,UINT LD,UINT M,UINT numDimensions) - Failed to compute filter coefficents!" << std::endl;
258  return false;
259  }
260 
261  initialized = true;
262 
263  return true;
264 }
265 
266 Float SavitzkyGolayFilter::filter(const Float x){
267 
268  //If the filter has not been initialised then return 0, otherwise filter x and return y
269  if( !initialized ){
270  errorLog << "filter(Float x) - The filter has not been initialized!" << std::endl;
271  return 0;
272  }
273 
274  VectorFloat y = filter(VectorFloat(1,x));
275 
276  if( y.size() > 0 ) return y[0];
277  return 0;
278 }
279 
281 
282  if( !initialized ){
283  errorLog << "filter(const VectorFloat &x) - Not Initialized!" << std::endl;
284  return VectorFloat();
285  }
286 
287  if( x.size() != numInputDimensions ){
288  errorLog << "filter(const VectorFloat &x) - The Number Of Input Dimensions (" << numInputDimensions << ") does not match the size of the input vector (" << x.size() << ")!" << std::endl;
289  return VectorFloat();
290  }
291 
292  //Add the new input data to the data buffer
293  data.push_back( x );
294 
295  //Filter the data
296  for(UINT j=0; j<x.size(); j++){
297  processedData[j] = 0;
298  for(UINT i=0; i<numPoints; i++)
299  processedData[j] += data[i][j] * coeff[i];
300  }
301 
302  return processedData;
303 }
304 
305 bool SavitzkyGolayFilter::calCoeff(){
306 
307  int np = (int)numPoints;
308  int nl = (int)numLeftHandPoints;
309  int nr = (int)numRightHandPoints;
310  int ld = (int)derivativeOrder;
311  int m = (int)smoothingPolynomialOrder;
312  int i,j,k,imj,ipj,kk,mm,pos;
313  Float fac,sum;
314  VectorFloat indx(m+1);
315  MatrixDouble a(m+1,m+1);
316  VectorFloat b(m+1);
317  VectorFloat c(np);
318 
319  for (ipj=0; ipj<=(m << 1); ipj++) {
320  sum=(ipj ? 0.0 : 1.0);
321 
322  for (k=1; k<=nr; k++) sum += pow(Float(k),Float(ipj));
323  for (k=1; k<=nl; k++) sum += pow(Float(-k),Float(ipj));
324 
325  mm = min_(ipj,2*m-ipj);
326 
327  for (imj = -mm; imj<=mm; imj+=2) a[(ipj+imj)/2][(ipj-imj)/2] = sum;
328  }
329 
330  LUDecomposition alud(a);
331  for (j=0;j<m+1;j++) b[j]=0.0;
332  b[ld]=1.0;
333  if( !alud.solve_vector(b,b) ){
334  return false;
335  }
336 
337  for (kk=0; kk<np; kk++) c[kk]=0.0;
338  for (k = -nl; k<=nr; k++) {
339  sum=b[0];
340  fac=1.0;
341 
342  for(mm=1; mm<=m; mm++)
343  sum += b[mm]*(fac *= k);
344 
345  kk=(np-k) % np;
346  c[kk]=sum;
347  }
348 
349  //Reorder coefficients and place them in coeff
350  //Reorder last=0 future = np-1
351  pos = nl;
352  for(i=0; i<np; i++){
353  coeff[i] = c[pos--];
354  if(pos==0)pos=np-1;
355  }
356  return true;
357  }
358 
359  GRT_END_NAMESPACE
360 
bool push_back(const T &value)
Float filter(const Float x)
This implements a Savitzky-Golay filter. This code is based on the Savitzky Golay filter code from Nu...
virtual bool resize(const unsigned int size)
Definition: Vector.h:133
SavitzkyGolayFilter(UINT numLeftHandPoints=10, UINT numRightHandPoints=10, UINT derivativeOrder=0, UINT smoothingPolynomialOrder=2, UINT numDimensions=1)
std::string getPreProcessingType() const
virtual bool load(std::fstream &file)
virtual bool deepCopyFrom(const PreProcessing *preProcessing)
SavitzkyGolayFilter & operator=(const SavitzkyGolayFilter &rhs)
bool copyBaseVariables(const PreProcessing *preProcessingModule)
bool setAllValues(const T &value)
virtual bool process(const VectorFloat &inputVector)
virtual bool save(std::fstream &file) const
bool resize(const unsigned int newBufferSize)