aimstil  5.0.5
rf4.h
Go to the documentation of this file.
1 #ifndef TIL_RECURSIVE_FILTER4_H
2 #define TIL_RECURSIVE_FILTER4_H
3 
4 // includes from STL
5 #include <cassert>
6 #include <vector>
7 
8 // includes from TIL library
9 #include "til/til_common.h"
10 #include "til/RecursiveFilter.h"
11 
12 // Namespace
13 namespace til {
14 
15 
16 
17 // 4-th order recursive filtering
18 
19 // direction = +1 : forward filter
20 // direction = -1 : backward filter
21 
22 template < typename TT, int direction >
23 class RecursiveFilter<TT, direction, 4>
24 {
25 public: // typedefs
26 
28  typedef TT T;
29 
30 public: // types
31 
32  // Boundary conditions of the recursive filter
33  // Zeros : values are supposed to be zero outside
34  // Constant : boundary values are duplicated to +/- infinity
35  enum BoundaryConditions { Zero, Constant };
36 
37 public: // constuctors & destructor
38 
39  // Default constructor
40  RecursiveFilter() { m_boundaryConditions = Self::Constant; }
41 
42 public: // set & get
43 
44  // get filter coefficient for input
45  const T* getMI() const { return m_mi; }
46  // get filter coefficient for output
47  const T* getMO() const { return m_mo; }
48 
49  // Set filter coefficients
50  // The filter is output = sum(mik*inputk) - sum(mok*outputk)
51 
52  void setFilter(T mi0, T mi1, T mi2, T mi3, T mo0, T mo1, T mo2, T mo3)
53  {
54  m_mi[0] = mi0;
55  m_mi[1] = mi1;
56  m_mi[2] = mi2;
57  m_mi[3] = mi3;
58  m_mo[0] = mo0;
59  m_mo[1] = mo1;
60  m_mo[2] = mo2;
61  m_mo[3] = mo3;
62  }
63 
64  // Set filter coefficients from impulse response formula
65  // Filter formula:
66  // ( a0 * cos(w0 * x/sigma) + a1 * cos(w0 * x/sigma) * exp( - b0 * x/sigma) ) +
67  // ( c0 * cos(w1 * x/sigma) + c1 * cos(w1 * x/sigma) * exp( - b1 * x/sigma) )
68 
69  void setFilterFromFormula(T a0, T a1, T c0, T c1, T w0, T w1, T b0, T b1, T sigma);
70 
71  // Set boundary conditions
72 
73  void setBoundaryConditions(BoundaryConditions bc) { m_boundaryConditions = bc; }
74 
75 
76  // TODO: To be exported outside class
77  void normalize(T norm)
78  {
79  norm = 2.0*norm - m_mi[0];
80 
81  m_mi[0] /= norm;
82  m_mi[1] /= norm;
83  m_mi[2] /= norm;
84  m_mi[3] /= norm;
85  }
86 
87 
88 public: // methods
89 
90  // Apply filter to 'in' (of given length), result outputed in 'out'
91  // out has to be allocated with the same size as in
92  // NB: out and in cannot point to the same data
93  void apply(const std::vector<T> &in, std::vector<T> &out) const;
94 
95 
96 private: // methods
97 
98  // Multiplicative coefficient used for 'Constant' boundary condition
99 
100  T borderFactor() const { return
101  ( m_mi[0] + m_mi[1] + m_mi[2] + m_mi[3]) /
102  (1 + m_mo[0] + m_mo[1] + m_mo[2] + m_mo[3]); }
103 
104  T apply(T in0, T in1, T in2, T in3, T out0, T out1, T out2, T out3) const
105  {
106  return (
107  m_mi[0] * in0 +
108  m_mi[1] * in1 +
109  m_mi[2] * in2 +
110  m_mi[3] * in3 -
111 
112  m_mo[0] * out0 -
113  m_mo[1] * out1 -
114  m_mo[2] * out2 -
115  m_mo[3] * out3);
116  }
117 
118 private: // data
119 
120  // Boundary conditions
121  BoundaryConditions m_boundaryConditions;
122 
123  // 4 multiplicative coefficients of the input
124  T m_mi[4];
125 
126  // 4 multiplicative coefficients of the output
127  T m_mo[4];
128 };
129 
130 
131 
132 
133 
134 template < typename TT, int direction >
135 void RecursiveFilter<TT,direction,4>::apply(const std::vector<T> &in, std::vector<T> &out) const
136 {
137  typename std::vector<T>::const_iterator pIn;
138  typename std::vector<T>::iterator pOut;
139 
140  size_t length = in.size();
141  assert(in.size() == out.size());
142 
143  if (direction == 1)
144  {
145  pIn = in.begin();
146  pOut = out.begin();
147  }
148  else if (direction == -1)
149  {
150  pIn = in.begin() + length - 1;
151  pOut = out.begin() + length - 1;
152  }
153 
154  size_t count = length;
155 
156  T x0, x1 = 0, x2 = 0, x3 = 0; // useless initializations -- done just to avoid a warning.
157  T y0 = 0, y1 = 0, y2 = 0, y3 = 0; // useless initializations -- done just to avoid a warning.
158 
159  // Filter initialization on borders
160 
161  switch (m_boundaryConditions)
162  {
163  case Zero:
164  x1 = x2 = x3 = 0;
165  y0 = y1 = y2 = y3 = 0;
166  break;
167  case Constant:
168  x1 = x2 = x3 = *pIn;
169  y0 = y1 = y2 = y3 = *pIn * this->borderFactor();
170  }
171 
172  for(;;)
173  {
174  x0 = *pIn;
175  *pOut += y3 = this->apply(x0, x1, x2, x3, y0, y1, y2, y3);
176  if (--count == 0) break;
177  pOut += direction;
178  pIn += direction;
179 
180  x3 = *pIn;
181  *pOut += y2 = this->apply(x3, x0, x1, x2, y3, y0, y1, y2);
182  if (--count == 0) break;
183  pOut += direction;
184  pIn += direction;
185 
186  x2 = *pIn;
187  *pOut += y1 = this->apply(x2, x3, x0, x1, y2, y3, y0, y1);
188  if (--count == 0) break;
189  pOut += direction;
190  pIn += direction;
191 
192  x1 = *pIn;
193  *pOut += y0 = this->apply(x1, x2, x3, x0, y1, y2, y3, y0);
194  if (--count == 0) break;
195  pOut += direction;
196  pIn += direction;
197  }
198 }
199 
200 template < typename TT, int direction >
201 void RecursiveFilter<TT,direction,4>::setFilterFromFormula(T a0, T a1, T c0, T c1, T w0, T w1, T b0, T b1, T sigma)
202 {
203 
204  // Standard shortcuts variables
205 
206  T cw0 = cos(w0/sigma);
207  T cw1 = cos(w1/sigma);
208  T sw0 = sin(w0/sigma);
209  T sw1 = sin(w1/sigma);
210 
211  T eb0 = exp(-b0/sigma);
212  T eb1 = exp(-b1/sigma);
213  T e2b0 = exp(-2.0*b0/sigma);
214  T e2b1 = exp(-2.0*b1/sigma);
215  T eb0b1 = exp(-(b0+b1)/sigma);
216  T e2b0b1 = exp(-(2.0*b0+b1)/sigma);
217  T eb02b1 = exp(-(b0+2.0*b1)/sigma);
218 
219 
220  // Deduce iterative coefficients from previous filter
221 
222  // coefficient for input
223 
224  m_mi[0] = a0 + c0;
225  m_mi[1] =
226  eb1 * (sw1 * c1 -
227  cw1 * (c0 + 2*a0)) +
228  eb0 * (sw0 * a1 -
229  cw0 * (a0 + 2*c0));
230  m_mi[2] =
231  2.0 * eb0b1 * ((a0+c0)*cw0*cw1 - a1*sw0*cw1 - c1*sw1*cw0)
232  + c0 * e2b0 + a0 * e2b1;
233  m_mi[3] = e2b0b1 * (c1*sw1 - c0*cw1) + eb02b1 * (a1*sw0 - a0*cw0);
234 
235 
236  // coefficient for output
237 
238  m_mo[0] = -2.0*(eb1*cw1 + eb0*cw0);
239  m_mo[1] = 4*cw1*cw0*eb0b1 + e2b0 + e2b1;
240  m_mo[2] = -2.0*(cw0*eb02b1 + cw1*e2b0b1);
241  m_mo[3] = exp(-2.0*(b0+b1)/sigma);
242 }
243 
244 
245 
246 
247 
248 // 4th order recursive filter
249 
250  /*
251 template < typename T >
252 class RF4
253 {
254 public: // constuctors & destructor
255 
256  RF4() {}
257 
258 public: // set & get
259 
260  // get forward filter coefficient for input
261  const T* getMIF() const { return m_mif; }
262  // get forward filter coefficient for output
263  const T* getMOF() const { return m_mof; }
264  // get backward filter coefficient for input
265  const T* getMIB() const { return m_mib; }
266  // get backward filter coefficient for input
267  const T* getMOB() const { return m_mob; }
268 
269  // Set filter coefficients
270 
271  void setForwardFilter(T mi0, T mi1, T mi2, T mi3,
272  T mo0, T mo1, T mo2, T mo3)
273  { this->setFilter(mi0, mi1, mi2, mi3, mo0, mo1, mo2, mo3, m_mif, m_mof); }
274 
275  void setBackwardFilter(T mi0, T mi1, T mi2, T mi3,
276  T mo0, T mo1, T mo2, T mo3)
277  { this->setFilter(mi0, mi1, mi2, mi3, mo0, mo1, mo2, mo3, m_mib, m_mob); }
278 
279 
280  // Set filter coefficients from impulse response formula
281 
282  // Filter formula:
283  // ( a0 * cos(w0 * x/sigma) + a1 * cos(w0 * x/sigma) * exp( - b0 * x/sigma) ) +
284  // ( c0 * cos(w1 * x/sigma) + c1 * cos(w1 * x/sigma) * exp( - b1 * x/sigma) )
285 
286  void setForwardFormula(T a0, T a1, T c0, T c1, T w0, T w1, T b0, T b1, T sigma)
287  {
288  this->formula2filter(a0, a1, c0, c1, w0, w1, b0, b1, sigma, m_mif, m_mof);
289  }
290 
291  void setBackwardFormula(T a0, T a1, T c0, T c1, T w0, T w1, T b0, T b1, T sigma)
292  {
293  this->formula2filter(a0, a1, c0, c1, w0, w1, b0, b1, sigma, m_mib, m_mob);
294  }
295 
296 
297 public: // methods
298 
299  // Apply filter to 'in' (of given length), result outputed in 'out'
300  // out has to be allocated with the same size as in
301  void apply(const T *in, T *out, int length) const;
302 
303 
304  // Normalize filter
305  // TODO: This is probably to be exported outside class
306  void normalize(T norm)
307  {
308  this->normalize(norm, m_mif);
309  this->normalize(norm, m_mib);
310  }
311 
312 private: // methods
313 
314  // Multiplicative coefficient used for RF initialization
315 
316  T borderFactorForward() const { return borderFactor(m_mif, m_mof); }
317  T borderFactorBackward() const { return borderFactor(m_mib, m_mob); }
318  T borderFactor(const T mi[4], const T mo[4]) const { return (mi[0]+mi[1]+mi[2]+mi[3])/(1+mo[0]+mo[1]+mo[2]+mo[3]); }
319 
320  T applyForward(T in0, T in1, T in2, T in3,
321  T out0, T out1, T out2, T out3) const
322  {
323  return (
324  m_mif[0] * in0 +
325  m_mif[1] * in1 +
326  m_mif[2] * in2 +
327  m_mif[3] * in3 -
328 
329  m_mof[0] * out0 -
330  m_mof[1] * out1 -
331  m_mof[2] * out2 -
332  m_mof[3] * out3);
333  }
334 
335  T applyBackward(T in0, T in1, T in2, T in3,
336  T out0, T out1, T out2, T out3) const
337  {
338  return (
339  m_mib[0] * in0 +
340  m_mib[1] * in1 +
341  m_mib[2] * in2 +
342  m_mib[3] * in3 -
343 
344  m_mob[0] * out0 -
345  m_mob[1] * out1 -
346  m_mob[2] * out2 -
347  m_mob[3] * out3);
348  }
349 
350 
351  void normalize(T norm, T mi[4])
352  {
353  norm = 2.0*norm - mi[0];
354 
355  mi[0] /= norm;
356  mi[1] /= norm;
357  mi[2] /= norm;
358  mi[3] /= norm;
359  }
360 
361  void setFilter(T mi0, T mi1, T mi2, T mi3, T mo0, T mo1, T mo2, T mo3, T mi[4], T mo[4])
362  {
363  mi[0] = mi0;
364  mi[1] = mi1;
365  mi[2] = mi2;
366  mi[3] = mi3;
367  mo[0] = mo0;
368  mo[1] = mo1;
369  mo[2] = mo2;
370  mo[3] = mo3;
371  }
372 
373  void formula2filter(T a0, T a1, T c0, T c1, T w0, T w1, T b0, T b1, T sigma, T mi[4], T mo[4])
374  {
375  //std::cout << "FORMULA2FILTER" << std::endl;
376  //std::cout << "ABC " << a0 <<" "<< a1 <<" "<< c0 <<" "<< c1 <<" "<< w0 <<" "<< w1 <<" "<< b0 <<" "<< b1 << std::endl;
377 
378  // Standard shortcuts variables
379 
380  T cw0 = cos(w0/sigma);
381  T cw1 = cos(w1/sigma);
382  T sw0 = sin(w0/sigma);
383  T sw1 = sin(w1/sigma);
384 
385  T eb0 = exp(-b0/sigma);
386  T eb1 = exp(-b1/sigma);
387  T e2b0 = exp(-2.0*b0/sigma);
388  T e2b1 = exp(-2.0*b1/sigma);
389  T eb0b1 = exp(-(b0+b1)/sigma);
390  T e2b0b1 = exp(-(2.0*b0+b1)/sigma);
391  T eb02b1 = exp(-(b0+2.0*b1)/sigma);
392 
393 
394  //std::cout << "CW " << cw0 <<" "<< cw1 <<" "<< sw0 <<" "<< sw1 <<" "<< eb0 <<" "<< eb1 <<" "<< e2b0 <<" "<< e2b1 <<" "<< eb0b1 <<" "<< e2b0b1 <<" "<< eb02b1 << std::endl;
395 
396  // Deduce iterative coefficients from previous filter
397 
398  // coefficient for input
399 
400  mi[0] = a0 + c0;
401  mi[1] =
402  eb1 * (sw1 * c1 -
403  cw1 * (c0 + 2*a0)) +
404  eb0 * (sw0 * a1 -
405  cw0 * (a0 + 2*c0));
406  mi[2] =
407  2.0 * eb0b1 * ((a0+c0)*cw0*cw1 - a1*sw0*cw1 - c1*sw1*cw0)
408  + c0 * e2b0 + a0 * e2b1;
409  mi[3] = e2b0b1 * (c1*sw1 - c0*cw1) + eb02b1 * (a1*sw0 - a0*cw0);
410 
411 
412  // coefficient for output
413 
414  mo[0] = -2.0*(eb1*cw1 + eb0*cw0);
415  mo[1] = 4*cw1*cw0*eb0b1 + e2b0 + e2b1;
416  mo[2] = -2.0*(cw0*eb02b1 + cw1*e2b0b1);
417  mo[3] = exp(-2.0*(b0+b1)/sigma);
418 
419 
420  //std::cout << mi[0] <<" "<< mi[1] <<" "<< mi[2] <<" "<< mi[3] << std::endl;
421  //std::cout << mo[0] <<" "<< mo[1] <<" "<< mo[2] <<" "<< mo[3] << std::endl;
422 
423  }
424 
425 
426  // Pb: the value at zero is computed two times, once forward, once
427  // backward. So it has to be removed.
428  // Theoretically this value is m_mif[0] = m_mib[0]
429  // But this equality may not hold (this is the case for
430  // Gaussian 1st derivative for example).
431  // So the mean is taken here.
432 
433  T bias() const { return (m_mif[0] + m_mib[0]) / 2.0; }
434 
435 
436 
437 private: // data
438 
439  // FORWARDS coefficients
440 
441  // 4 multiplicative coefficients of the input
442  T m_mif[4];
443 
444  // 4 multiplicative coefficients of the output
445  T m_mof[4];
446 
447 
448  // BACKWARDS coefficients
449 
450  // 4 multiplicative coefficients of the input
451  T m_mib[4];
452 
453  // 4 multiplicative coefficients of the output
454  T m_mob[4];
455 
456 
457 };
458 
459 
460 
461 
462 
463 template < typename T >
464 void RF4<T>::apply(const T *in, T *out, int nSeq) const
465 {
466 
467  const T *pIn = in;
468  T *pOut = out;
469 
470  // Initialization of output
471 
472  for (int i = 0; i < nSeq; ++i)
473  {
474  out[i] = - in[i] * this->bias();
475  }
476 
477  int count = nSeq;
478 
479  T x0, x1, x2, x3;
480  T y0, y1, y2, y3;
481 
482  // Filter initialization on borders
483 
484  x1 = x2 = x3 = *pIn;
485  y0 = y1 = y2 = y3 = *pIn * this->borderFactorForward();
486 
487  for(;;)
488  {
489  x0 = *pIn;
490  (*pOut) += y3 = this->applyForward(x0, x1, x2, x3, y0, y1, y2, y3);
491  if (--count == 0) break;
492  ++pOut;
493  ++pIn;
494 
495  x3 = *pIn;
496  (*pOut) += y2 = this->applyForward(x3, x0, x1, x2, y3, y0, y1, y2);
497  if (--count == 0) break;
498  ++pOut;
499  ++pIn;
500 
501  x2 = *pIn;
502  (*pOut) += y1 = this->applyForward(x2, x3, x0, x1, y2, y3, y0, y1);
503  if (--count == 0) break;
504  ++pOut;
505  ++pIn;
506 
507  x1 = *pIn;
508  (*pOut) += y0 = this->applyForward(x1, x2, x3, x0, y1, y2, y3, y0);
509  if (--count == 0) break;
510  ++pOut;
511  ++pIn;
512  }
513 
514 
515  pIn = in + nSeq - 1;
516  pOut = out + nSeq - 1;
517 
518  x1 = x2 = x3 = *pIn;
519  y0 = y1 = y2 = y3 = *pIn * this->borderFactorBackward();
520 
521  count = nSeq;
522 
523  for(;;)
524  {
525  x0 = *pIn;
526  (*pOut) += y3 = this->applyBackward(x0, x1, x2, x3, y0, y1, y2, y3);
527  if (--count == 0) break;
528  --pOut;
529  --pIn;
530 
531  x3 = *pIn;
532  (*pOut) += y2 = this->applyBackward(x3, x0, x1, x2, y3, y0, y1, y2);
533  if (--count == 0) break;
534  --pOut;
535  --pIn;
536 
537  x2 = *pIn;
538  (*pOut) += y1 = this->applyBackward(x2, x3, x0, x1, y2, y3, y0, y1);
539  if (--count == 0) break;
540  --pOut;
541  --pIn;
542 
543  x1 = *pIn;
544  (*pOut) += y0 = this->applyBackward(x1, x2, x3, x0, y1, y2, y3, y0);
545  if (--count == 0) break;
546  --pOut;
547  --pIn;
548  }
549 }
550 */
551 
552 
553 
554 
555 } // namespace
556 
557 
558 #endif
559 
INLINE void apply(const Affine< T1 > &a, const numeric_array< T2, 3 > &in, numeric_array< typename combine< T1, T2 >::type, 3 > &out)
INLINE double norm(const T &a, const T &b)
< Euclidean norm of 2D vector (a, b)
Belongs to package Box Do not include directly, include til/Box.h instead.
Definition: Accumulator.h:10
General macros, definitions and functions.
RecursiveFilter< TT, direction, 4 > Self
Definition: rf4.h:27
void setFilter(T mi0, T mi1, T mi2, T mi3, T mo0, T mo1, T mo2, T mo3)
Definition: rf4.h:52
void setBoundaryConditions(BoundaryConditions bc)
Definition: rf4.h:73