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

recursiveconvolution.hxx VIGRA

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 #include "multi_shape.hxx"
48 
49 namespace vigra {
50 
51 /********************************************************/
52 /* */
53 /* Recursive convolution functions */
54 /* */
55 /********************************************************/
56 
57 /** \addtogroup RecursiveConvolution Recursive convolution functions
58 
59  First order recursive filters and their specialization for
60  the exponential filter and its derivatives (1D and separable 2D).
61  These filters are very fast, and the speed does not depend on the
62  filter size.
63 */
64 //@{
65 
66 /********************************************************/
67 /* */
68 /* recursiveFilterLine */
69 /* */
70 /********************************************************/
71 
72 /** \brief Performs a 1-dimensional recursive convolution of the source signal.
73 
74  The function performs a causal and an anti-causal first or second order
75  recursive filtering with the given filter parameter <TT>b1</TT> and
76  border treatment <TT>border</TT> (first order filter, <TT>b2 = 0</TT>) or parameters
77  <TT>b1, b2</TT> and <TT>BORDER_TREATMENT_REFLECT</TT> (second order filter). Thus,
78  the result is always a filtering with linear phase.
79  \f[
80  \begin{array}{rcl}
81  a_{i, causal} & = & source_i + b1 * a_{i-1, causal} + b2 * a_{i-2, causal} \\
82  a_{i, anticausal} & = & source_i + b1 * a_{i+1, anticausal} + b2 * a_{i+2, anticausal} \\
83  dest_i & = & \frac{1 - b1 - b2}{1 + b1 + b2}(a_{i, causal} + a_{i, anticausal} - source_i)
84  \end{array}
85  \f]
86 
87  The signal's value_type (SrcAccessor::value_type) must be a
88  linear space over <TT>double</TT>,
89  i.e. addition of source values, multiplication with <TT>double</TT>,
90  and <TT>NumericTraits</TT> must be defined.
91 
92  <b> Declaration:</b>
93 
94  <b>First order recursive filter:</b>
95 
96  \code
97  namespace vigra {
98  template <class SrcIterator, class SrcAccessor,
99  class DestIterator, class DestAccessor>
100  void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
101  DestIterator id, DestAccessor ad,
102  double b1, BorderTreatmentMode border)
103  }
104  \endcode
105 
106  <b>Second order recursive filter:</b>
107 
108  \code
109  namespace vigra {
110  template <class SrcIterator, class SrcAccessor,
111  class DestIterator, class DestAccessor>
112  void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
113  DestIterator id, DestAccessor ad,
114  double b1, double b2)
115  }
116  \endcode
117 
118  <b> Usage:</b>
119 
120  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
121  Namespace: vigra
122 
123 
124  \code
125  vector<float> src, dest;
126  ...
127 
128  DefaultAccessor<vector<float>::iterator, float> FAccessor;
129 
130 
131  recursiveFilterLine(src.begin(), src.end(), FAccessor(),
132  dest.begin(), FAccessor(),
133  0.5, BORDER_TREATMENT_REFLECT);
134  \endcode
135 
136  <b> Required Interface:</b>
137 
138  \code
139  RandomAccessIterator is, isend;
140  RandomAccessIterator id;
141 
142  SrcAccessor src_accessor;
143  DestAccessor dest_accessor;
144 
145  NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
146  double d;
147 
148  s = s + s;
149  s = d * s;
150 
151  dest_accessor.set(
152  NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
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  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  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 
320  // speichert den Ergebnis der linkseitigen Filterung.
321  std::vector<TempType> vline(w+1);
322  typename std::vector<TempType>::iterator line = vline.begin();
323 
324  double norm = 1.0 - b1 - b2;
325  double norm1 = (1.0 - b1 - b2) / (1.0 + b1 + b2);
326  double norm2 = norm * norm;
327 
328 
329  // init left side of filter
330  int kernelw = std::min(w-1, std::max(8, (int)(1.0 / norm + 0.5)));
331  is += (kernelw - 2);
332  line[kernelw] = as(is);
333  line[kernelw-1] = as(is);
334  for(x = kernelw - 2; x > 0; --x, --is)
335  {
336  line[x] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[x+1] + b2 * line[x+2]);
337  }
338  line[0] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[1] + b2 * line[2]);
339  ++is;
340  line[1] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[0] + b2 * line[1]);
341  ++is;
342  for(x=2; x < w; ++x, ++is)
343  {
344  line[x] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[x-1] + b2 * line[x-2]);
345  }
346  line[w] = line[w-1];
347 
348  line[w-1] = detail::RequiresExplicitCast<TempType>::cast(norm1 * (line[w-1] + b1 * line[w-2] + b2 * line[w-3]));
349  line[w-2] = detail::RequiresExplicitCast<TempType>::cast(norm1 * (line[w-2] + b1 * line[w] + b2 * line[w-2]));
350  id += w-1;
351  ad.set(line[w-1], id);
352  --id;
353  ad.set(line[w-2], id);
354  --id;
355  for(x=w-3; x>=0; --x, --id, --is)
356  {
357  line[x] = detail::RequiresExplicitCast<TempType>::cast(norm2 * line[x] + b1 * line[x+1] + b2 * line[x+2]);
358  ad.set(line[x], id);
359  }
360 }
361 
362 /********************************************************/
363 /* */
364 /* recursiveGaussianFilterLine */
365 /* */
366 /********************************************************/
367 
368 // AUTHOR: Sebastian Boppel
369 
370 /** \brief Compute a 1-dimensional recursive approximation of Gaussian smoothing.
371 
372  The function applies a causal and an anti-causal third order recursive filter
373  which optimally approximates the Gaussian filter, as proposed in
374 
375  I. Young, L. van Vliet: <i>Recursive implementation of the Gaussian filter</i><br>
376  Signal Processing 44:139-151, 1995
377 
378  The formulas for transforming the given scale parameter <tt>sigma</tt> into the actual filter coefficients
379  are taken from Luigi Rosa's Matlab implementation.
380 
381  The signal's value_type (SrcAccessor::value_type) must be a
382  linear space over <TT>double</TT>, i.e. addition of source values, multiplication with <TT>double</TT>,
383  and <TT>NumericTraits</TT> must be defined.
384 
385  <b> Declaration:</b>
386 
387  \code
388  namespace vigra {
389  template <class SrcIterator, class SrcAccessor,
390  class DestIterator, class DestAccessor>
391  void
392  recursiveGaussianFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
393  DestIterator id, DestAccessor ad,
394  double sigma);
395  }
396  \endcode
397 
398  <b> Usage:</b>
399 
400  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
401  Namespace: vigra
402 
403 
404  \code
405  vector<float> src, dest;
406  ...
407 
408  vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
409  double sigma = 2.5;
410 
411  vigra::recursiveGaussianFilterLine(src.begin(), src.end(), FAccessor(),
412  dest.begin(), FAccessor(),
413  sigma);
414  \endcode
415 
416  <b> Required Interface:</b>
417 
418  \code
419  RandomAccessIterator is, isend;
420  RandomAccessIterator id;
421 
422  SrcAccessor src_accessor;
423  DestAccessor dest_accessor;
424 
425  NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
426  double d;
427 
428  s = s + s;
429  s = d * s;
430 
431  dest_accessor.set(
432  NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
433  \endcode
434 
435  <b> Preconditions:</b>
436 
437  \code
438  0 <= sigma (absolute values are used for negative sigma)
439  \endcode
440 
441 */
443 
444 template <class SrcIterator, class SrcAccessor,
445  class DestIterator, class DestAccessor>
446 void
447 recursiveGaussianFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
448  DestIterator id, DestAccessor ad,
449  double sigma)
450 {
451  //coefficients taken out Luigi Rosa's implementation for Matlab
452  double q = 1.31564 * (std::sqrt(1.0 + 0.490811 * sigma*sigma) - 1.0);
453  double qq = q*q;
454  double qqq = qq*q;
455  double b0 = 1.0/(1.57825 + 2.44413*q + 1.4281*qq + 0.422205*qqq);
456  double b1 = (2.44413*q + 2.85619*qq + 1.26661*qqq)*b0;
457  double b2 = (-1.4281*qq - 1.26661*qqq)*b0;
458  double b3 = 0.422205*qqq*b0;
459  double B = 1.0 - (b1 + b2 + b3);
460 
461  int w = isend - is;
462  vigra_precondition(w >= 4,
463  "recursiveGaussianFilterLine(): line must have at least length 4.");
464 
465  int kernelw = std::min(w-4, (int)(4.0*sigma));
466 
467  int x;
468 
469  typedef typename
470  NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
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> <vigra/recursiveconvolution.hxx><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  \endcode
576 
577  <b> Preconditions:</b>
578 
579  \code
580  scale > 0
581  \endcode
582 
583 */
585 
586 template <class SrcIterator, class SrcAccessor,
587  class DestIterator, class DestAccessor>
588 inline
589 void recursiveSmoothLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
590  DestIterator id, DestAccessor ad, double scale)
591 {
592  vigra_precondition(scale >= 0,
593  "recursiveSmoothLine(): scale must be >= 0.\n");
594 
595  double b = (scale == 0.0) ?
596  0.0 :
597  VIGRA_CSTD::exp(-1.0/scale);
598 
599  recursiveFilterLine(is, isend, as, id, ad, b, BORDER_TREATMENT_REPEAT);
600 }
601 
602 /********************************************************/
603 /* */
604 /* recursiveFirstDerivativeLine */
605 /* */
606 /********************************************************/
607 
608 /** \brief Performs a 1 dimensional recursive convolution of the source signal.
609 
610  It uses the first derivative an exponential <TT>d/dx exp(-abs(x)/scale)</TT> as
611  a kernel. The signal's value_type (SrcAccessor::value_type) must be a
612  linear space over <TT>double</TT>,
613  i.e. addition and subtraction of source values, multiplication with
614  <TT>double</TT>, and <TT>NumericTraits</TT> must be defined. Border
615  treatment is always <TT>BORDER_TREATMENT_REPEAT</TT>.
616 
617  <b> Declaration:</b>
618 
619  \code
620  namespace vigra {
621  template <class SrcIterator, class SrcAccessor,
622  class DestIterator, class DestAccessor>
623  void recursiveFirstDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
624  DestIterator id, DestAccessor ad, double scale)
625  }
626  \endcode
627 
628  <b> Usage:</b>
629 
630  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
631  Namespace: vigra
632 
633 
634  \code
635  vector<float> src, dest;
636  ...
637 
638  vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
639 
640 
641  vigra::recursiveFirstDerivativeLine(src.begin(), src.end(), FAccessor(),
642  dest.begin(), FAccessor(), 3.0);
643  \endcode
644 
645  <b> Required Interface:</b>
646 
647  \code
648  RandomAccessIterator is, isend;
649  RandomAccessIterator id;
650 
651  SrcAccessor src_accessor;
652  DestAccessor dest_accessor;
653 
654  NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
655  double d;
656 
657  s = s + s;
658  s = -s;
659  s = d * s;
660 
661  dest_accessor.set(
662  NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
663  \endcode
664 
665  <b> Preconditions:</b>
666 
667  \code
668  scale > 0
669  \endcode
670 
671 */
673 
674 template <class SrcIterator, class SrcAccessor,
675  class DestIterator, class DestAccessor>
676 void recursiveFirstDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
677  DestIterator id, DestAccessor ad, double scale)
678 {
679  vigra_precondition(scale > 0,
680  "recursiveFirstDerivativeLine(): scale must be > 0.\n");
681 
682  int w = isend -is;
683 
684  int x;
685 
686  typedef typename
687  NumericTraits<typename SrcAccessor::value_type>::RealPromote
688  TempType;
689  typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
690 
691  std::vector<TempType> vline(w);
692  typename std::vector<TempType>::iterator line = vline.begin();
693 
694  double b = VIGRA_CSTD::exp(-1.0/scale);
695  double norm = (1.0 - b) * (1.0 - b) / 2.0 / b;
696  TempType old = (1.0 / (1.0 - b)) * as(is);
697 
698  // left side of filter
699  for(x=0; x<w; ++x, ++is)
700  {
701  old = as(is) + b * old;
702  line[x] = -old;
703  }
704 
705  // right side of the filter
706  --is;
707  old = (1.0 / (1.0 - b)) * as(is);
708  id += w;
709  ++is;
710 
711  for(x=w-1; x>=0; --x)
712  {
713  --is;
714  --id;
715 
716  old = as(is) + b * old;
717 
718  ad.set(DestTraits::fromRealPromote(norm * (line[x] + old)), id);
719  }
720 }
721 
722 /********************************************************/
723 /* */
724 /* recursiveSecondDerivativeLine */
725 /* */
726 /********************************************************/
727 
728 /** \brief Performs a 1 dimensional recursive convolution of the source signal.
729 
730  It uses the second derivative an exponential <TT>d2/dx2 exp(-abs(x)/scale)</TT> as
731  a kernel. The signal's value_type (SrcAccessor::value_type) must be a
732  linear space over <TT>double</TT>,
733  i.e. addition and subtraction of source values, multiplication with
734  <TT>double</TT>, and <TT>NumericTraits</TT> must be defined. Border
735  treatment is always <TT>BORDER_TREATMENT_REPEAT</TT>.
736 
737  <b> Declaration:</b>
738 
739  \code
740  namespace vigra {
741  template <class SrcIterator, class SrcAccessor,
742  class DestIterator, class DestAccessor>
743  void recursiveSecondDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
744  DestIterator id, DestAccessor ad, double scale)
745  }
746  \endcode
747 
748  <b> Usage:</b>
749 
750  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
751  Namespace: vigra
752 
753 
754  \code
755  vector<float> src, dest;
756  ...
757 
758  vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
759 
760 
761  vigra::recursiveSecondDerivativeLine(src.begin(), src.end(), FAccessor(),
762  dest.begin(), FAccessor(), 3.0);
763  \endcode
764 
765  <b> Required Interface:</b>
766 
767  \code
768  RandomAccessIterator is, isend;
769  RandomAccessIterator id;
770 
771  SrcAccessor src_accessor;
772  DestAccessor dest_accessor;
773 
774  NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
775  double d;
776 
777  s = s + s;
778  s = s - s;
779  s = d * s;
780 
781  dest_accessor.set(
782  NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
783  \endcode
784 
785  <b> Preconditions:</b>
786 
787  \code
788  scale > 0
789  \endcode
790 
791 */
793 
794 template <class SrcIterator, class SrcAccessor,
795  class DestIterator, class DestAccessor>
796 void recursiveSecondDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
797  DestIterator id, DestAccessor ad, double scale)
798 {
799  vigra_precondition(scale > 0,
800  "recursiveSecondDerivativeLine(): scale must be > 0.\n");
801 
802  int w = isend -is;
803 
804  int x;
805 
806  typedef typename
807  NumericTraits<typename SrcAccessor::value_type>::RealPromote
808  TempType;
809  typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
810 
811  std::vector<TempType> vline(w);
812  typename std::vector<TempType>::iterator line = vline.begin();
813 
814  double b = VIGRA_CSTD::exp(-1.0/scale);
815  double a = -2.0 / (1.0 - b);
816  double norm = (1.0 - b) * (1.0 - b) * (1.0 - b) / (1.0 + b);
817  TempType old = detail::RequiresExplicitCast<TempType>::cast((1.0 / (1.0 - b)) * as(is));
818 
819  // left side of filter
820  for(x=0; x<w; ++x, ++is)
821  {
822  line[x] = old;
823  old = detail::RequiresExplicitCast<TempType>::cast(as(is) + b * old);
824  }
825 
826  // right side of the filter
827  --is;
828  old = detail::RequiresExplicitCast<TempType>::cast((1.0 / (1.0 - b)) * as(is));
829  id += w;
830  ++is;
831 
832  for(x=w-1; x>=0; --x)
833  {
834  --is;
835  --id;
836 
837  TempType f = detail::RequiresExplicitCast<TempType>::cast(old + a * as(is));
838  old = detail::RequiresExplicitCast<TempType>::cast(as(is) + b * old);
839  ad.set(DestTraits::fromRealPromote(detail::RequiresExplicitCast<TempType>::cast(norm * (line[x] + f))), id);
840  }
841 }
842 
843 /********************************************************/
844 /* */
845 /* recursiveFilterX */
846 /* */
847 /********************************************************/
848 
849 /** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) in x direction.
850 
851  It calls \ref recursiveFilterLine() for every row of the
852  image. See \ref recursiveFilterLine() for more information about
853  required interfaces and vigra_preconditions.
854 
855  <b> Declarations:</b>
856 
857  pass 2D array views:
858  \code
859  namespace vigra {
860  // first order filter
861  template <class T1, class S1,
862  class T2, class S2>
863  void
864  recursiveFilterX(MultiArrayView<2, T1, S1> const & src,
865  MultiArrayView<2, T2, S2> dest,
866  double b, BorderTreatmentMode border);
867 
868  // second order filter
869  template <class T1, class S1,
870  class T2, class S2>
871  void
872  recursiveFilterX(MultiArrayView<2, T1, S1> const & src,
873  MultiArrayView<2, T2, S2> dest,
874  double b1, double b2);
875  }
876  \endcode
877 
878  \deprecatedAPI{recursiveFilterX}
879  pass \ref ImageIterators and \ref DataAccessors :
880  \code
881  namespace vigra {
882  // first order filter
883  template <class SrcImageIterator, class SrcAccessor,
884  class DestImageIterator, class DestAccessor>
885  void recursiveFilterX(SrcImageIterator supperleft,
886  SrcImageIterator slowerright, SrcAccessor as,
887  DestImageIterator dupperleft, DestAccessor ad,
888  double b, BorderTreatmentMode border);
889 
890  // second order filter
891  template <class SrcImageIterator, class SrcAccessor,
892  class DestImageIterator, class DestAccessor>
893  void recursiveFilterX(SrcImageIterator supperleft,
894  SrcImageIterator slowerright, SrcAccessor as,
895  DestImageIterator dupperleft, DestAccessor ad,
896  double b1, double b2);
897  }
898  \endcode
899  use argument objects in conjunction with \ref ArgumentObjectFactories :
900  \code
901  namespace vigra {
902  // first order filter
903  template <class SrcImageIterator, class SrcAccessor,
904  class DestImageIterator, class DestAccessor>
905  void recursiveFilterX(
906  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
907  pair<DestImageIterator, DestAccessor> dest,
908  double b, BorderTreatmentMode border);
909 
910  // second order filter
911  template <class SrcImageIterator, class SrcAccessor,
912  class DestImageIterator, class DestAccessor>
913  void recursiveFilterX(
914  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
915  pair<DestImageIterator, DestAccessor> dest,
916  double b1, double b2);
917  }
918  \endcode
919  \deprecatedEnd
920 
921  <b> Usage:</b>
922 
923  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
924  Namespace: vigra
925 
926  \code
927  MultiArray<2, float> src(w,h), dest(w,h);
928  ...
929 
930  // apply a first-order filter to the x-axis
931  recursiveFilterX(src, dest, 0.5, BORDER_TREATMENT_REFLECT);
932  \endcode
933 
934  \deprecatedUsage{recursiveFilterX}
935  \code
936  vigra::FImage src(w,h), dest(w,h);
937  ...
938 
939  vigra::recursiveFilterX(srcImageRange(src), destImage(dest),
940  0.5, BORDER_TREATMENT_REFLECT);
941  \endcode
942  \deprecatedEnd
943 */
945 
946 template <class SrcImageIterator, class SrcAccessor,
947  class DestImageIterator, class DestAccessor>
948 void recursiveFilterX(SrcImageIterator supperleft,
949  SrcImageIterator slowerright, SrcAccessor as,
950  DestImageIterator dupperleft, DestAccessor ad,
951  double b, BorderTreatmentMode border)
952 {
953  int w = slowerright.x - supperleft.x;
954  int h = slowerright.y - supperleft.y;
955 
956  int y;
957 
958  for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
959  {
960  typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
961  typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
962 
963  recursiveFilterLine(rs, rs+w, as,
964  rd, ad,
965  b, border);
966  }
967 }
968 
969 template <class SrcImageIterator, class SrcAccessor,
970  class DestImageIterator, class DestAccessor>
971 inline void
972 recursiveFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
973  pair<DestImageIterator, DestAccessor> dest,
974  double b, BorderTreatmentMode border)
975 {
976  recursiveFilterX(src.first, src.second, src.third,
977  dest.first, dest.second, b, border);
978 }
979 
980 template <class T1, class S1,
981  class T2, class S2>
982 inline void
983 recursiveFilterX(MultiArrayView<2, T1, S1> const & src,
984  MultiArrayView<2, T2, S2> dest,
985  double b, BorderTreatmentMode border)
986 {
987  vigra_precondition(src.shape() == dest.shape(),
988  "recursiveFilterX(): shape mismatch between input and output.");
989  recursiveFilterX(srcImageRange(src),
990  destImage(dest), b, border);
991 }
992 
993 /********************************************************/
994 /* */
995 /* recursiveFilterX (2nd order) */
996 /* */
997 /********************************************************/
998 
999 template <class SrcImageIterator, class SrcAccessor,
1000  class DestImageIterator, class DestAccessor>
1001 void recursiveFilterX(SrcImageIterator supperleft,
1002  SrcImageIterator slowerright, SrcAccessor as,
1003  DestImageIterator dupperleft, DestAccessor ad,
1004  double b1, double b2)
1005 {
1006  int w = slowerright.x - supperleft.x;
1007  int h = slowerright.y - supperleft.y;
1008 
1009  int y;
1010 
1011  for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
1012  {
1013  typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
1014  typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
1015 
1016  recursiveFilterLine(rs, rs+w, as,
1017  rd, ad,
1018  b1, b2);
1019  }
1020 }
1021 
1022 template <class SrcImageIterator, class SrcAccessor,
1023  class DestImageIterator, class DestAccessor>
1024 inline void
1025 recursiveFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1026  pair<DestImageIterator, DestAccessor> dest,
1027  double b1, double b2)
1028 {
1029  recursiveFilterX(src.first, src.second, src.third,
1030  dest.first, dest.second, b1, b2);
1031 }
1032 
1033 template <class T1, class S1,
1034  class T2, class S2>
1035 inline void
1036 recursiveFilterX(MultiArrayView<2, T1, S1> const & src,
1037  MultiArrayView<2, T2, S2> dest,
1038  double b1, double b2)
1039 {
1040  vigra_precondition(src.shape() == dest.shape(),
1041  "recursiveFilterX(): shape mismatch between input and output.");
1042  recursiveFilterX(srcImageRange(src),
1043  destImage(dest), b1, b2);
1044 }
1045 
1046 /********************************************************/
1047 /* */
1048 /* recursiveGaussianFilterX */
1049 /* */
1050 /********************************************************/
1051 
1052 // AUTHOR: Sebastian Boppel
1053 
1054 /** \brief Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
1055 
1056  It calls \ref recursiveGaussianFilterLine() for every column of the
1057  image. See \ref recursiveGaussianFilterLine() for more information about
1058  required interfaces and vigra_preconditions.
1059 
1060  <b> Declarations:</b>
1061 
1062  pass 2D array views:
1063  \code
1064  namespace vigra {
1065  template <class T1, class S1,
1066  class T2, class S2>
1067  void
1068  recursiveGaussianFilterX(MultiArrayView<2, T1, S1> const & src,
1069  MultiArrayView<2, T2, S2> dest,
1070  double sigma);
1071  }
1072  \endcode
1073 
1074  \deprecatedAPI{recursiveGaussianFilterX}
1075  pass \ref ImageIterators and \ref DataAccessors :
1076  \code
1077  namespace vigra {
1078  template <class SrcImageIterator, class SrcAccessor,
1079  class DestImageIterator, class DestAccessor>
1080  void
1081  recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
1082  DestImageIterator dupperleft, DestAccessor ad,
1083  double sigma);
1084  }
1085  \endcode
1086  use argument objects in conjunction with \ref ArgumentObjectFactories :
1087  \code
1088  namespace vigra {
1089  template <class SrcImageIterator, class SrcAccessor,
1090  class DestImageIterator, class DestAccessor>
1091  void
1092  recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1093  pair<DestImageIterator, DestAccessor> dest,
1094  double sigma);
1095  }
1096  \endcode
1097  \deprecatedEnd
1098 
1099  <b> Usage:</b>
1100 
1101  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1102  Namespace: vigra
1103 
1104  \code
1105  MultiArray<2, float> src(w,h), dest(w,h);
1106  ...
1107 
1108  recursiveGaussianFilterX(src, dest, 3.0);
1109  \endcode
1110 
1111  \deprecatedUsage{recursiveGaussianFilterX}
1112  \code
1113  vigra::FImage src(w,h), dest(w,h);
1114  ...
1115 
1116  vigra::recursiveGaussianFilterX(srcImageRange(src), destImage(dest), 3.0);
1117  \endcode
1118  \deprecatedEnd
1119 */
1121 
1122 template <class SrcImageIterator, class SrcAccessor,
1123  class DestImageIterator, class DestAccessor>
1124 void
1125 recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
1126  DestImageIterator dupperleft, DestAccessor ad,
1127  double sigma)
1128 {
1129  int w = slowerright.x - supperleft.x;
1130  int h = slowerright.y - supperleft.y;
1131 
1132  int y;
1133 
1134  for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
1135  {
1136  typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
1137  typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
1138 
1139  recursiveGaussianFilterLine(rs, rs+w, as,
1140  rd, ad,
1141  sigma);
1142  }
1143 }
1144 
1145 template <class SrcImageIterator, class SrcAccessor,
1146  class DestImageIterator, class DestAccessor>
1147 inline void
1148 recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1149  pair<DestImageIterator, DestAccessor> dest,
1150  double sigma)
1151 {
1152  recursiveGaussianFilterX(src.first, src.second, src.third,
1153  dest.first, dest.second, sigma);
1154 }
1155 
1156 template <class T1, class S1,
1157  class T2, class S2>
1158 inline void
1159 recursiveGaussianFilterX(MultiArrayView<2, T1, S1> const & src,
1160  MultiArrayView<2, T2, S2> dest,
1161  double sigma)
1162 {
1163  vigra_precondition(src.shape() == dest.shape(),
1164  "recursiveGaussianFilterX(): shape mismatch between input and output.");
1165  recursiveGaussianFilterX(srcImageRange(src),
1166  destImage(dest), sigma);
1167 }
1168 
1169 /********************************************************/
1170 /* */
1171 /* recursiveSmoothX */
1172 /* */
1173 /********************************************************/
1174 
1175 /** \brief Performs 1 dimensional recursive smoothing in x direction.
1176 
1177  It calls \ref recursiveSmoothLine() for every row of the
1178  image. See \ref recursiveSmoothLine() for more information about
1179  required interfaces and vigra_preconditions.
1180 
1181  <b> Declarations:</b>
1182 
1183  pass 2D array views:
1184  \code
1185  namespace vigra {
1186  template <class T1, class S1,
1187  class T2, class S2>
1188  void
1189  recursiveSmoothX(MultiArrayView<2, T1, S1> const & src,
1190  MultiArrayView<2, T2, S2> dest,
1191  double scale);
1192  }
1193  \endcode
1194 
1195  \deprecatedAPI{recursiveSmoothX}
1196  pass \ref ImageIterators and \ref DataAccessors :
1197  \code
1198  namespace vigra {
1199  template <class SrcImageIterator, class SrcAccessor,
1200  class DestImageIterator, class DestAccessor>
1201  void recursiveSmoothX(SrcImageIterator supperleft,
1202  SrcImageIterator slowerright, SrcAccessor as,
1203  DestImageIterator dupperleft, DestAccessor ad,
1204  double scale)
1205  }
1206  \endcode
1207  use argument objects in conjunction with \ref ArgumentObjectFactories :
1208  \code
1209  namespace vigra {
1210  template <class SrcImageIterator, class SrcAccessor,
1211  class DestImageIterator, class DestAccessor>
1212  void recursiveSmoothX(
1213  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1214  pair<DestImageIterator, DestAccessor> dest,
1215  double scale)
1216  }
1217  \endcode
1218  \deprecatedEnd
1219 
1220  <b> Usage:</b>
1221 
1222  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1223  Namespace: vigra
1224 
1225  \code
1226  MultiArray<2, float> src(w,h), dest(w,h);
1227  ...
1228 
1229  recursiveSmoothX(src, dest, 3.0);
1230  \endcode
1231 
1232  \deprecatedUsage{recursiveGaussianFilterX}
1233  \code
1234  vigra::FImage src(w,h), dest(w,h);
1235  ...
1236 
1237  vigra::recursiveSmoothX(srcImageRange(src), destImage(dest), 3.0);
1238  \endcode
1239  \deprecatedEnd
1240 */
1241 doxygen_overloaded_function(template <...> void recursiveSmoothX)
1242 
1243 template <class SrcImageIterator, class SrcAccessor,
1244  class DestImageIterator, class DestAccessor>
1245 void recursiveSmoothX(SrcImageIterator supperleft,
1246  SrcImageIterator slowerright, SrcAccessor as,
1247  DestImageIterator dupperleft, DestAccessor ad,
1248  double scale)
1249 {
1250  int w = slowerright.x - supperleft.x;
1251  int h = slowerright.y - supperleft.y;
1252 
1253  int y;
1254 
1255  for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
1256  {
1257  typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
1258  typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
1259 
1260  recursiveSmoothLine(rs, rs+w, as,
1261  rd, ad,
1262  scale);
1263  }
1264 }
1265 
1266 template <class SrcImageIterator, class SrcAccessor,
1267  class DestImageIterator, class DestAccessor>
1268 inline void
1269 recursiveSmoothX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1270  pair<DestImageIterator, DestAccessor> dest,
1271  double scale)
1272 {
1273  recursiveSmoothX(src.first, src.second, src.third,
1274  dest.first, dest.second, scale);
1275 }
1276 
1277 template <class T1, class S1,
1278  class T2, class S2>
1279 inline void
1280 recursiveSmoothX(MultiArrayView<2, T1, S1> const & src,
1281  MultiArrayView<2, T2, S2> dest,
1282  double scale)
1283 {
1284  vigra_precondition(src.shape() == dest.shape(),
1285  "recursiveSmoothX(): shape mismatch between input and output.");
1286  recursiveSmoothX(srcImageRange(src),
1287  destImage(dest), scale);
1288 }
1289 
1290 /********************************************************/
1291 /* */
1292 /* recursiveFilterY */
1293 /* */
1294 /********************************************************/
1295 
1296 /** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) in y direction.
1297 
1298  It calls \ref recursiveFilterLine() for every column of the
1299  image. See \ref recursiveFilterLine() for more information about
1300  required interfaces and vigra_preconditions.
1301 
1302  <b> Declarations:</b>
1303 
1304  pass 2D array views:
1305  \code
1306  namespace vigra {
1307  // first order filter
1308  template <class T1, class S1,
1309  class T2, class S2>
1310  void
1311  recursiveFilterY(MultiArrayView<2, T1, S1> const & src,
1312  MultiArrayView<2, T2, S2> dest,
1313  double b, BorderTreatmentMode border);
1314 
1315  // second order filter
1316  template <class T1, class S1,
1317  class T2, class S2>
1318  void
1319  recursiveFilterY(MultiArrayView<2, T1, S1> const & src,
1320  MultiArrayView<2, T2, S2> dest,
1321  double b1, double b2);
1322  }
1323  \endcode
1324 
1325  \deprecatedAPI{recursiveFilterY}
1326  pass \ref ImageIterators and \ref DataAccessors :
1327  \code
1328  namespace vigra {
1329  // first order filter
1330  template <class SrcImageIterator, class SrcAccessor,
1331  class DestImageIterator, class DestAccessor>
1332  void recursiveFilterY(SrcImageIterator supperleft,
1333  SrcImageIterator slowerright, SrcAccessor as,
1334  DestImageIterator dupperleft, DestAccessor ad,
1335  double b, BorderTreatmentMode border);
1336 
1337  // second order filter
1338  template <class SrcImageIterator, class SrcAccessor,
1339  class DestImageIterator, class DestAccessor>
1340  void recursiveFilterY(SrcImageIterator supperleft,
1341  SrcImageIterator slowerright, SrcAccessor as,
1342  DestImageIterator dupperleft, DestAccessor ad,
1343  double b1, double b2);
1344  }
1345  \endcode
1346  use argument objects in conjunction with \ref ArgumentObjectFactories :
1347  \code
1348  namespace vigra {
1349  // first order filter
1350  template <class SrcImageIterator, class SrcAccessor,
1351  class DestImageIterator, class DestAccessor>
1352  void recursiveFilterY(
1353  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1354  pair<DestImageIterator, DestAccessor> dest,
1355  double b, BorderTreatmentMode border);
1356 
1357  // second order filter
1358  template <class SrcImageIterator, class SrcAccessor,
1359  class DestImageIterator, class DestAccessor>
1360  void recursiveFilterY(
1361  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1362  pair<DestImageIterator, DestAccessor> dest,
1363  double b1, double b2);
1364  }
1365  \endcode
1366  \deprecatedEnd
1367 
1368  <b> Usage:</b>
1369 
1370  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1371  Namespace: vigra
1372 
1373  \code
1374  MultiArray<2, float> src(w,h), dest(w,h);
1375  ...
1376 
1377  // apply a second-order filter to the y-axis
1378  recursiveFilterY(src, dest, -0.6, -0.06);
1379  \endcode
1380 
1381  \deprecatedUsage{recursiveFilterY}
1382  \code
1383  vigra::FImage src(w,h), dest(w,h);
1384  ...
1385 
1386  vigra::recursiveFilterY(srcImageRange(src), destImage(dest), -0.6, -0.06);
1387  \endcode
1388  \deprecatedEnd
1389 */
1390 doxygen_overloaded_function(template <...> void recursiveFilterY)
1391 
1392 template <class SrcImageIterator, class SrcAccessor,
1393  class DestImageIterator, class DestAccessor>
1394 void recursiveFilterY(SrcImageIterator supperleft,
1395  SrcImageIterator slowerright, SrcAccessor as,
1396  DestImageIterator dupperleft, DestAccessor ad,
1397  double b, BorderTreatmentMode border)
1398 {
1399  int w = slowerright.x - supperleft.x;
1400  int h = slowerright.y - supperleft.y;
1401 
1402  int x;
1403 
1404  for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1405  {
1406  typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1407  typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1408 
1409  recursiveFilterLine(cs, cs+h, as,
1410  cd, ad,
1411  b, border);
1412  }
1413 }
1414 
1415 template <class SrcImageIterator, class SrcAccessor,
1416  class DestImageIterator, class DestAccessor>
1417 inline void
1418 recursiveFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1419  pair<DestImageIterator, DestAccessor> dest,
1420  double b, BorderTreatmentMode border)
1421 {
1422  recursiveFilterY(src.first, src.second, src.third,
1423  dest.first, dest.second, b, border);
1424 }
1425 
1426 template <class T1, class S1,
1427  class T2, class S2>
1428 inline void
1429 recursiveFilterY(MultiArrayView<2, T1, S1> const & src,
1430  MultiArrayView<2, T2, S2> dest,
1431  double b, BorderTreatmentMode border)
1432 {
1433  vigra_precondition(src.shape() == dest.shape(),
1434  "recursiveFilterY(): shape mismatch between input and output.");
1435  recursiveFilterY(srcImageRange(src),
1436  destImage(dest), b, border);
1437 }
1438 
1439 /********************************************************/
1440 /* */
1441 /* recursiveFilterY (2nd order) */
1442 /* */
1443 /********************************************************/
1444 
1445 template <class SrcImageIterator, class SrcAccessor,
1446  class DestImageIterator, class DestAccessor>
1447 void recursiveFilterY(SrcImageIterator supperleft,
1448  SrcImageIterator slowerright, SrcAccessor as,
1449  DestImageIterator dupperleft, DestAccessor ad,
1450  double b1, double b2)
1451 {
1452  int w = slowerright.x - supperleft.x;
1453  int h = slowerright.y - supperleft.y;
1454 
1455  int x;
1456 
1457  for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1458  {
1459  typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1460  typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1461 
1462  recursiveFilterLine(cs, cs+h, as,
1463  cd, ad,
1464  b1, b2);
1465  }
1466 }
1467 
1468 template <class SrcImageIterator, class SrcAccessor,
1469  class DestImageIterator, class DestAccessor>
1470 inline void
1471 recursiveFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1472  pair<DestImageIterator, DestAccessor> dest,
1473  double b1, double b2)
1474 {
1475  recursiveFilterY(src.first, src.second, src.third,
1476  dest.first, dest.second, b1, b2);
1477 }
1478 
1479 template <class T1, class S1,
1480  class T2, class S2>
1481 inline void
1482 recursiveFilterY(MultiArrayView<2, T1, S1> const & src,
1483  MultiArrayView<2, T2, S2> dest,
1484  double b1, double b2)
1485 {
1486  vigra_precondition(src.shape() == dest.shape(),
1487  "recursiveFilterY(): shape mismatch between input and output.");
1488  recursiveFilterY(srcImageRange(src),
1489  destImage(dest), b1, b2);
1490 }
1491 
1492 /********************************************************/
1493 /* */
1494 /* recursiveGaussianFilterY */
1495 /* */
1496 /********************************************************/
1497 
1498 // AUTHOR: Sebastian Boppel
1499 
1500 /** \brief Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
1501 
1502  It calls \ref recursiveGaussianFilterLine() for every column of the
1503  image. See \ref recursiveGaussianFilterLine() for more information about
1504  required interfaces and vigra_preconditions.
1505 
1506  <b> Declarations:</b>
1507 
1508  pass 2D array views:
1509  \code
1510  namespace vigra {
1511  template <class T1, class S1,
1512  class T2, class S2>
1513  void
1514  recursiveGaussianFilterY(MultiArrayView<2, T1, S1> const & src,
1515  MultiArrayView<2, T2, S2> dest,
1516  double sigma);
1517  }
1518  \endcode
1519 
1520  \deprecatedAPI{recursiveGaussianFilterY}
1521  pass \ref ImageIterators and \ref DataAccessors :
1522  \code
1523  namespace vigra {
1524  template <class SrcImageIterator, class SrcAccessor,
1525  class DestImageIterator, class DestAccessor>
1526  void
1527  recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
1528  DestImageIterator dupperleft, DestAccessor ad,
1529  double sigma);
1530  }
1531  \endcode
1532  use argument objects in conjunction with \ref ArgumentObjectFactories :
1533  \code
1534  namespace vigra {
1535  template <class SrcImageIterator, class SrcAccessor,
1536  class DestImageIterator, class DestAccessor>
1537  void
1538  recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1539  pair<DestImageIterator, DestAccessor> dest,
1540  double sigma);
1541  }
1542  \endcode
1543  \deprecatedEnd
1544 
1545  <b> Usage:</b>
1546 
1547  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1548  Namespace: vigra
1549 
1550  \code
1551  MultiArray<2, float> src(w,h), dest(w,h);
1552  ...
1553 
1554  recursiveGaussianFilterY(src, dest, 3.0);
1555  \endcode
1556 
1557  \deprecatedUsage{recursiveGaussianFilterY}
1558  \code
1559  vigra::FImage src(w,h), dest(w,h);
1560  ...
1561 
1562  vigra::recursiveGaussianFilterY(srcImageRange(src), destImage(dest), 3.0);
1563  \endcode
1564  \deprecatedEnd
1565 */
1567 
1568 template <class SrcImageIterator, class SrcAccessor,
1569  class DestImageIterator, class DestAccessor>
1570 void
1571 recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
1572  DestImageIterator dupperleft, DestAccessor ad,
1573  double sigma)
1574 {
1575  int w = slowerright.x - supperleft.x;
1576  int h = slowerright.y - supperleft.y;
1577 
1578  int x;
1579 
1580  for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1581  {
1582  typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1583  typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1584 
1585  recursiveGaussianFilterLine(cs, cs+h, as,
1586  cd, ad,
1587  sigma);
1588  }
1589 }
1590 
1591 template <class SrcImageIterator, class SrcAccessor,
1592  class DestImageIterator, class DestAccessor>
1593 inline void
1594 recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1595  pair<DestImageIterator, DestAccessor> dest,
1596  double sigma)
1597 {
1598  recursiveGaussianFilterY(src.first, src.second, src.third,
1599  dest.first, dest.second, sigma);
1600 }
1601 
1602 template <class T1, class S1,
1603  class T2, class S2>
1604 inline void
1605 recursiveGaussianFilterY(MultiArrayView<2, T1, S1> const & src,
1606  MultiArrayView<2, T2, S2> dest,
1607  double sigma)
1608 {
1609  vigra_precondition(src.shape() == dest.shape(),
1610  "recursiveGaussianFilterY(): shape mismatch between input and output.");
1611  recursiveGaussianFilterY(srcImageRange(src),
1612  destImage(dest), sigma);
1613 }
1614 
1615 
1616 /********************************************************/
1617 /* */
1618 /* recursiveSmoothY */
1619 /* */
1620 /********************************************************/
1621 
1622 /** \brief Performs 1 dimensional recursive smoothing in y direction.
1623 
1624  It calls \ref recursiveSmoothLine() for every column of the
1625  image. See \ref recursiveSmoothLine() for more information about
1626  required interfaces and vigra_preconditions.
1627 
1628  <b> Declarations:</b>
1629 
1630  pass 2D array views:
1631  \code
1632  namespace vigra {
1633  template <class T1, class S1,
1634  class T2, class S2>
1635  void
1636  recursiveSmoothY(MultiArrayView<2, T1, S1> const & src,
1637  MultiArrayView<2, T2, S2> dest,
1638  double scale);
1639  }
1640  \endcode
1641 
1642  \deprecatedAPI{recursiveSmoothY}
1643  pass \ref ImageIterators and \ref DataAccessors :
1644  \code
1645  namespace vigra {
1646  template <class SrcImageIterator, class SrcAccessor,
1647  class DestImageIterator, class DestAccessor>
1648  void recursiveSmoothY(SrcImageIterator supperleft,
1649  SrcImageIterator slowerright, SrcAccessor as,
1650  DestImageIterator dupperleft, DestAccessor ad,
1651  double scale)
1652  }
1653  \endcode
1654  use argument objects in conjunction with \ref ArgumentObjectFactories :
1655  \code
1656  namespace vigra {
1657  template <class SrcImageIterator, class SrcAccessor,
1658  class DestImageIterator, class DestAccessor>
1659  void recursiveSmoothY(
1660  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1661  pair<DestImageIterator, DestAccessor> dest,
1662  double scale)
1663  }
1664  \endcode
1665  \deprecatedEnd
1666 
1667  <b> Usage:</b>
1668 
1669  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1670  Namespace: vigra
1671 
1672  \code
1673  MultiArray<2, float> src(w,h), dest(w,h);
1674  ...
1675 
1676  recursiveSmoothY(src, dest, 3.0);
1677  \endcode
1678 
1679  \deprecatedUsage{recursiveSmoothY}
1680  \code
1681  vigra::FImage src(w,h), dest(w,h);
1682  ...
1683 
1684  vigra::recursiveSmoothY(srcImageRange(src), destImage(dest), 3.0);
1685  \endcode
1686  \deprecatedEnd
1687 */
1688 doxygen_overloaded_function(template <...> void recursiveSmoothY)
1689 
1690 template <class SrcImageIterator, class SrcAccessor,
1691  class DestImageIterator, class DestAccessor>
1692 void recursiveSmoothY(SrcImageIterator supperleft,
1693  SrcImageIterator slowerright, SrcAccessor as,
1694  DestImageIterator dupperleft, DestAccessor ad,
1695  double scale)
1696 {
1697  int w = slowerright.x - supperleft.x;
1698  int h = slowerright.y - supperleft.y;
1699 
1700  int x;
1701 
1702  for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1703  {
1704  typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1705  typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1706 
1707  recursiveSmoothLine(cs, cs+h, as,
1708  cd, ad,
1709  scale);
1710  }
1711 }
1712 
1713 template <class SrcImageIterator, class SrcAccessor,
1714  class DestImageIterator, class DestAccessor>
1715 inline void
1716 recursiveSmoothY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1717  pair<DestImageIterator, DestAccessor> dest,
1718  double scale)
1719 {
1720  recursiveSmoothY(src.first, src.second, src.third,
1721  dest.first, dest.second, scale);
1722 }
1723 
1724 template <class T1, class S1,
1725  class T2, class S2>
1726 inline void
1727 recursiveSmoothY(MultiArrayView<2, T1, S1> const & src,
1728  MultiArrayView<2, T2, S2> dest,
1729  double scale)
1730 {
1731  vigra_precondition(src.shape() == dest.shape(),
1732  "recursiveSmoothY(): shape mismatch between input and output.");
1733  recursiveSmoothY(srcImageRange(src),
1734  destImage(dest), scale);
1735 }
1736 
1737 /********************************************************/
1738 /* */
1739 /* recursiveFirstDerivativeX */
1740 /* */
1741 /********************************************************/
1742 
1743 /** \brief Recursively calculates the 1 dimensional first derivative in x
1744  direction.
1745 
1746  It calls \ref recursiveFirstDerivativeLine() for every
1747  row of the image. See \ref recursiveFirstDerivativeLine() for more
1748  information about required interfaces and vigra_preconditions.
1749 
1750  <b> Declarations:</b>
1751 
1752  pass 2D array views:
1753  \code
1754  namespace vigra {
1755  template <class T1, class S1,
1756  class T2, class S2>
1757  void
1758  recursiveFirstDerivativeX(MultiArrayView<2, T1, S1> const & src,
1759  MultiArrayView<2, T2, S2> dest,
1760  double scale);
1761  }
1762  \endcode
1763 
1764  \deprecatedAPI{recursiveFirstDerivativeX}
1765  pass \ref ImageIterators and \ref DataAccessors :
1766  \code
1767  namespace vigra {
1768  template <class SrcImageIterator, class SrcAccessor,
1769  class DestImageIterator, class DestAccessor>
1770  void recursiveFirstDerivativeX(SrcImageIterator supperleft,
1771  SrcImageIterator slowerright, SrcAccessor as,
1772  DestImageIterator dupperleft, DestAccessor ad,
1773  double scale)
1774  }
1775  \endcode
1776  use argument objects in conjunction with \ref ArgumentObjectFactories :
1777  \code
1778  namespace vigra {
1779  template <class SrcImageIterator, class SrcAccessor,
1780  class DestImageIterator, class DestAccessor>
1781  void recursiveFirstDerivativeX(
1782  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1783  pair<DestImageIterator, DestAccessor> dest,
1784  double scale)
1785  }
1786  \endcode
1787  \deprecatedEnd
1788 
1789  <b> Usage:</b>
1790 
1791  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1792  Namespace: vigra
1793 
1794  \code
1795  MultiArray<2, float> src(w,h), dest(w,h);
1796  ...
1797 
1798  recursiveFirstDerivativeX(src, dest, 3.0);
1799  \endcode
1800 
1801  \deprecatedUsage{recursiveFirstDerivativeX}
1802  \code
1803  vigra::FImage src(w,h), dest(w,h);
1804  ...
1805 
1806  vigra::recursiveFirstDerivativeX(srcImageRange(src), destImage(dest), 3.0);
1807  \endcode
1808  \deprecatedEnd
1809 */
1811 
1812 template <class SrcImageIterator, class SrcAccessor,
1813  class DestImageIterator, class DestAccessor>
1814 void recursiveFirstDerivativeX(SrcImageIterator supperleft,
1815  SrcImageIterator slowerright, SrcAccessor as,
1816  DestImageIterator dupperleft, DestAccessor ad,
1817  double scale)
1818 {
1819  int w = slowerright.x - supperleft.x;
1820  int h = slowerright.y - supperleft.y;
1821 
1822  int y;
1823 
1824  for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
1825  {
1826  typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
1827  typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
1828 
1829  recursiveFirstDerivativeLine(rs, rs+w, as,
1830  rd, ad,
1831  scale);
1832  }
1833 }
1834 
1835 template <class SrcImageIterator, class SrcAccessor,
1836  class DestImageIterator, class DestAccessor>
1837 inline void
1838 recursiveFirstDerivativeX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1839  pair<DestImageIterator, DestAccessor> dest,
1840  double scale)
1841 {
1842  recursiveFirstDerivativeX(src.first, src.second, src.third,
1843  dest.first, dest.second, scale);
1844 }
1845 
1846 template <class T1, class S1,
1847  class T2, class S2>
1848 inline void
1849 recursiveFirstDerivativeX(MultiArrayView<2, T1, S1> const & src,
1850  MultiArrayView<2, T2, S2> dest,
1851  double scale)
1852 {
1853  vigra_precondition(src.shape() == dest.shape(),
1854  "recursiveFirstDerivativeX(): shape mismatch between input and output.");
1855  recursiveFirstDerivativeX(srcImageRange(src),
1856  destImage(dest), scale);
1857 }
1858 
1859 /********************************************************/
1860 /* */
1861 /* recursiveFirstDerivativeY */
1862 /* */
1863 /********************************************************/
1864 
1865 /** \brief Recursively calculates the 1 dimensional first derivative in y
1866  direction.
1867 
1868  It calls \ref recursiveFirstDerivativeLine() for every
1869  column of the image. See \ref recursiveFirstDerivativeLine() for more
1870  information about required interfaces and vigra_preconditions.
1871 
1872  <b> Declarations:</b>
1873 
1874  pass 2D array views:
1875  \code
1876  namespace vigra {
1877  template <class T1, class S1,
1878  class T2, class S2>
1879  void
1880  recursiveFirstDerivativeY(MultiArrayView<2, T1, S1> const & src,
1881  MultiArrayView<2, T2, S2> dest,
1882  double scale);
1883  }
1884  \endcode
1885 
1886  \deprecatedAPI{recursiveFirstDerivativeY}
1887  pass \ref ImageIterators and \ref DataAccessors :
1888  \code
1889  namespace vigra {
1890  template <class SrcImageIterator, class SrcAccessor,
1891  class DestImageIterator, class DestAccessor>
1892  void recursiveFirstDerivativeY(SrcImageIterator supperleft,
1893  SrcImageIterator slowerright, SrcAccessor as,
1894  DestImageIterator dupperleft, DestAccessor ad,
1895  double scale)
1896  }
1897  \endcode
1898  use argument objects in conjunction with \ref ArgumentObjectFactories :
1899  \code
1900  namespace vigra {
1901  template <class SrcImageIterator, class SrcAccessor,
1902  class DestImageIterator, class DestAccessor>
1903  void recursiveFirstDerivativeY(
1904  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1905  pair<DestImageIterator, DestAccessor> dest,
1906  double scale)
1907  }
1908  \endcode
1909  \deprecatedEnd
1910 
1911  <b> Usage:</b>
1912 
1913  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1914  Namespace: vigra
1915 
1916  \code
1917  MultiArray<2, float> src(w,h), dest(w,h);
1918  ...
1919 
1920  recursiveFirstDerivativeY(src, dest, 3.0);
1921  \endcode
1922 
1923  \deprecatedUsage{recursiveFirstDerivativeY}
1924  \code
1925  vigra::FImage src(w,h), dest(w,h);
1926  ...
1927 
1928  vigra::recursiveFirstDerivativeY(srcImageRange(src), destImage(dest), 3.0);
1929  \endcode
1930  \deprecatedEnd
1931 */
1933 
1934 template <class SrcImageIterator, class SrcAccessor,
1935  class DestImageIterator, class DestAccessor>
1936 void recursiveFirstDerivativeY(SrcImageIterator supperleft,
1937  SrcImageIterator slowerright, SrcAccessor as,
1938  DestImageIterator dupperleft, DestAccessor ad,
1939  double scale)
1940 {
1941  int w = slowerright.x - supperleft.x;
1942  int h = slowerright.y - supperleft.y;
1943 
1944  int x;
1945 
1946  for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1947  {
1948  typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1949  typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1950 
1951  recursiveFirstDerivativeLine(cs, cs+h, as,
1952  cd, ad,
1953  scale);
1954  }
1955 }
1956 
1957 template <class SrcImageIterator, class SrcAccessor,
1958  class DestImageIterator, class DestAccessor>
1959 inline void
1960 recursiveFirstDerivativeY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1961  pair<DestImageIterator, DestAccessor> dest,
1962  double scale)
1963 {
1964  recursiveFirstDerivativeY(src.first, src.second, src.third,
1965  dest.first, dest.second, scale);
1966 }
1967 
1968 template <class T1, class S1,
1969  class T2, class S2>
1970 inline void
1971 recursiveFirstDerivativeY(MultiArrayView<2, T1, S1> const & src,
1972  MultiArrayView<2, T2, S2> dest,
1973  double scale)
1974 {
1975  vigra_precondition(src.shape() == dest.shape(),
1976  "recursiveFirstDerivativeY(): shape mismatch between input and output.");
1977  recursiveFirstDerivativeY(srcImageRange(src),
1978  destImage(dest), scale);
1979 }
1980 
1981 /********************************************************/
1982 /* */
1983 /* recursiveSecondDerivativeX */
1984 /* */
1985 /********************************************************/
1986 
1987 /** \brief Recursively calculates the 1 dimensional second derivative in x
1988  direction.
1989 
1990  It calls \ref recursiveSecondDerivativeLine() for every
1991  row of the image. See \ref recursiveSecondDerivativeLine() for more
1992  information about required interfaces and vigra_preconditions.
1993 
1994  <b> Declarations:</b>
1995 
1996  pass 2D array views:
1997  \code
1998  namespace vigra {
1999  template <class T1, class S1,
2000  class T2, class S2>
2001  void
2002  recursiveSecondDerivativeX(MultiArrayView<2, T1, S1> const & src,
2003  MultiArrayView<2, T2, S2> dest,
2004  double scale);
2005  }
2006  \endcode
2007 
2008  \deprecatedAPI{recursiveSecondDerivativeX}
2009  pass \ref ImageIterators and \ref DataAccessors :
2010  \code
2011  namespace vigra {
2012  template <class SrcImageIterator, class SrcAccessor,
2013  class DestImageIterator, class DestAccessor>
2014  void recursiveSecondDerivativeX(SrcImageIterator supperleft,
2015  SrcImageIterator slowerright, SrcAccessor as,
2016  DestImageIterator dupperleft, DestAccessor ad,
2017  double scale)
2018  }
2019  \endcode
2020  use argument objects in conjunction with \ref ArgumentObjectFactories :
2021  \code
2022  namespace vigra {
2023  template <class SrcImageIterator, class SrcAccessor,
2024  class DestImageIterator, class DestAccessor>
2025  void recursiveSecondDerivativeX(
2026  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
2027  pair<DestImageIterator, DestAccessor> dest,
2028  double scale)
2029  }
2030  \endcode
2031  \deprecatedEnd
2032 
2033  <b> Usage:</b>
2034 
2035  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
2036  Namespace: vigra
2037 
2038  \code
2039  MultiArray<2, float> src(w,h), dest(w,h);
2040  ...
2041 
2042  recursiveSecondDerivativeX(src, dest, 3.0);
2043  \endcode
2044 
2045  \deprecatedUsage{recursiveSecondDerivativeX}
2046  \code
2047  vigra::FImage src(w,h), dest(w,h);
2048  ...
2049 
2050  vigra::recursiveSecondDerivativeX(srcImageRange(src), destImage(dest), 3.0);
2051  \endcode
2052  \deprecatedEnd
2053 */
2055 
2056 template <class SrcImageIterator, class SrcAccessor,
2057  class DestImageIterator, class DestAccessor>
2058 void recursiveSecondDerivativeX(SrcImageIterator supperleft,
2059  SrcImageIterator slowerright, SrcAccessor as,
2060  DestImageIterator dupperleft, DestAccessor ad,
2061  double scale)
2062 {
2063  int w = slowerright.x - supperleft.x;
2064  int h = slowerright.y - supperleft.y;
2065 
2066  int y;
2067 
2068  for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
2069  {
2070  typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
2071  typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
2072 
2073  recursiveSecondDerivativeLine(rs, rs+w, as,
2074  rd, ad,
2075  scale);
2076  }
2077 }
2078 
2079 template <class SrcImageIterator, class SrcAccessor,
2080  class DestImageIterator, class DestAccessor>
2081 inline void
2082 recursiveSecondDerivativeX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
2083  pair<DestImageIterator, DestAccessor> dest,
2084  double scale)
2085 {
2086  recursiveSecondDerivativeX(src.first, src.second, src.third,
2087  dest.first, dest.second, scale);
2088 }
2089 
2090 template <class T1, class S1,
2091  class T2, class S2>
2092 inline void
2093 recursiveSecondDerivativeX(MultiArrayView<2, T1, S1> const & src,
2094  MultiArrayView<2, T2, S2> dest,
2095  double scale)
2096 {
2097  vigra_precondition(src.shape() == dest.shape(),
2098  "recursiveSecondDerivativeX(): shape mismatch between input and output.");
2099  recursiveSecondDerivativeX(srcImageRange(src),
2100  destImage(dest), scale);
2101 }
2102 
2103 /********************************************************/
2104 /* */
2105 /* recursiveSecondDerivativeY */
2106 /* */
2107 /********************************************************/
2108 
2109 /** \brief Recursively calculates the 1 dimensional second derivative in y
2110  direction.
2111 
2112  It calls \ref recursiveSecondDerivativeLine() for every
2113  column of the image. See \ref recursiveSecondDerivativeLine() for more
2114  information about required interfaces and vigra_preconditions.
2115 
2116  <b> Declarations:</b>
2117 
2118  pass 2D array views:
2119  \code
2120  namespace vigra {
2121  template <class T1, class S1,
2122  class T2, class S2>
2123  void
2124  recursiveSecondDerivativeY(MultiArrayView<2, T1, S1> const & src,
2125  MultiArrayView<2, T2, S2> dest,
2126  double scale);
2127  }
2128  \endcode
2129 
2130  \deprecatedAPI{recursiveSecondDerivativeY}
2131  pass \ref ImageIterators and \ref DataAccessors :
2132  \code
2133  namespace vigra {
2134  template <class SrcImageIterator, class SrcAccessor,
2135  class DestImageIterator, class DestAccessor>
2136  void recursiveSecondDerivativeY(SrcImageIterator supperleft,
2137  SrcImageIterator slowerright, SrcAccessor as,
2138  DestImageIterator dupperleft, DestAccessor ad,
2139  double scale)
2140  }
2141  \endcode
2142  use argument objects in conjunction with \ref ArgumentObjectFactories :
2143  \code
2144  namespace vigra {
2145  template <class SrcImageIterator, class SrcAccessor,
2146  class DestImageIterator, class DestAccessor>
2147  void recursiveSecondDerivativeY(
2148  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
2149  pair<DestImageIterator, DestAccessor> dest,
2150  double scale)
2151  }
2152  \endcode
2153  \deprecatedEnd
2154 
2155  <b> Usage:</b>
2156 
2157  <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
2158  Namespace: vigra
2159 
2160  \code
2161  MultiArray<2, float> src(w,h), dest(w,h);
2162  ...
2163 
2164  recursiveSecondDerivativeY(src, dest, 3.0);
2165  \endcode
2166 
2167  \deprecatedUsage{recursiveSecondDerivativeY}
2168  \code
2169  vigra::FImage src(w,h), dest(w,h);
2170  ...
2171 
2172  vigra::recursiveSecondDerivativeY(srcImageRange(src), destImage(dest), 3.0);
2173  \endcode
2174  \deprecatedEnd
2175 */
2177 
2178 template <class SrcImageIterator, class SrcAccessor,
2179  class DestImageIterator, class DestAccessor>
2180 void recursiveSecondDerivativeY(SrcImageIterator supperleft,
2181  SrcImageIterator slowerright, SrcAccessor as,
2182  DestImageIterator dupperleft, DestAccessor ad,
2183  double scale)
2184 {
2185  int w = slowerright.x - supperleft.x;
2186  int h = slowerright.y - supperleft.y;
2187 
2188  int x;
2189 
2190  for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
2191  {
2192  typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
2193  typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
2194 
2195  recursiveSecondDerivativeLine(cs, cs+h, as,
2196  cd, ad,
2197  scale);
2198  }
2199 }
2200 
2201 template <class SrcImageIterator, class SrcAccessor,
2202  class DestImageIterator, class DestAccessor>
2203 inline void
2204 recursiveSecondDerivativeY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
2205  pair<DestImageIterator, DestAccessor> dest,
2206  double scale)
2207 {
2208  recursiveSecondDerivativeY(src.first, src.second, src.third,
2209  dest.first, dest.second, scale);
2210 }
2211 
2212 template <class T1, class S1,
2213  class T2, class S2>
2214 inline void
2215 recursiveSecondDerivativeY(MultiArrayView<2, T1, S1> const & src,
2216  MultiArrayView<2, T2, S2> dest,
2217  double scale)
2218 {
2219  vigra_precondition(src.shape() == dest.shape(),
2220  "recursiveSecondDerivativeY(): shape mismatch between input and output.");
2221  recursiveSecondDerivativeY(srcImageRange(src),
2222  destImage(dest), scale);
2223 }
2224 
2225 //@}
2226 
2227 } // namespace vigra
2228 
2229 #endif // VIGRA_RECURSIVECONVOLUTION_HXX
void recursiveFirstDerivativeX(...)
Recursively calculates the 1 dimensional first derivative in x direction.
void recursiveGaussianFilterX(...)
Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
void recursiveFirstDerivativeLine(...)
Performs a 1 dimensional recursive convolution of the source signal.
void recursiveFilterY(...)
Performs 1 dimensional recursive filtering (1st and 2nd order) in y direction.
linalg::TemporaryMatrix< T > exp(MultiArrayView< 2, T, C > const &v)
void recursiveSmoothLine(...)
Convolves the image with a 1-dimensional exponential filter.
void recursiveSecondDerivativeY(...)
Recursively calculates the 1 dimensional second derivative in y direction.
FFTWComplex< R >::NormType norm(const FFTWComplex< R > &a)
norm (= magnitude)
Definition: fftw3.hxx:1037
void recursiveSecondDerivativeLine(...)
Performs a 1 dimensional recursive convolution of the source signal.
void recursiveFilterLine(...)
Performs a 1-dimensional recursive convolution of the source signal.
void recursiveFilterX(...)
Performs 1 dimensional recursive filtering (1st and 2nd order) in x direction.
void recursiveGaussianFilterY(...)
Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
void recursiveGaussianFilterLine(...)
Compute a 1-dimensional recursive approximation of Gaussian smoothing.
void recursiveSmoothX(...)
Performs 1 dimensional recursive smoothing in x direction.
void recursiveSecondDerivativeX(...)
Recursively calculates the 1 dimensional second derivative in x direction.
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
void recursiveSmoothY(...)
Performs 1 dimensional recursive smoothing in y direction.
linalg::TemporaryMatrix< T > log(MultiArrayView< 2, T, C > const &v)
void recursiveFirstDerivativeY(...)
Recursively calculates the 1 dimensional first derivative in y direction.
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616

© 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.11.1 (Fri May 19 2017)