[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

recursiveconvolution.hxx
1 /************************************************************************/
2 /* */
3 /* Copyright 1998-2002 by Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 
37 #ifndef VIGRA_RECURSIVECONVOLUTION_HXX
38 #define VIGRA_RECURSIVECONVOLUTION_HXX
39 
40 #include <cmath>
41 #include <vector>
42 #include "utilities.hxx"
43 #include "numerictraits.hxx"
44 #include "imageiteratoradapter.hxx"
45 #include "bordertreatment.hxx"
46 #include "array_vector.hxx"
47 
48 namespace vigra {
49 
50 /********************************************************/
51 /* */
52 /* Recursive convolution functions */
53 /* */
54 /********************************************************/
55 
56 /** \addtogroup RecursiveConvolution Recursive convolution functions
57 
58  First order recursive filters and their specialization for
59  the exponential filter and its derivatives (1D and separable 2D).
60  These filters are very fast, and the speed does not depend on the
61  filter size.
62 */
63 //@{
64 
65 /********************************************************/
66 /* */
67 /* recursiveFilterLine */
68 /* */
69 /********************************************************/
70 
71 /** \brief Performs a 1-dimensional recursive convolution of the source signal.
72 
73  The function performs a causal and an anti-causal first or second order
74  recursive filtering with the given filter parameter <TT>b1</TT> and
75  border treatment <TT>border</TT> (first order filter, <TT>b2 = 0</TT>) or parameters
76  <TT>b1, b2</TT> and <TT>BORDER_TREATMENT_REFLECT</TT> (second order filter). Thus,
77  the result is always a filtering with linear phase.
78  \f[
79  \begin{array}{rcl}
80  a_{i, causal} & = & source_i + b1 * a_{i-1, causal} + b2 * a_{i-2, causal} \\
81  a_{i, anticausal} & = & source_i + b1 * a_{i+1, anticausal} + b2 * a_{i+2, anticausal} \\
82  dest_i & = & \frac{1 - b1 - b2}{1 + b1 + b2}(a_{i, causal} + a_{i, anticausal} - source_i)
83  \end{array}
84  \f]
85 
86  The signal's value_type (SrcAccessor::value_type) must be a
87  linear space over <TT>double</TT>,
88  i.e. addition of source values, multiplication with <TT>double</TT>,
89  and <TT>NumericTraits</TT> must be defined.
90 
91  <b> Declaration:</b>
92 
93  <b>First order recursive filter:</b>
94 
95  \code
96  namespace vigra {
97  template <class SrcIterator, class SrcAccessor,
98  class DestIterator, class DestAccessor>
99  void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
100  DestIterator id, DestAccessor ad,
101  double b1, BorderTreatmentMode border)
102  }
103  \endcode
104 
105  <b>Second order recursive filter:</b>
106 
107  \code
108  namespace vigra {
109  template <class SrcIterator, class SrcAccessor,
110  class DestIterator, class DestAccessor>
111  void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
112  DestIterator id, DestAccessor ad,
113  double b1, double b2)
114  }
115  \endcode
116 
117  <b> Usage:</b>
118 
119  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
120  Namespace: vigra
121 
122 
123  \code
124  vector<float> src, dest;
125  ...
126 
127  vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
128 
129 
130  vigra::recursiveFilterLine(src.begin(), src.end(), FAccessor(),
131  dest.begin(), FAccessor(),
132  0.5, BORDER_TREATMENT_REFLECT);
133  \endcode
134 
135  <b> Required Interface:</b>
136 
137  \code
138  RandomAccessIterator is, isend;
139  RandomAccessIterator id;
140 
141  SrcAccessor src_accessor;
142  DestAccessor dest_accessor;
143 
144  NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
145  double d;
146 
147  s = s + s;
148  s = d * s;
149 
150  dest_accessor.set(
151  NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
152 
153  \endcode
154 
155  <b> Preconditions:</b>
156 
157  \code
158  -1 < b < 1
159  \endcode
160 
161 */
162 doxygen_overloaded_function(template <...> void recursiveFilterLine)
163 
164 template <class SrcIterator, class SrcAccessor,
165  class DestIterator, class DestAccessor>
166 void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
167  DestIterator id, DestAccessor ad, double b, BorderTreatmentMode border)
168 {
169  int w = isend - is;
170  SrcIterator istart = is;
171 
172  int x;
173 
174  vigra_precondition(-1.0 < b && b < 1.0,
175  "recursiveFilterLine(): -1 < factor < 1 required.\n");
176 
177  // trivial case: b == 0.0 is an identity filter => simply copy the data and return
178  if(b == 0.0)
179  {
180  for(; is != isend; ++is, ++id)
181  {
182  ad.set(as(is), id);
183  }
184  return;
185  }
186 
187  double eps = 0.00001;
188  int kernelw = std::min(w-1, (int)(VIGRA_CSTD::log(eps)/VIGRA_CSTD::log(VIGRA_CSTD::fabs(b))));
189 
190  typedef typename
191  NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
192  typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
193  typedef typename DestTraits::RealPromote RealPromote;
194 
195  // store result of causal filtering
196  std::vector<TempType> vline(w);
197  typename std::vector<TempType>::iterator line = vline.begin();
198 
199  double norm = (1.0 - b) / (1.0 + b);
200 
201  TempType old;
202 
203  if(border == BORDER_TREATMENT_REPEAT ||
204  border == BORDER_TREATMENT_AVOID)
205  {
206  old = TempType((1.0 / (1.0 - b)) * as(is));
207  }
208  else if(border == BORDER_TREATMENT_REFLECT)
209  {
210  is += kernelw;
211  old = TempType((1.0 / (1.0 - b)) * as(is));
212  for(x = 0; x < kernelw; ++x, --is)
213  old = TempType(as(is) + b * old);
214  }
215  else if(border == BORDER_TREATMENT_WRAP)
216  {
217  is = isend - kernelw;
218  old = TempType((1.0 / (1.0 - b)) * as(is));
219  for(x = 0; x < kernelw; ++x, ++is)
220  old = TempType(as(is) + b * old);
221  }
222  else if(border == BORDER_TREATMENT_CLIP ||
223  border == BORDER_TREATMENT_ZEROPAD)
224  {
225  old = NumericTraits<TempType>::zero();
226  }
227  else
228  {
229  vigra_fail("recursiveFilterLine(): Unknown border treatment mode.\n");
230  old = NumericTraits<TempType>::zero(); // fix a stupid warning
231  }
232 
233  // left side of filter
234  for(x=0, is = istart; x < w; ++x, ++is)
235  {
236  old = TempType(as(is) + b * old);
237  line[x] = old;
238  }
239 
240  // right side of the filter
241  if(border == BORDER_TREATMENT_REPEAT ||
242  border == BORDER_TREATMENT_AVOID)
243  {
244  is = isend - 1;
245  old = TempType((1.0 / (1.0 - b)) * as(is));
246  }
247  else if(border == BORDER_TREATMENT_REFLECT)
248  {
249  old = line[w-2];
250  }
251  else if(border == BORDER_TREATMENT_WRAP)
252  {
253  is = istart + kernelw - 1;
254  old = TempType((1.0 / (1.0 - b)) * as(is));
255  for(x = 0; x < kernelw; ++x, --is)
256  old = TempType(as(is) + b * old);
257  }
258  else if(border == BORDER_TREATMENT_CLIP ||
259  border == BORDER_TREATMENT_ZEROPAD)
260  {
261  old = NumericTraits<TempType>::zero();
262  }
263 
264  is = isend - 1;
265  id += w - 1;
266  if(border == BORDER_TREATMENT_CLIP)
267  {
268  // correction factors for b
269  double bright = b;
270  double bleft = VIGRA_CSTD::pow(b, w);
271 
272  for(x=w-1; x>=0; --x, --is, --id)
273  {
274  TempType f = TempType(b * old);
275  old = as(is) + f;
276  double norm = (1.0 - b) / (1.0 + b - bleft - bright);
277  bleft /= b;
278  bright *= b;
279  ad.set(norm * (line[x] + f), id);
280  }
281  }
282  else if(border == BORDER_TREATMENT_AVOID)
283  {
284  for(x=w-1; x >= kernelw; --x, --is, --id)
285  {
286  TempType f = TempType(b * old);
287  old = as(is) + f;
288  if(x < w - kernelw)
289  ad.set(DestTraits::fromRealPromote(RealPromote(norm * (line[x] + f))), id);
290  }
291  }
292  else
293  {
294  for(x=w-1; x>=0; --x, --is, --id)
295  {
296  TempType f = TempType(b * old);
297  old = as(is) + f;
298  ad.set(DestTraits::fromRealPromote(RealPromote(norm * (line[x] + f))), id);
299  }
300  }
301 }
302 
303 /********************************************************/
304 /* */
305 /* recursiveFilterLine (2nd order) */
306 /* */
307 /********************************************************/
308 
309 template <class SrcIterator, class SrcAccessor,
310  class DestIterator, class DestAccessor>
311 void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
312  DestIterator id, DestAccessor ad, double b1, double b2)
313 {
314  int w = isend - is;
315  int x;
316 
317  typedef typename
318  NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
319  typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
320 
321  // speichert den Ergebnis der linkseitigen Filterung.
322  std::vector<TempType> vline(w+1);
323  typename std::vector<TempType>::iterator line = vline.begin();
324 
325  double norm = 1.0 - b1 - b2;
326  double norm1 = (1.0 - b1 - b2) / (1.0 + b1 + b2);
327  double norm2 = norm * norm;
328 
329 
330  // init left side of filter
331  int kernelw = std::min(w-1, std::max(8, (int)(1.0 / norm + 0.5)));
332  is += (kernelw - 2);
333  line[kernelw] = as(is);
334  line[kernelw-1] = as(is);
335  for(x = kernelw - 2; x > 0; --x, --is)
336  {
337  line[x] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[x+1] + b2 * line[x+2]);
338  }
339  line[0] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[1] + b2 * line[2]);
340  ++is;
341  line[1] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[0] + b2 * line[1]);
342  ++is;
343  for(x=2; x < w; ++x, ++is)
344  {
345  line[x] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[x-1] + b2 * line[x-2]);
346  }
347  line[w] = line[w-1];
348 
349  line[w-1] = detail::RequiresExplicitCast<TempType>::cast(norm1 * (line[w-1] + b1 * line[w-2] + b2 * line[w-3]));
350  line[w-2] = detail::RequiresExplicitCast<TempType>::cast(norm1 * (line[w-2] + b1 * line[w] + b2 * line[w-2]));
351  id += w-1;
352  ad.set(line[w-1], id);
353  --id;
354  ad.set(line[w-2], id);
355  --id;
356  for(x=w-3; x>=0; --x, --id, --is)
357  {
358  line[x] = detail::RequiresExplicitCast<TempType>::cast(norm2 * line[x] + b1 * line[x+1] + b2 * line[x+2]);
359  ad.set(line[x], id);
360  }
361 }
362 
363 /********************************************************/
364 /* */
365 /* recursiveGaussianFilterLine */
366 /* */
367 /********************************************************/
368 
369 // AUTHOR: Sebastian Boppel
370 
371 /** \brief Compute a 1-dimensional recursive approximation of Gaussian smoothing.
372 
373  The function applies a causal and an anti-causal third order recursive filter
374  which optimally approximates the Gaussian filter, as proposed in
375 
376  I. Young, L. van Vliet: <i>Recursive implementation of the Gaussian filter</i><br>
377  Signal Processing 44:139-151, 1995
378 
379  The formulas for transforming the given scale parameter <tt>sigma</tt> into the actual filter coefficients
380  are taken from Luigi Rosa's Matlab implementation.
381 
382  The signal's value_type (SrcAccessor::value_type) must be a
383  linear space over <TT>double</TT>, i.e. addition of source values, multiplication with <TT>double</TT>,
384  and <TT>NumericTraits</TT> must be defined.
385 
386  <b> Declaration:</b>
387 
388  \code
389  namespace vigra {
390  template <class SrcIterator, class SrcAccessor,
391  class DestIterator, class DestAccessor>
392  void
393  recursiveGaussianFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
394  DestIterator id, DestAccessor ad,
395  double sigma);
396  }
397  \endcode
398 
399  <b> Usage:</b>
400 
401  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
402  Namespace: vigra
403 
404 
405  \code
406  vector<float> src, dest;
407  ...
408 
409  vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
410  double sigma = 2.5;
411 
412  vigra::recursiveGaussianFilterLine(src.begin(), src.end(), FAccessor(),
413  dest.begin(), FAccessor(),
414  sigma);
415  \endcode
416 
417  <b> Required Interface:</b>
418 
419  \code
420  RandomAccessIterator is, isend;
421  RandomAccessIterator id;
422 
423  SrcAccessor src_accessor;
424  DestAccessor dest_accessor;
425 
426  NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
427  double d;
428 
429  s = s + s;
430  s = d * s;
431 
432  dest_accessor.set(
433  NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
434 
435  \endcode
436 
437  <b> Preconditions:</b>
438 
439  \code
440  0 <= sigma (absolute values are used for negative sigma)
441  \endcode
442 
443 */
444 doxygen_overloaded_function(template <...> void recursiveGaussianFilterLine)
445 
446 template <class SrcIterator, class SrcAccessor,
447  class DestIterator, class DestAccessor>
448 void
449 recursiveGaussianFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
450  DestIterator id, DestAccessor ad,
451  double sigma)
452 {
453  //coefficients taken out Luigi Rosa's implementation for Matlab
454  double q = 1.31564 * (std::sqrt(1.0 + 0.490811 * sigma*sigma) - 1.0);
455  double qq = q*q;
456  double qqq = qq*q;
457  double b0 = 1.0/(1.57825 + 2.44413*q + 1.4281*qq + 0.422205*qqq);
458  double b1 = (2.44413*q + 2.85619*qq + 1.26661*qqq)*b0;
459  double b2 = (-1.4281*qq - 1.26661*qqq)*b0;
460  double b3 = 0.422205*qqq*b0;
461  double B = 1.0 - (b1 + b2 + b3);
462 
463  int w = isend - is;
464  vigra_precondition(w >= 4,
465  "recursiveGaussianFilterLine(): line must have at least length 4.");
466 
467  int kernelw = std::min(w-4, (int)(4.0*sigma));
468 
469  int x;
470 
471  typedef typename
472  NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
473  typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
474 
475  // speichert das Ergebnis der linkseitigen Filterung.
476  std::vector<TempType> yforward(w);
477 
478  std::vector<TempType> ybackward(w, 0.0);
479 
480  // initialise the filter for reflective boundary conditions
481  for(x=kernelw; x>=0; --x)
482  {
483  ybackward[x] = detail::RequiresExplicitCast<TempType>::cast(B*as(is, x) + (b1*ybackward[x+1]+b2*ybackward[x+2]+b3*ybackward[x+3]));
484  }
485 
486  //from left to right - causal - forward
487  yforward[0] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (b1*ybackward[1]+b2*ybackward[2]+b3*ybackward[3]));
488 
489  ++is;
490  yforward[1] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (b1*yforward[0]+b2*ybackward[1]+b3*ybackward[2]));
491 
492  ++is;
493  yforward[2] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (b1*yforward[1]+b2*yforward[0]+b3*ybackward[1]));
494 
495  ++is;
496  for(x=3; x < w; ++x, ++is)
497  {
498  yforward[x] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (b1*yforward[x-1]+b2*yforward[x-2]+b3*yforward[x-3]));
499  }
500 
501  //from right to left - anticausal - backward
502  ybackward[w-1] = detail::RequiresExplicitCast<TempType>::cast(B*yforward[w-1] + (b1*yforward[w-2]+b2*yforward[w-3]+b3*yforward[w-4]));
503 
504  ybackward[w-2] = detail::RequiresExplicitCast<TempType>::cast(B*yforward[w-2] + (b1*ybackward[w-1]+b2*yforward[w-2]+b3*yforward[w-3]));
505 
506  ybackward[w-3] = detail::RequiresExplicitCast<TempType>::cast(B*yforward[w-3] + (b1*ybackward[w-2]+b2*ybackward[w-1]+b3*yforward[w-2]));
507 
508  for(x=w-4; x>=0; --x)
509  {
510  ybackward[x] = detail::RequiresExplicitCast<TempType>::cast(B*yforward[x]+(b1*ybackward[x+1]+b2*ybackward[x+2]+b3*ybackward[x+3]));
511  }
512 
513  // output
514  for(x=0; x < w; ++x, ++id)
515  {
516  ad.set(ybackward[x], id);
517  }
518 }
519 
520 
521 /********************************************************/
522 /* */
523 /* recursiveSmoothLine */
524 /* */
525 /********************************************************/
526 
527 /** \brief Convolves the image with a 1-dimensional exponential filter.
528 
529  This function calls \ref recursiveFilterLine() with <TT>b = exp(-1.0/scale)</TT>
530  and <TT>border = BORDER_TREATMENT_REPEAT</TT>. See
531  \ref recursiveFilterLine() for more documentation.
532 
533  <b> Declaration:</b>
534 
535  \code
536  namespace vigra {
537  template <class SrcIterator, class SrcAccessor,
538  class DestIterator, class DestAccessor>
539  void recursiveSmoothLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
540  DestIterator id, DestAccessor ad, double scale)
541  }
542  \endcode
543 
544  <b> Usage:</b>
545 
546  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
547  Namespace: vigra
548 
549 
550  \code
551  vector<float> src, dest;
552  ...
553 
554  vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
555 
556 
557  vigra::recursiveSmoothLine(src.begin(), src.end(), FAccessor(),
558  dest.begin(), FAccessor(), 3.0);
559  \endcode
560 
561  <b> Required Interface:</b>
562 
563  \code
564  RandomAccessIterator is, isend;
565  RandomAccessIterator id;
566 
567  SrcAccessor src_accessor;
568  DestAccessor dest_accessor;
569 
570  NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
571  double d;
572 
573  s = s + s;
574  s = d * s;
575 
576  dest_accessor.set(
577  NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
578 
579  \endcode
580 
581  <b> Preconditions:</b>
582 
583  \code
584  scale > 0
585  \endcode
586 
587 */
588 doxygen_overloaded_function(template <...> void recursiveSmoothLine)
589 
590 template <class SrcIterator, class SrcAccessor,
591  class DestIterator, class DestAccessor>
592 inline
593 void recursiveSmoothLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
594  DestIterator id, DestAccessor ad, double scale)
595 {
596  vigra_precondition(scale >= 0,
597  "recursiveSmoothLine(): scale must be >= 0.\n");
598 
599  double b = (scale == 0.0) ?
600  0.0 :
601  VIGRA_CSTD::exp(-1.0/scale);
602 
603  recursiveFilterLine(is, isend, as, id, ad, b, BORDER_TREATMENT_REPEAT);
604 }
605 
606 /********************************************************/
607 /* */
608 /* recursiveFirstDerivativeLine */
609 /* */
610 /********************************************************/
611 
612 /** \brief Performs a 1 dimensional recursive convolution of the source signal.
613 
614  It uses the first derivative an exponential <TT>d/dx exp(-abs(x)/scale)</TT> as
615  a kernel. The signal's value_type (SrcAccessor::value_type) must be a
616  linear space over <TT>double</TT>,
617  i.e. addition and subtraction of source values, multiplication with
618  <TT>double</TT>, and <TT>NumericTraits</TT> must be defined. Border
619  treatment is always <TT>BORDER_TREATMENT_REPEAT</TT>.
620 
621  <b> Declaration:</b>
622 
623  \code
624  namespace vigra {
625  template <class SrcIterator, class SrcAccessor,
626  class DestIterator, class DestAccessor>
627  void recursiveFirstDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
628  DestIterator id, DestAccessor ad, double scale)
629  }
630  \endcode
631 
632  <b> Usage:</b>
633 
634  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
635  Namespace: vigra
636 
637 
638  \code
639  vector<float> src, dest;
640  ...
641 
642  vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
643 
644 
645  vigra::recursiveFirstDerivativeLine(src.begin(), src.end(), FAccessor(),
646  dest.begin(), FAccessor(), 3.0);
647  \endcode
648 
649  <b> Required Interface:</b>
650 
651  \code
652  RandomAccessIterator is, isend;
653  RandomAccessIterator id;
654 
655  SrcAccessor src_accessor;
656  DestAccessor dest_accessor;
657 
658  NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
659  double d;
660 
661  s = s + s;
662  s = -s;
663  s = d * s;
664 
665  dest_accessor.set(
666  NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
667 
668  \endcode
669 
670  <b> Preconditions:</b>
671 
672  \code
673  scale > 0
674  \endcode
675 
676 */
677 doxygen_overloaded_function(template <...> void recursiveFirstDerivativeLine)
678 
679 template <class SrcIterator, class SrcAccessor,
680  class DestIterator, class DestAccessor>
681 void recursiveFirstDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
682  DestIterator id, DestAccessor ad, double scale)
683 {
684  vigra_precondition(scale > 0,
685  "recursiveFirstDerivativeLine(): scale must be > 0.\n");
686 
687  int w = isend -is;
688 
689  int x;
690 
691  typedef typename
692  NumericTraits<typename SrcAccessor::value_type>::RealPromote
693  TempType;
694  typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
695 
696  std::vector<TempType> vline(w);
697  typename std::vector<TempType>::iterator line = vline.begin();
698 
699  double b = VIGRA_CSTD::exp(-1.0/scale);
700  double norm = (1.0 - b) * (1.0 - b) / 2.0 / b;
701  TempType old = (1.0 / (1.0 - b)) * as(is);
702 
703  // left side of filter
704  for(x=0; x<w; ++x, ++is)
705  {
706  old = as(is) + b * old;
707  line[x] = -old;
708  }
709 
710  // right side of the filter
711  --is;
712  old = (1.0 / (1.0 - b)) * as(is);
713  id += w;
714  ++is;
715 
716  for(x=w-1; x>=0; --x)
717  {
718  --is;
719  --id;
720 
721  old = as(is) + b * old;
722 
723  ad.set(DestTraits::fromRealPromote(norm * (line[x] + old)), id);
724  }
725 }
726 
727 /********************************************************/
728 /* */
729 /* recursiveSecondDerivativeLine */
730 /* */
731 /********************************************************/
732 
733 /** \brief Performs a 1 dimensional recursive convolution of the source signal.
734 
735  It uses the second derivative an exponential <TT>d2/dx2 exp(-abs(x)/scale)</TT> as
736  a kernel. The signal's value_type (SrcAccessor::value_type) must be a
737  linear space over <TT>double</TT>,
738  i.e. addition and subtraction of source values, multiplication with
739  <TT>double</TT>, and <TT>NumericTraits</TT> must be defined. Border
740  treatment is always <TT>BORDER_TREATMENT_REPEAT</TT>.
741 
742  <b> Declaration:</b>
743 
744  \code
745  namespace vigra {
746  template <class SrcIterator, class SrcAccessor,
747  class DestIterator, class DestAccessor>
748  void recursiveSecondDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
749  DestIterator id, DestAccessor ad, double scale)
750  }
751  \endcode
752 
753  <b> Usage:</b>
754 
755  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
756  Namespace: vigra
757 
758 
759  \code
760  vector<float> src, dest;
761  ...
762 
763  vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
764 
765 
766  vigra::recursiveSecondDerivativeLine(src.begin(), src.end(), FAccessor(),
767  dest.begin(), FAccessor(), 3.0);
768  \endcode
769 
770  <b> Required Interface:</b>
771 
772  \code
773  RandomAccessIterator is, isend;
774  RandomAccessIterator id;
775 
776  SrcAccessor src_accessor;
777  DestAccessor dest_accessor;
778 
779  NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
780  double d;
781 
782  s = s + s;
783  s = s - s;
784  s = d * s;
785 
786  dest_accessor.set(
787  NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
788 
789  \endcode
790 
791  <b> Preconditions:</b>
792 
793  \code
794  scale > 0
795  \endcode
796 
797 */
798 doxygen_overloaded_function(template <...> void recursiveSecondDerivativeLine)
799 
800 template <class SrcIterator, class SrcAccessor,
801  class DestIterator, class DestAccessor>
802 void recursiveSecondDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
803  DestIterator id, DestAccessor ad, double scale)
804 {
805  vigra_precondition(scale > 0,
806  "recursiveSecondDerivativeLine(): scale must be > 0.\n");
807 
808  int w = isend -is;
809 
810  int x;
811 
812  typedef typename
813  NumericTraits<typename SrcAccessor::value_type>::RealPromote
814  TempType;
815  typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
816 
817  std::vector<TempType> vline(w);
818  typename std::vector<TempType>::iterator line = vline.begin();
819 
820  double b = VIGRA_CSTD::exp(-1.0/scale);
821  double a = -2.0 / (1.0 - b);
822  double norm = (1.0 - b) * (1.0 - b) * (1.0 - b) / (1.0 + b);
823  TempType old = detail::RequiresExplicitCast<TempType>::cast((1.0 / (1.0 - b)) * as(is));
824 
825  // left side of filter
826  for(x=0; x<w; ++x, ++is)
827  {
828  line[x] = old;
829  old = detail::RequiresExplicitCast<TempType>::cast(as(is) + b * old);
830  }
831 
832  // right side of the filter
833  --is;
834  old = detail::RequiresExplicitCast<TempType>::cast((1.0 / (1.0 - b)) * as(is));
835  id += w;
836  ++is;
837 
838  for(x=w-1; x>=0; --x)
839  {
840  --is;
841  --id;
842 
843  TempType f = detail::RequiresExplicitCast<TempType>::cast(old + a * as(is));
844  old = detail::RequiresExplicitCast<TempType>::cast(as(is) + b * old);
845  ad.set(DestTraits::fromRealPromote(detail::RequiresExplicitCast<TempType>::cast(norm * (line[x] + f))), id);
846  }
847 }
848 
849 /********************************************************/
850 /* */
851 /* recursiveFilterX */
852 /* */
853 /********************************************************/
854 
855 /** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) in x direction.
856 
857  It calls \ref recursiveFilterLine() for every row of the
858  image. See \ref recursiveFilterLine() for more information about
859  required interfaces and vigra_preconditions.
860 
861  <b> Declarations:</b>
862 
863  pass arguments explicitly:
864  \code
865  namespace vigra {
866  // first order filter
867  template <class SrcImageIterator, class SrcAccessor,
868  class DestImageIterator, class DestAccessor>
869  void recursiveFilterX(SrcImageIterator supperleft,
870  SrcImageIterator slowerright, SrcAccessor as,
871  DestImageIterator dupperleft, DestAccessor ad,
872  double b, BorderTreatmentMode border);
873 
874  // second order filter
875  template <class SrcImageIterator, class SrcAccessor,
876  class DestImageIterator, class DestAccessor>
877  void recursiveFilterX(SrcImageIterator supperleft,
878  SrcImageIterator slowerright, SrcAccessor as,
879  DestImageIterator dupperleft, DestAccessor ad,
880  double b1, double b2);
881  }
882  \endcode
883 
884 
885  use argument objects in conjunction with \ref ArgumentObjectFactories :
886  \code
887  namespace vigra {
888  // first order filter
889  template <class SrcImageIterator, class SrcAccessor,
890  class DestImageIterator, class DestAccessor>
891  void recursiveFilterX(
892  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
893  pair<DestImageIterator, DestAccessor> dest,
894  double b, BorderTreatmentMode border);
895 
896  // second order filter
897  template <class SrcImageIterator, class SrcAccessor,
898  class DestImageIterator, class DestAccessor>
899  void recursiveFilterX(
900  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
901  pair<DestImageIterator, DestAccessor> dest,
902  double b1, double b2);
903  }
904  \endcode
905 
906  <b> Usage:</b>
907 
908  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
909  Namespace: vigra
910 
911  \code
912  vigra::FImage src(w,h), dest(w,h);
913  ...
914 
915  vigra::recursiveSmoothX(srcImageRange(src), destImage(dest),
916  0.5, BORDER_TREATMENT_REFLECT);
917 
918  \endcode
919 
920 */
921 doxygen_overloaded_function(template <...> void recursiveFilterX)
922 
923 template <class SrcImageIterator, class SrcAccessor,
924  class DestImageIterator, class DestAccessor>
925 void recursiveFilterX(SrcImageIterator supperleft,
926  SrcImageIterator slowerright, SrcAccessor as,
927  DestImageIterator dupperleft, DestAccessor ad,
928  double b, BorderTreatmentMode border)
929 {
930  int w = slowerright.x - supperleft.x;
931  int h = slowerright.y - supperleft.y;
932 
933  int y;
934 
935  for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
936  {
937  typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
938  typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
939 
940  recursiveFilterLine(rs, rs+w, as,
941  rd, ad,
942  b, border);
943  }
944 }
945 
946 template <class SrcImageIterator, class SrcAccessor,
947  class DestImageIterator, class DestAccessor>
948 inline void recursiveFilterX(
949  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
950  pair<DestImageIterator, DestAccessor> dest,
951  double b, BorderTreatmentMode border)
952 {
953  recursiveFilterX(src.first, src.second, src.third,
954  dest.first, dest.second, b, border);
955 }
956 
957 /********************************************************/
958 /* */
959 /* recursiveFilterX (2nd order) */
960 /* */
961 /********************************************************/
962 
963 template <class SrcImageIterator, class SrcAccessor,
964  class DestImageIterator, class DestAccessor>
965 void recursiveFilterX(SrcImageIterator supperleft,
966  SrcImageIterator slowerright, SrcAccessor as,
967  DestImageIterator dupperleft, DestAccessor ad,
968  double b1, double b2)
969 {
970  int w = slowerright.x - supperleft.x;
971  int h = slowerright.y - supperleft.y;
972 
973  int y;
974 
975  for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
976  {
977  typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
978  typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
979 
980  recursiveFilterLine(rs, rs+w, as,
981  rd, ad,
982  b1, b2);
983  }
984 }
985 
986 template <class SrcImageIterator, class SrcAccessor,
987  class DestImageIterator, class DestAccessor>
988 inline void recursiveFilterX(
989  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
990  pair<DestImageIterator, DestAccessor> dest,
991  double b1, double b2)
992 {
993  recursiveFilterX(src.first, src.second, src.third,
994  dest.first, dest.second, b1, b2);
995 }
996 
997 
998 
999 /********************************************************/
1000 /* */
1001 /* recursiveGaussianFilterX */
1002 /* */
1003 /********************************************************/
1004 
1005 // AUTHOR: Sebastian Boppel
1006 
1007 /** \brief Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
1008 
1009  It calls \ref recursiveGaussianFilterLine() for every column of the
1010  image. See \ref recursiveGaussianFilterLine() for more information about
1011  required interfaces and vigra_preconditions.
1012 
1013  <b> Declarations:</b>
1014 
1015  pass arguments explicitly:
1016  \code
1017  namespace vigra {
1018  template <class SrcImageIterator, class SrcAccessor,
1019  class DestImageIterator, class DestAccessor>
1020  void
1021  recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
1022  DestImageIterator dupperleft, DestAccessor ad,
1023  double sigma);
1024  }
1025  \endcode
1026 
1027 
1028  use argument objects in conjunction with \ref ArgumentObjectFactories :
1029  \code
1030  namespace vigra {
1031  template <class SrcImageIterator, class SrcAccessor,
1032  class DestImageIterator, class DestAccessor>
1033  void
1034  recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1035  pair<DestImageIterator, DestAccessor> dest,
1036  double sigma);
1037  }
1038  \endcode
1039 
1040  <b> Usage:</b>
1041 
1042  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1043  Namespace: vigra
1044 
1045  \code
1046  vigra::FImage src(w,h), dest(w,h);
1047  ...
1048 
1049  vigra::recursiveGaussianFilterX(srcImageRange(src), destImage(dest), 3.0);
1050 
1051  \endcode
1052 
1053 */
1054 doxygen_overloaded_function(template <...> void recursiveGaussianFilterX)
1055 
1056 template <class SrcImageIterator, class SrcAccessor,
1057  class DestImageIterator, class DestAccessor>
1058 void
1059 recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
1060  DestImageIterator dupperleft, DestAccessor ad,
1061  double sigma)
1062 {
1063  int w = slowerright.x - supperleft.x;
1064  int h = slowerright.y - supperleft.y;
1065 
1066  int y;
1067 
1068  for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
1069  {
1070  typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
1071  typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
1072 
1073  recursiveGaussianFilterLine(rs, rs+w, as,
1074  rd, ad,
1075  sigma);
1076  }
1077 }
1078 
1079 template <class SrcImageIterator, class SrcAccessor,
1080  class DestImageIterator, class DestAccessor>
1081 inline void
1082 recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1083  pair<DestImageIterator, DestAccessor> dest,
1084  double sigma)
1085 {
1086  recursiveGaussianFilterX(src.first, src.second, src.third,
1087  dest.first, dest.second, sigma);
1088 }
1089 
1090 
1091 /********************************************************/
1092 /* */
1093 /* recursiveSmoothX */
1094 /* */
1095 /********************************************************/
1096 
1097 /** \brief Performs 1 dimensional recursive smoothing in x direction.
1098 
1099  It calls \ref recursiveSmoothLine() for every row of the
1100  image. See \ref recursiveSmoothLine() for more information about
1101  required interfaces and vigra_preconditions.
1102 
1103  <b> Declarations:</b>
1104 
1105  pass arguments explicitly:
1106  \code
1107  namespace vigra {
1108  template <class SrcImageIterator, class SrcAccessor,
1109  class DestImageIterator, class DestAccessor>
1110  void recursiveSmoothX(SrcImageIterator supperleft,
1111  SrcImageIterator slowerright, SrcAccessor as,
1112  DestImageIterator dupperleft, DestAccessor ad,
1113  double scale)
1114  }
1115  \endcode
1116 
1117 
1118  use argument objects in conjunction with \ref ArgumentObjectFactories :
1119  \code
1120  namespace vigra {
1121  template <class SrcImageIterator, class SrcAccessor,
1122  class DestImageIterator, class DestAccessor>
1123  void recursiveSmoothX(
1124  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1125  pair<DestImageIterator, DestAccessor> dest,
1126  double scale)
1127  }
1128  \endcode
1129 
1130  <b> Usage:</b>
1131 
1132  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1133  Namespace: vigra
1134 
1135  \code
1136  vigra::FImage src(w,h), dest(w,h);
1137  ...
1138 
1139  vigra::recursiveSmoothX(srcImageRange(src), destImage(dest), 3.0);
1140 
1141  \endcode
1142 
1143 */
1144 doxygen_overloaded_function(template <...> void recursiveSmoothX)
1145 
1146 template <class SrcImageIterator, class SrcAccessor,
1147  class DestImageIterator, class DestAccessor>
1148 void recursiveSmoothX(SrcImageIterator supperleft,
1149  SrcImageIterator slowerright, SrcAccessor as,
1150  DestImageIterator dupperleft, DestAccessor ad,
1151  double scale)
1152 {
1153  int w = slowerright.x - supperleft.x;
1154  int h = slowerright.y - supperleft.y;
1155 
1156  int y;
1157 
1158  for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
1159  {
1160  typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
1161  typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
1162 
1163  recursiveSmoothLine(rs, rs+w, as,
1164  rd, ad,
1165  scale);
1166  }
1167 }
1168 
1169 template <class SrcImageIterator, class SrcAccessor,
1170  class DestImageIterator, class DestAccessor>
1171 inline void recursiveSmoothX(
1172  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1173  pair<DestImageIterator, DestAccessor> dest,
1174  double scale)
1175 {
1176  recursiveSmoothX(src.first, src.second, src.third,
1177  dest. first, dest.second, scale);
1178 }
1179 
1180 /********************************************************/
1181 /* */
1182 /* recursiveFilterY */
1183 /* */
1184 /********************************************************/
1185 
1186 /** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) in y direction.
1187 
1188  It calls \ref recursiveFilterLine() for every column of the
1189  image. See \ref recursiveFilterLine() for more information about
1190  required interfaces and vigra_preconditions.
1191 
1192  <b> Declarations:</b>
1193 
1194  pass arguments explicitly:
1195  \code
1196  namespace vigra {
1197  // first order filter
1198  template <class SrcImageIterator, class SrcAccessor,
1199  class DestImageIterator, class DestAccessor>
1200  void recursiveFilterY(SrcImageIterator supperleft,
1201  SrcImageIterator slowerright, SrcAccessor as,
1202  DestImageIterator dupperleft, DestAccessor ad,
1203  double b, BorderTreatmentMode border);
1204 
1205  // second order filter
1206  template <class SrcImageIterator, class SrcAccessor,
1207  class DestImageIterator, class DestAccessor>
1208  void recursiveFilterY(SrcImageIterator supperleft,
1209  SrcImageIterator slowerright, SrcAccessor as,
1210  DestImageIterator dupperleft, DestAccessor ad,
1211  double b1, double b2);
1212  }
1213  \endcode
1214 
1215 
1216  use argument objects in conjunction with \ref ArgumentObjectFactories :
1217  \code
1218  namespace vigra {
1219  // first order filter
1220  template <class SrcImageIterator, class SrcAccessor,
1221  class DestImageIterator, class DestAccessor>
1222  void recursiveFilterY(
1223  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1224  pair<DestImageIterator, DestAccessor> dest,
1225  double b, BorderTreatmentMode border);
1226 
1227  // second order filter
1228  template <class SrcImageIterator, class SrcAccessor,
1229  class DestImageIterator, class DestAccessor>
1230  void recursiveFilterY(
1231  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1232  pair<DestImageIterator, DestAccessor> dest,
1233  double b1, double b2);
1234  }
1235  \endcode
1236 
1237  <b> Usage:</b>
1238 
1239  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1240  Namespace: vigra
1241 
1242  \code
1243  vigra::FImage src(w,h), dest(w,h);
1244  ...
1245 
1246  vigra::recursiveFilterY(srcImageRange(src), destImage(dest), -0.6, -0.06);
1247 
1248  \endcode
1249 
1250 */
1251 doxygen_overloaded_function(template <...> void recursiveFilterY)
1252 
1253 template <class SrcImageIterator, class SrcAccessor,
1254  class DestImageIterator, class DestAccessor>
1255 void recursiveFilterY(SrcImageIterator supperleft,
1256  SrcImageIterator slowerright, SrcAccessor as,
1257  DestImageIterator dupperleft, DestAccessor ad,
1258  double b, BorderTreatmentMode border)
1259 {
1260  int w = slowerright.x - supperleft.x;
1261  int h = slowerright.y - supperleft.y;
1262 
1263  int x;
1264 
1265  for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1266  {
1267  typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1268  typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1269 
1270  recursiveFilterLine(cs, cs+h, as,
1271  cd, ad,
1272  b, border);
1273  }
1274 }
1275 
1276 template <class SrcImageIterator, class SrcAccessor,
1277  class DestImageIterator, class DestAccessor>
1278 inline void recursiveFilterY(
1279  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1280  pair<DestImageIterator, DestAccessor> dest,
1281  double b, BorderTreatmentMode border)
1282 {
1283  recursiveFilterY(src.first, src.second, src.third,
1284  dest.first, dest.second, b, border);
1285 }
1286 
1287 /********************************************************/
1288 /* */
1289 /* recursiveFilterY (2nd order) */
1290 /* */
1291 /********************************************************/
1292 
1293 template <class SrcImageIterator, class SrcAccessor,
1294  class DestImageIterator, class DestAccessor>
1295 void recursiveFilterY(SrcImageIterator supperleft,
1296  SrcImageIterator slowerright, SrcAccessor as,
1297  DestImageIterator dupperleft, DestAccessor ad,
1298  double b1, double b2)
1299 {
1300  int w = slowerright.x - supperleft.x;
1301  int h = slowerright.y - supperleft.y;
1302 
1303  int x;
1304 
1305  for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1306  {
1307  typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1308  typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1309 
1310  recursiveFilterLine(cs, cs+h, as,
1311  cd, ad,
1312  b1, b2);
1313  }
1314 }
1315 
1316 template <class SrcImageIterator, class SrcAccessor,
1317  class DestImageIterator, class DestAccessor>
1318 inline void recursiveFilterY(
1319  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1320  pair<DestImageIterator, DestAccessor> dest,
1321  double b1, double b2)
1322 {
1323  recursiveFilterY(src.first, src.second, src.third,
1324  dest.first, dest.second, b1, b2);
1325 }
1326 
1327 
1328 /********************************************************/
1329 /* */
1330 /* recursiveGaussianFilterY */
1331 /* */
1332 /********************************************************/
1333 
1334 // AUTHOR: Sebastian Boppel
1335 
1336 /** \brief Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
1337 
1338  It calls \ref recursiveGaussianFilterLine() for every column of the
1339  image. See \ref recursiveGaussianFilterLine() for more information about
1340  required interfaces and vigra_preconditions.
1341 
1342  <b> Declarations:</b>
1343 
1344  pass arguments explicitly:
1345  \code
1346  namespace vigra {
1347  template <class SrcImageIterator, class SrcAccessor,
1348  class DestImageIterator, class DestAccessor>
1349  void
1350  recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
1351  DestImageIterator dupperleft, DestAccessor ad,
1352  double sigma);
1353  }
1354  \endcode
1355 
1356 
1357  use argument objects in conjunction with \ref ArgumentObjectFactories :
1358  \code
1359  namespace vigra {
1360  template <class SrcImageIterator, class SrcAccessor,
1361  class DestImageIterator, class DestAccessor>
1362  void
1363  recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1364  pair<DestImageIterator, DestAccessor> dest,
1365  double sigma);
1366  }
1367  \endcode
1368 
1369  <b> Usage:</b>
1370 
1371  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1372  Namespace: vigra
1373 
1374  \code
1375  vigra::FImage src(w,h), dest(w,h);
1376  ...
1377 
1378  vigra::recursiveGaussianFilterY(srcImageRange(src), destImage(dest), 3.0);
1379 
1380  \endcode
1381 
1382 */
1383 doxygen_overloaded_function(template <...> void recursiveGaussianFilterY)
1384 
1385 template <class SrcImageIterator, class SrcAccessor,
1386  class DestImageIterator, class DestAccessor>
1387 void
1388 recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
1389  DestImageIterator dupperleft, DestAccessor ad,
1390  double sigma)
1391 {
1392  int w = slowerright.x - supperleft.x;
1393  int h = slowerright.y - supperleft.y;
1394 
1395  int x;
1396 
1397  for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1398  {
1399  typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1400  typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1401 
1402  recursiveGaussianFilterLine(cs, cs+h, as,
1403  cd, ad,
1404  sigma);
1405  }
1406 }
1407 
1408 template <class SrcImageIterator, class SrcAccessor,
1409  class DestImageIterator, class DestAccessor>
1410 inline void
1411 recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1412  pair<DestImageIterator, DestAccessor> dest,
1413  double sigma)
1414 {
1415  recursiveGaussianFilterY(src.first, src.second, src.third,
1416  dest.first, dest.second, sigma);
1417 }
1418 
1419 
1420 /********************************************************/
1421 /* */
1422 /* recursiveSmoothY */
1423 /* */
1424 /********************************************************/
1425 
1426 /** \brief Performs 1 dimensional recursive smoothing in y direction.
1427 
1428  It calls \ref recursiveSmoothLine() for every column of the
1429  image. See \ref recursiveSmoothLine() for more information about
1430  required interfaces and vigra_preconditions.
1431 
1432  <b> Declarations:</b>
1433 
1434  pass arguments explicitly:
1435  \code
1436  namespace vigra {
1437  template <class SrcImageIterator, class SrcAccessor,
1438  class DestImageIterator, class DestAccessor>
1439  void recursiveSmoothY(SrcImageIterator supperleft,
1440  SrcImageIterator slowerright, SrcAccessor as,
1441  DestImageIterator dupperleft, DestAccessor ad,
1442  double scale)
1443  }
1444  \endcode
1445 
1446 
1447  use argument objects in conjunction with \ref ArgumentObjectFactories :
1448  \code
1449  namespace vigra {
1450  template <class SrcImageIterator, class SrcAccessor,
1451  class DestImageIterator, class DestAccessor>
1452  void recursiveSmoothY(
1453  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1454  pair<DestImageIterator, DestAccessor> dest,
1455  double scale)
1456  }
1457  \endcode
1458 
1459  <b> Usage:</b>
1460 
1461  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1462  Namespace: vigra
1463 
1464  \code
1465  vigra::FImage src(w,h), dest(w,h);
1466  ...
1467 
1468  vigra::recursiveSmoothY(srcImageRange(src), destImage(dest), 3.0);
1469 
1470  \endcode
1471 
1472 */
1473 doxygen_overloaded_function(template <...> void recursiveSmoothY)
1474 
1475 template <class SrcImageIterator, class SrcAccessor,
1476  class DestImageIterator, class DestAccessor>
1477 void recursiveSmoothY(SrcImageIterator supperleft,
1478  SrcImageIterator slowerright, SrcAccessor as,
1479  DestImageIterator dupperleft, DestAccessor ad,
1480  double scale)
1481 {
1482  int w = slowerright.x - supperleft.x;
1483  int h = slowerright.y - supperleft.y;
1484 
1485  int x;
1486 
1487  for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1488  {
1489  typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1490  typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1491 
1492  recursiveSmoothLine(cs, cs+h, as,
1493  cd, ad,
1494  scale);
1495  }
1496 }
1497 
1498 template <class SrcImageIterator, class SrcAccessor,
1499  class DestImageIterator, class DestAccessor>
1500 inline void recursiveSmoothY(
1501  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1502  pair<DestImageIterator, DestAccessor> dest,
1503  double scale)
1504 {
1505  recursiveSmoothY(src.first, src.second, src.third,
1506  dest. first, dest.second, scale);
1507 }
1508 
1509 /********************************************************/
1510 /* */
1511 /* recursiveFirstDerivativeX */
1512 /* */
1513 /********************************************************/
1514 
1515 /** \brief Recursively calculates the 1 dimensional first derivative in x
1516  direction.
1517 
1518  It calls \ref recursiveFirstDerivativeLine() for every
1519  row of the image. See \ref recursiveFirstDerivativeLine() for more
1520  information about required interfaces and vigra_preconditions.
1521 
1522  <b> Declarations:</b>
1523 
1524  pass arguments explicitly:
1525  \code
1526  namespace vigra {
1527  template <class SrcImageIterator, class SrcAccessor,
1528  class DestImageIterator, class DestAccessor>
1529  void recursiveFirstDerivativeX(SrcImageIterator supperleft,
1530  SrcImageIterator slowerright, SrcAccessor as,
1531  DestImageIterator dupperleft, DestAccessor ad,
1532  double scale)
1533  }
1534  \endcode
1535 
1536 
1537  use argument objects in conjunction with \ref ArgumentObjectFactories :
1538  \code
1539  namespace vigra {
1540  template <class SrcImageIterator, class SrcAccessor,
1541  class DestImageIterator, class DestAccessor>
1542  void recursiveFirstDerivativeX(
1543  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1544  pair<DestImageIterator, DestAccessor> dest,
1545  double scale)
1546  }
1547  \endcode
1548 
1549  <b> Usage:</b>
1550 
1551  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1552  Namespace: vigra
1553 
1554  \code
1555  vigra::FImage src(w,h), dest(w,h);
1556  ...
1557 
1558  vigra::recursiveFirstDerivativeX(srcImageRange(src), destImage(dest), 3.0);
1559 
1560  \endcode
1561 
1562 */
1563 doxygen_overloaded_function(template <...> void recursiveFirstDerivativeX)
1564 
1565 template <class SrcImageIterator, class SrcAccessor,
1566  class DestImageIterator, class DestAccessor>
1567 void recursiveFirstDerivativeX(SrcImageIterator supperleft,
1568  SrcImageIterator slowerright, SrcAccessor as,
1569  DestImageIterator dupperleft, DestAccessor ad,
1570  double scale)
1571 {
1572  int w = slowerright.x - supperleft.x;
1573  int h = slowerright.y - supperleft.y;
1574 
1575  int y;
1576 
1577  for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
1578  {
1579  typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
1580  typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
1581 
1582  recursiveFirstDerivativeLine(rs, rs+w, as,
1583  rd, ad,
1584  scale);
1585  }
1586 }
1587 
1588 template <class SrcImageIterator, class SrcAccessor,
1589  class DestImageIterator, class DestAccessor>
1590 inline void recursiveFirstDerivativeX(
1591  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1592  pair<DestImageIterator, DestAccessor> dest,
1593  double scale)
1594 {
1595  recursiveFirstDerivativeX(src.first, src.second, src.third,
1596  dest. first, dest.second, scale);
1597 }
1598 
1599 /********************************************************/
1600 /* */
1601 /* recursiveFirstDerivativeY */
1602 /* */
1603 /********************************************************/
1604 
1605 /** \brief Recursively calculates the 1 dimensional first derivative in y
1606  direction.
1607 
1608  It calls \ref recursiveFirstDerivativeLine() for every
1609  column of the image. See \ref recursiveFirstDerivativeLine() for more
1610  information about required interfaces and vigra_preconditions.
1611 
1612  <b> Declarations:</b>
1613 
1614  pass arguments explicitly:
1615  \code
1616  namespace vigra {
1617  template <class SrcImageIterator, class SrcAccessor,
1618  class DestImageIterator, class DestAccessor>
1619  void recursiveFirstDerivativeY(SrcImageIterator supperleft,
1620  SrcImageIterator slowerright, SrcAccessor as,
1621  DestImageIterator dupperleft, DestAccessor ad,
1622  double scale)
1623  }
1624  \endcode
1625 
1626 
1627  use argument objects in conjunction with \ref ArgumentObjectFactories :
1628  \code
1629  namespace vigra {
1630  template <class SrcImageIterator, class SrcAccessor,
1631  class DestImageIterator, class DestAccessor>
1632  void recursiveFirstDerivativeY(
1633  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1634  pair<DestImageIterator, DestAccessor> dest,
1635  double scale)
1636  }
1637  \endcode
1638 
1639  <b> Usage:</b>
1640 
1641  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1642  Namespace: vigra
1643 
1644  \code
1645  vigra::FImage src(w,h), dest(w,h);
1646  ...
1647 
1648  vigra::recursiveFirstDerivativeY(srcImageRange(src), destImage(dest), 3.0);
1649 
1650  \endcode
1651 
1652 */
1653 doxygen_overloaded_function(template <...> void recursiveFirstDerivativeY)
1654 
1655 template <class SrcImageIterator, class SrcAccessor,
1656  class DestImageIterator, class DestAccessor>
1657 void recursiveFirstDerivativeY(SrcImageIterator supperleft,
1658  SrcImageIterator slowerright, SrcAccessor as,
1659  DestImageIterator dupperleft, DestAccessor ad,
1660  double scale)
1661 {
1662  int w = slowerright.x - supperleft.x;
1663  int h = slowerright.y - supperleft.y;
1664 
1665  int x;
1666 
1667  for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1668  {
1669  typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1670  typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1671 
1672  recursiveFirstDerivativeLine(cs, cs+h, as,
1673  cd, ad,
1674  scale);
1675  }
1676 }
1677 
1678 template <class SrcImageIterator, class SrcAccessor,
1679  class DestImageIterator, class DestAccessor>
1680 inline void recursiveFirstDerivativeY(
1681  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1682  pair<DestImageIterator, DestAccessor> dest,
1683  double scale)
1684 {
1685  recursiveFirstDerivativeY(src.first, src.second, src.third,
1686  dest. first, dest.second, scale);
1687 }
1688 
1689 /********************************************************/
1690 /* */
1691 /* recursiveSecondDerivativeX */
1692 /* */
1693 /********************************************************/
1694 
1695 /** \brief Recursively calculates the 1 dimensional second derivative in x
1696  direction.
1697 
1698  It calls \ref recursiveSecondDerivativeLine() for every
1699  row of the image. See \ref recursiveSecondDerivativeLine() for more
1700  information about required interfaces and vigra_preconditions.
1701 
1702  <b> Declarations:</b>
1703 
1704  pass arguments explicitly:
1705  \code
1706  namespace vigra {
1707  template <class SrcImageIterator, class SrcAccessor,
1708  class DestImageIterator, class DestAccessor>
1709  void recursiveSecondDerivativeX(SrcImageIterator supperleft,
1710  SrcImageIterator slowerright, SrcAccessor as,
1711  DestImageIterator dupperleft, DestAccessor ad,
1712  double scale)
1713  }
1714  \endcode
1715 
1716 
1717  use argument objects in conjunction with \ref ArgumentObjectFactories :
1718  \code
1719  namespace vigra {
1720  template <class SrcImageIterator, class SrcAccessor,
1721  class DestImageIterator, class DestAccessor>
1722  void recursiveSecondDerivativeX(
1723  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1724  pair<DestImageIterator, DestAccessor> dest,
1725  double scale)
1726  }
1727  \endcode
1728 
1729  <b> Usage:</b>
1730 
1731  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1732  Namespace: vigra
1733 
1734  \code
1735  vigra::FImage src(w,h), dest(w,h);
1736  ...
1737 
1738  vigra::recursiveSecondDerivativeX(srcImageRange(src), destImage(dest), 3.0);
1739 
1740  \endcode
1741 
1742 */
1743 doxygen_overloaded_function(template <...> void recursiveSecondDerivativeX)
1744 
1745 template <class SrcImageIterator, class SrcAccessor,
1746  class DestImageIterator, class DestAccessor>
1747 void recursiveSecondDerivativeX(SrcImageIterator supperleft,
1748  SrcImageIterator slowerright, SrcAccessor as,
1749  DestImageIterator dupperleft, DestAccessor ad,
1750  double scale)
1751 {
1752  int w = slowerright.x - supperleft.x;
1753  int h = slowerright.y - supperleft.y;
1754 
1755  int y;
1756 
1757  for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
1758  {
1759  typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
1760  typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
1761 
1762  recursiveSecondDerivativeLine(rs, rs+w, as,
1763  rd, ad,
1764  scale);
1765  }
1766 }
1767 
1768 template <class SrcImageIterator, class SrcAccessor,
1769  class DestImageIterator, class DestAccessor>
1770 inline void recursiveSecondDerivativeX(
1771  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1772  pair<DestImageIterator, DestAccessor> dest,
1773  double scale)
1774 {
1775  recursiveSecondDerivativeX(src.first, src.second, src.third,
1776  dest. first, dest.second, scale);
1777 }
1778 
1779 /********************************************************/
1780 /* */
1781 /* recursiveSecondDerivativeY */
1782 /* */
1783 /********************************************************/
1784 
1785 /** \brief Recursively calculates the 1 dimensional second derivative in y
1786  direction.
1787 
1788  It calls \ref recursiveSecondDerivativeLine() for every
1789  column of the image. See \ref recursiveSecondDerivativeLine() for more
1790  information about required interfaces and vigra_preconditions.
1791 
1792  <b> Declarations:</b>
1793 
1794  pass arguments explicitly:
1795  \code
1796  namespace vigra {
1797  template <class SrcImageIterator, class SrcAccessor,
1798  class DestImageIterator, class DestAccessor>
1799  void recursiveSecondDerivativeY(SrcImageIterator supperleft,
1800  SrcImageIterator slowerright, SrcAccessor as,
1801  DestImageIterator dupperleft, DestAccessor ad,
1802  double scale)
1803  }
1804  \endcode
1805 
1806 
1807  use argument objects in conjunction with \ref ArgumentObjectFactories :
1808  \code
1809  namespace vigra {
1810  template <class SrcImageIterator, class SrcAccessor,
1811  class DestImageIterator, class DestAccessor>
1812  void recursiveSecondDerivativeY(
1813  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1814  pair<DestImageIterator, DestAccessor> dest,
1815  double scale)
1816  }
1817  \endcode
1818 
1819  <b> Usage:</b>
1820 
1821  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1822  Namespace: vigra
1823 
1824  \code
1825  vigra::FImage src(w,h), dest(w,h);
1826  ...
1827 
1828  vigra::recursiveSecondDerivativeY(srcImageRange(src), destImage(dest), 3.0);
1829 
1830  \endcode
1831 
1832 */
1833 doxygen_overloaded_function(template <...> void recursiveSecondDerivativeY)
1834 
1835 template <class SrcImageIterator, class SrcAccessor,
1836  class DestImageIterator, class DestAccessor>
1837 void recursiveSecondDerivativeY(SrcImageIterator supperleft,
1838  SrcImageIterator slowerright, SrcAccessor as,
1839  DestImageIterator dupperleft, DestAccessor ad,
1840  double scale)
1841 {
1842  int w = slowerright.x - supperleft.x;
1843  int h = slowerright.y - supperleft.y;
1844 
1845  int x;
1846 
1847  for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1848  {
1849  typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1850  typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1851 
1852  recursiveSecondDerivativeLine(cs, cs+h, as,
1853  cd, ad,
1854  scale);
1855  }
1856 }
1857 
1858 template <class SrcImageIterator, class SrcAccessor,
1859  class DestImageIterator, class DestAccessor>
1860 inline void recursiveSecondDerivativeY(
1861  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1862  pair<DestImageIterator, DestAccessor> dest,
1863  double scale)
1864 {
1865  recursiveSecondDerivativeY(src.first, src.second, src.third,
1866  dest. first, dest.second, scale);
1867 }
1868 
1869 
1870 //@}
1871 
1872 } // namespace vigra
1873 
1874 #endif // VIGRA_RECURSIVECONVOLUTION_HXX

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.9.0 (Tue Sep 24 2013)