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