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