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

convolution.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_CONVOLUTION_HXX
38 #define VIGRA_CONVOLUTION_HXX
39 
40 #include <functional>
41 #include "stdconvolution.hxx"
42 #include "separableconvolution.hxx"
43 #include "recursiveconvolution.hxx"
44 #include "nonlineardiffusion.hxx"
45 #include "combineimages.hxx"
46 #include "multi_shape.hxx"
47 
48 
49 /** \page Convolution Functions to Convolve Images and Signals
50 
51  1D and 2D filters, including separable and recursive convolution, and non-linear diffusion
52 
53  <b>\#include</b> <vigra/convolution.hxx><br>
54  Namespace: vigra
55 
56  <UL style="list-style-image:url(documents/bullet.gif)">
57  <LI> \ref CommonConvolutionFilters
58  <BR>&nbsp;&nbsp;&nbsp;<em>Short-hands for many common 2D convolution filters (including normalized convolution)</em>
59  <LI> \ref MultiArrayConvolutionFilters
60  <BR>&nbsp;&nbsp;&nbsp;<em>Convolution filters for arbitrary dimensional arrays (MultiArray etc.)</em>
61  <LI> \ref ResamplingConvolutionFilters
62  <BR>&nbsp;&nbsp;&nbsp;<em>Resampling convolution filters</em>
63  <LI> \ref vigra::Kernel2D
64  <BR>&nbsp;&nbsp;&nbsp;<em>Generic 2-dimensional discrete convolution kernel </em>
65  <LI> \ref SeparableConvolution
66  <BR>&nbsp;&nbsp;&nbsp;<em>1D convolution and separable filters in 2 dimensions </em>
67  <LI> \ref vigra::Kernel1D
68  <BR>&nbsp;&nbsp;&nbsp;<em>Generic 1-dimensional discrete convolution kernel </em>
69  <LI> \ref RecursiveConvolution
70  <BR>&nbsp;&nbsp;&nbsp;<em>Recursive filters (1st and 2nd order)</em>
71  <LI> \ref NonLinearDiffusion
72  <BR>&nbsp;&nbsp;&nbsp;<em>Edge-preserving smoothing </em>
73  <LI> \ref BorderTreatmentMode
74  <BR>&nbsp;&nbsp;&nbsp;<em>Choose between different border treatment modes </em>
75  <LI> \ref KernelArgumentObjectFactories
76  <BR>&nbsp;&nbsp;&nbsp;<em>Factory functions to create argument objects to simplify passing kernels</em>
77  </UL>
78 */
79 
80 /** \page KernelArgumentObjectFactories Kernel Argument Object Factories
81 
82  These factory functions allow to create argument objects for 1D
83  and 2D convolution kernel analogously to
84  \ref ArgumentObjectFactories for images.
85 
86  \section Kernel1dFactory kernel1d()
87 
88  Pass a \ref vigra::Kernel1D to a 1D or separable convolution algorithm.
89 
90  These factories can be used to create argument objects when we
91  are given instances or subclasses of \ref vigra::Kernel1D
92  (analogous to the \ref ArgumentObjectFactories for images).
93  These factory functions access <TT>kernel.center()</TT>,
94  <TT>kernel.left()</TT>, <TT>kernel.right()</TT>, <TT>kernel.accessor()</TT>,
95  and <TT>kernel.borderTreatment()</TT> to obtain the necessary
96  information. The following factory functions are provided:
97 
98  <table>
99  <tr><th bgcolor="#f0e0c0" colspan=2 align=left>
100  <TT>\ref vigra::Kernel1D "vigra::Kernel1D<SomeType>" kernel;</TT>
101  </th>
102  </tr>
103  <tr><td>
104  <TT>kernel1d(kernel)</TT>
105  </td><td>
106  create argument object from information provided by
107  kernel
108 
109  </td></tr>
110  <tr><td>
111  <TT>kernel1d(kernel, vigra::BORDER_TREATMENT_CLIP)</TT>
112  </td><td>
113  create argument object from information provided by
114  kernel, but use given border treatment mode
115 
116  </td></tr>
117  <tr><td>
118  <TT>kernel1d(kerneliterator, kernelaccessor,</TT><br>
119  <TT> kernelleft, kernelright,</TT><br>
120  <TT> vigra::BORDER_TREATMENT_CLIP)</TT>
121  </td><td>
122  create argument object from explicitly given iterator
123  (pointing to the center of th kernel), accessor,
124  left and right boundaries, and border treatment mode
125 
126  </table>
127 
128  For usage examples see \ref convolveImage().
129 
130  \section Kernel2dFactory kernel2d()
131 
132  Pass a \ref vigra::Kernel2D to a 2D (non-separable) convolution algorithm.
133 
134  These factories can be used to create argument objects when we
135  are given instances or subclasses of \ref vigra::Kernel2D
136  (analogous to the \ref ArgumentObjectFactories for images).
137  These factory functions access <TT>kernel.center()</TT>,
138  <TT>kernel.upperLeft()</TT>, <TT>kernel.lowerRight()</TT>, <TT>kernel.accessor()</TT>,
139  and <TT>kernel.borderTreatment()</TT> to obtain the necessary
140  information. The following factory functions are provided:
141 
142  <table>
143  <tr><th bgcolor="#f0e0c0" colspan=2 align=left>
144  <TT>\ref vigra::Kernel2D "vigra::Kernel2D<SomeType>" kernel;</TT>
145  </th>
146  </tr>
147  <tr><td>
148  <TT>kernel2d(kernel)</TT>
149  </td><td>
150  create argument object from information provided by
151  kernel
152 
153  </td></tr>
154  <tr><td>
155  <TT>kernel2d(kernel, vigra::BORDER_TREATMENT_CLIP)</TT>
156  </td><td>
157  create argument object from information provided by
158  kernel, but use given border treatment mode
159 
160  </td></tr>
161  <tr><td>
162  <TT>kernel2d(kerneliterator, kernelaccessor,</TT>
163  <TT> upperleft, lowerright,</TT>
164  <TT> vigra::BORDER_TREATMENT_CLIP)</TT>
165  </td><td>
166  create argument object from explicitly given iterator
167  (pointing to the center of th kernel), accessor,
168  upper left and lower right corners, and border treatment mode
169 
170  </table>
171 
172  For usage examples see \ref convolveImage().
173 */
174 
175 namespace vigra {
176 
177 
178 
179 /********************************************************/
180 /* */
181 /* Common convolution filters */
182 /* */
183 /********************************************************/
184 
185 /** \addtogroup CommonConvolutionFilters Common Filters
186 
187  These functions calculate common filters by appropriate sequences of calls
188  to \ref separableConvolveX() and \ref separableConvolveY() or explicit 2-dimensional
189  convolution.
190 */
191 //@{
192 
193 /** \brief Convolve an image with the given kernel(s).
194 
195  If you pass \ref vigra::Kernel2D to this function, it will perform an explicit 2-dimensional
196  convolution. If you pass a single \ref vigra::Kernel1D, it performs a separable convolution,
197  i.e. it concatenates two 1D convolutions (along the x-axis and along the y-axis) with the same
198  kernel via internal calls to \ref separableConvolveX() and \ref separableConvolveY(). If two
199  1D kernels are specified, separable convolution uses different kernels for the x- and y-axis.
200 
201  All \ref BorderTreatmentMode "border treatment modes" are supported.
202 
203  The unput pixel type <tt>T1</tt> must be a \ref LinearSpace "linear space" over
204  the kernel's value_type <tt>T</tt>, i.e. addition of source values, multiplication with kernel values,
205  and NumericTraits must be defined. The kernel's value_type must be an \ref AlgebraicField "algebraic field",
206  i.e. the arithmetic operations (+, -, *, /) and NumericTraits must be defined. Typically, you will use
207  <tt>double</tt> for the kernel type.
208 
209  <b> Declarations:</b>
210 
211  pass 2D array views:
212  \code
213  namespace vigra {
214  // use the same 1D kernel for all axes
215  template <class T1, class S1,
216  class T2, class S2,
217  class T>
218  void
219  convolveImage(MultiArrayView<2, T1, S1> const & src,
220  MultiArrayView<2, T2, S2> dest,
221  Kernel1D<T> const & k);
222 
223  // use a different kernel for each axis
224  template <class T1, class S1,
225  class T2, class S2,
226  class T>
227  void
228  convolveImage(MultiArrayView<2, T1, S1> const & src,
229  MultiArrayView<2, T2, S2> dest,
230  Kernel1D<T> const & kx, Kernel1D<T> const & ky);
231 
232  // use a non-separable 2D kernel
233  template <class T1, class S1,
234  class T2, class S2,
235  class T3>
236  void
237  convolveImage(MultiArrayView<2, T1, S1> const & src,
238  MultiArrayView<2, T2, S2> dest,
239  Kernel2D<T3> const & kernel);
240  }
241  \endcode
242 
243  \deprecatedAPI{convolveImage}
244  pass \ref ImageIterators and \ref DataAccessors :
245  \code
246  namespace vigra {
247  // use a different kernel for each axis
248  template <class SrcIterator, class SrcAccessor,
249  class DestIterator, class DestAccessor,
250  class T>
251  void convolveImage(SrcIterator supperleft,
252  SrcIterator slowerright, SrcAccessor sa,
253  DestIterator dupperleft, DestAccessor da,
254  Kernel1D<T> const & kx, Kernel1D<T> const & ky);
255 
256  // use a non-separable 2D kernel
257  template <class SrcIterator, class SrcAccessor,
258  class DestIterator, class DestAccessor,
259  class KernelIterator, class KernelAccessor>
260  void convolveImage(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
261  DestIterator dest_ul, DestAccessor dest_acc,
262  KernelIterator ki, KernelAccessor ak,
263  Diff2D kul, Diff2D klr, BorderTreatmentMode border);
264  }
265  \endcode
266  use argument objects in conjunction with \ref ArgumentObjectFactories :
267  \code
268  namespace vigra {
269  // use a different kernel for each axis
270  template <class SrcIterator, class SrcAccessor,
271  class DestIterator, class DestAccessor,
272  class T>
273  void
274  convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
275  pair<DestIterator, DestAccessor> dest,
276  Kernel1D<T> const & kx, Kernel1D<T> const & ky);
277 
278  // use a non-separable 2D kernel
279  template <class SrcIterator, class SrcAccessor,
280  class DestIterator, class DestAccessor,
281  class KernelIterator, class KernelAccessor>
282  void convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
283  pair<DestIterator, DestAccessor> dest,
284  tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D,
285  BorderTreatmentMode> kernel);
286  }
287  \endcode
288  \deprecatedEnd
289 
290  <b> Usage:</b>
291 
292  <b>\#include</b> <vigra/convolution.hxx><br/>
293  Namespace: vigra
294 
295  \code
296  MultiArray<2, float> src(w,h), dest1(w,h), dest2(w,h);
297  ...
298 
299  // create horizontal sobel filter (symmetric difference in x-direction, smoothing in y direction)
300  Kernel1D<double> kx, ky;
301  kx.initSymmetricDifference();
302  ky.initBinomial(1);
303 
304  // calls separable convolution with the two 1D kernels
305  convolveImage(src, dest1, kx, ky);
306 
307  // create a 3x3 Laplacian filter
308  Kernel2D<double> laplace;
309  laplace.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) =
310  0.375, 0.25, 0.375,
311  0.25, -2.5, 0.25,
312  0.375, 0.25, 0.375;
313 
314  // calls 2D convolution
315  convolveImage(src, dest2, laplace);
316  \endcode
317 
318  \deprecatedUsage{convolveImage}
319  \code
320  vigra::FImage src(w,h), dest(w,h);
321  ...
322 
323  // create horizontal sobel filter (symmetric difference in x-direction, smoothing in y direction)
324  Kernel1D<double> kx, ky;
325  kx.initSymmetricDifference();
326  ky.initBinomial(1);
327 
328  // calls separable convolution with the two 1D kernels
329  vigra::convolveImage(srcImageRange(src), destImage(dest), kx, ky);
330 
331  // create a 3x3 Laplacian filter
332  Kernel2D<double> laplace;
333  laplace.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) =
334  0.375, 0.25, 0.375,
335  0.25, -2.5, 0.25,
336  0.375, 0.25, 0.375;
337 
338  // calls 2D convolution
339  vigra::convolveImage(srcImageRange(src), destImage(dest), kernel2d(laplace));
340  \endcode
341  \deprecatedEnd
342 
343  <b> Preconditions:</b>
344 
345  The image must be larger than the kernel radius.
346  <ul>
347  <li>For 1D kernels, <tt>w > std::max(xkernel.right(), -xkernel.keft())</tt> and
348  <tt>h > std::max(ykernel.right(), -ykernel.left())</tt> are required.
349  <li>For 2D kernels, <tt>w > std::max(kernel.lowerRight().x, -kernel.upperLeft().x)</tt> and
350  <tt>h > std::max(kernel.lowerRight().y, -kernel.upperLeft().y)</tt> are required.
351  </ul>
352  If <tt>BORDER_TREATMENT_CLIP</tt> is requested: the sum of kernel elements must be != 0.
353 */
354 doxygen_overloaded_function(template <...> void convolveImage)
355 
356 template <class SrcIterator, class SrcAccessor,
357  class DestIterator, class DestAccessor,
358  class T>
359 void convolveImage(SrcIterator supperleft,
360  SrcIterator slowerright, SrcAccessor sa,
361  DestIterator dupperleft, DestAccessor da,
362  Kernel1D<T> const & kx, Kernel1D<T> const & ky)
363 {
364  typedef typename
365  NumericTraits<typename SrcAccessor::value_type>::RealPromote
366  TmpType;
367  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization);
368 
369  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
370  destImage(tmp), kernel1d(kx));
371  separableConvolveY(srcImageRange(tmp),
372  destIter(dupperleft, da), kernel1d(ky));
373 }
374 
375 template <class SrcIterator, class SrcAccessor,
376  class DestIterator, class DestAccessor,
377  class T>
378 inline void
379 convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
380  pair<DestIterator, DestAccessor> dest,
381  Kernel1D<T> const & kx, Kernel1D<T> const & ky)
382 {
383  convolveImage(src.first, src.second, src.third,
384  dest.first, dest.second, kx, ky);
385 }
386 
387 template <class T1, class S1,
388  class T2, class S2,
389  class T>
390 inline void
391 convolveImage(MultiArrayView<2, T1, S1> const & src,
392  MultiArrayView<2, T2, S2> dest,
393  Kernel1D<T> const & k)
394 {
395  vigra_precondition(src.shape() == dest.shape(),
396  "convolveImage(): shape mismatch between input and output.");
397  convolveImage(srcImageRange(src),
398  destImage(dest), k, k);
399 }
400 
401 template <class T1, class S1,
402  class T2, class S2,
403  class T>
404 inline void
405 convolveImage(MultiArrayView<2, T1, S1> const & src,
406  MultiArrayView<2, T2, S2> dest,
407  Kernel1D<T> const & kx, Kernel1D<T> const & ky)
408 {
409  vigra_precondition(src.shape() == dest.shape(),
410  "convolveImage(): shape mismatch between input and output.");
411  convolveImage(srcImageRange(src),
412  destImage(dest), kx, ky);
413 }
414 
415 /********************************************************/
416 /* */
417 /* simpleSharpening */
418 /* */
419 /********************************************************/
420 
421 /** \brief Perform simple sharpening function.
422 
423  This function uses \ref convolveImage() with the following 3x3 filter:
424 
425  \code
426  -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_factor/16.0,
427  -sharpening_factor/8.0, 1.0+sharpening_factor*0.75, -sharpening_factor/8.0,
428  -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_factor/16.0;
429  \endcode
430 
431  and uses <TT>BORDER_TREATMENT_REFLECT</TT> as border treatment mode.
432 
433  <b> Preconditions:</b>
434  \code
435  1. sharpening_factor >= 0
436  2. scale >= 0
437  \endcode
438 
439  <b> Declarations:</b>
440 
441  pass 2D array views:
442  \code
443  namespace vigra {
444  template <class T1, class S1,
445  class T2, class S2>
446  void
447  simpleSharpening(MultiArrayView<2, T1, S1> const & src,
448  MultiArrayView<2, T2, S2> dest,
449  double sharpening_factor);
450  }
451  \endcode
452 
453  \deprecatedAPI{simpleSharpening}
454  pass \ref ImageIterators and \ref DataAccessors :
455  \code
456  namespace vigra {
457  template <class SrcIterator, class SrcAccessor,
458  class DestIterator, class DestAccessor>
459  void simpleSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
460  DestIterator dest_ul, DestAccessor dest_acc, double sharpening_factor);
461  }
462  \endcode
463  use argument objects in conjunction with \ref ArgumentObjectFactories :
464  \code
465  namespace vigra {
466  template <class SrcIterator, class SrcAccessor,
467  class DestIterator, class DestAccessor>
468  void simpleSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
469  pair<DestIterator, DestAccessor> dest, double sharpening_factor);
470  }
471  \endcode
472  \deprecatedEnd
473 
474  <b> Usage:</b>
475 
476  <b>\#include</b> <vigra/convolution.hxx><br/>
477  Namespace: vigra
478 
479  \code
480  MultiArray<2, float> src(w,h), dest(w,h);
481  ...
482 
483  // sharpening with sharpening_factor = 0.1
484  vigra::simpleSharpening(src, dest, 0.1);
485  \endcode
486 
487  \deprecatedUsage{simpleSharpening}
488  \code
489  vigra::FImage src(w,h), dest(w,h);
490  ...
491 
492  // sharpening with sharpening_factor = 0.1
493  vigra::simpleSharpening(srcImageRange(src), destImage(dest), 0.1);
494 
495  \endcode
496  \deprecatedEnd
497 */
498 doxygen_overloaded_function(template <...> void simpleSharpening)
499 
500 template <class SrcIterator, class SrcAccessor,
501  class DestIterator, class DestAccessor>
502 void simpleSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
503  DestIterator dest_ul, DestAccessor dest_acc, double sharpening_factor)
504 {
505 
506  vigra_precondition(sharpening_factor >= 0.0,
507  "simpleSharpening(): amount of sharpening must be >= 0.");
508 
509  Kernel2D<double> kernel;
510 
511  kernel.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) = -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_factor/16.0,
512  -sharpening_factor/8.0, 1.0+sharpening_factor*0.75, -sharpening_factor/8.0,
513  -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_factor/16.0;
514 
515  convolveImage(src_ul, src_lr, src_acc, dest_ul, dest_acc,
516  kernel.center(), kernel.accessor(),
517  kernel.upperLeft(), kernel.lowerRight() , BORDER_TREATMENT_REFLECT );
518 }
519 
520 template <class SrcIterator, class SrcAccessor,
521  class DestIterator, class DestAccessor>
522 inline
523 void simpleSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
524  pair<DestIterator, DestAccessor> dest, double sharpening_factor)
525 {
526  simpleSharpening(src.first, src.second, src.third,
527  dest.first, dest.second, sharpening_factor);
528 }
529 
530 template <class T1, class S1,
531  class T2, class S2>
532 inline void
533 simpleSharpening(MultiArrayView<2, T1, S1> const & src,
534  MultiArrayView<2, T2, S2> dest,
535  double sharpening_factor)
536 {
537  vigra_precondition(src.shape() == dest.shape(),
538  "simpleSharpening(): shape mismatch between input and output.");
539  simpleSharpening(srcImageRange(src),
540  destImage(dest), sharpening_factor);
541 }
542 
543 
544 /********************************************************/
545 /* */
546 /* gaussianSharpening */
547 /* */
548 /********************************************************/
549 
550 /** \brief Perform sharpening function with gaussian filter.
551 
552 
553  This function uses \ref gaussianSmoothing() at the given scale to create a
554  temporary image 'smooth' and than blends the original and smoothed image
555  according to the formula
556 
557  \code
558  dest = (1 + sharpening_factor)*src - sharpening_factor*smooth
559  \endcode
560 
561  <b> Preconditions:</b>
562  \code
563  1. sharpening_factor >= 0
564  2. scale >= 0
565  \endcode
566 
567  <b> Declarations:</b>
568 
569  pass 2D array views:
570  \code
571  namespace vigra {
572  template <class T1, class S1,
573  class T2, class S2>
574  void
575  gaussianSharpening(MultiArrayView<2, T1, S1> const & src,
576  MultiArrayView<2, T2, S2> dest,
577  double sharpening_factor,
578  double scale);
579  }
580  \endcode
581 
582  \deprecatedAPI{gaussianSharpening}
583  pass \ref ImageIterators and \ref DataAccessors :
584  \code
585  namespace vigra {
586  template <class SrcIterator, class SrcAccessor,
587  class DestIterator, class DestAccessor>
588  void gaussianSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
589  DestIterator dest_ul, DestAccessor dest_acc,
590  double sharpening_factor, double scale)
591  }
592  \endcode
593  use argument objects in conjunction with \ref ArgumentObjectFactories :
594  \code
595  namespace vigra {
596  template <class SrcIterator, class SrcAccessor,
597  class DestIterator, class DestAccessor>
598  void gaussianSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
599  pair<DestIterator, DestAccessor> dest,
600  double sharpening_factor, double scale)
601  }
602  \endcode
603  \deprecatedEnd
604 
605  <b> Usage:</b>
606 
607  <b>\#include</b> <vigra/convolution.hxx><br/>
608  Namespace: vigra
609 
610  \code
611  MultiArray<2, float> src(w,h), dest(w,h);
612  ...
613 
614  // sharpening with sharpening_factor = 3.0
615  // smoothing with scale = 0.5
616  gaussianSharpening(src, dest, 3.0, 0.5);
617  \endcode
618 
619  \deprecatedUsage{gaussianSharpening}
620  \code
621  vigra::FImage src(w,h), dest(w,h);
622  ...
623 
624  // sharpening with sharpening_factor = 3.0
625  // smoothing with scale = 0.5
626  vigra::gaussianSharpening(srcImageRange(src), destImage(dest), 3.0, 0.5);
627  \endcode
628  \deprecatedEnd
629 */
630 doxygen_overloaded_function(template <...> void gaussianSharpening)
631 
632 template <class SrcIterator, class SrcAccessor,
633  class DestIterator, class DestAccessor>
634 void gaussianSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
635  DestIterator dest_ul, DestAccessor dest_acc, double sharpening_factor,
636  double scale)
637 {
638  vigra_precondition(sharpening_factor >= 0.0,
639  "gaussianSharpening(): amount of sharpening must be >= 0");
640  vigra_precondition(scale >= 0.0,
641  "gaussianSharpening(): scale parameter should be >= 0.");
642 
643  typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote ValueType;
644 
645  BasicImage<ValueType> tmp(src_lr - src_ul, SkipInitialization);
646 
647  gaussianSmoothing(src_ul, src_lr, src_acc, tmp.upperLeft(), tmp.accessor(), scale);
648 
649  SrcIterator i_src = src_ul;
650  DestIterator i_dest = dest_ul;
651  typename BasicImage<ValueType>::traverser tmp_ul = tmp.upperLeft();
652  typename BasicImage<ValueType>::traverser i_tmp = tmp_ul;
653  typename BasicImage<ValueType>::Accessor tmp_acc = tmp.accessor();
654 
655  for(; i_src.y != src_lr.y ; i_src.y++, i_dest.y++, i_tmp.y++ )
656  {
657  for (;i_src.x != src_lr.x ; i_src.x++, i_dest.x++, i_tmp.x++ )
658  {
659  dest_acc.set((1.0 + sharpening_factor)*src_acc(i_src) - sharpening_factor*tmp_acc(i_tmp), i_dest);
660  }
661  i_src.x = src_ul.x;
662  i_dest.x = dest_ul.x;
663  i_tmp.x = tmp_ul.x;
664  }
665 }
666 
667 template <class SrcIterator, class SrcAccessor,
668  class DestIterator, class DestAccessor>
669 inline void
670 gaussianSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
671  pair<DestIterator, DestAccessor> dest, double sharpening_factor,
672  double scale)
673 {
674  gaussianSharpening(src.first, src.second, src.third,
675  dest.first, dest.second,
676  sharpening_factor, scale);
677 }
678 
679 template <class T1, class S1,
680  class T2, class S2>
681 inline void
682 gaussianSharpening(MultiArrayView<2, T1, S1> const & src,
683  MultiArrayView<2, T2, S2> dest,
684  double sharpening_factor,
685  double scale)
686 {
687  vigra_precondition(src.shape() == dest.shape(),
688  "gaussianSharpening(): shape mismatch between input and output.");
689  gaussianSharpening(srcImageRange(src),
690  destImage(dest),
691  sharpening_factor, scale);
692 }
693 
694 
695 
696 /********************************************************/
697 /* */
698 /* gaussianSmoothing */
699 /* */
700 /********************************************************/
701 
702 /** \brief Perform isotropic Gaussian convolution.
703 
704  This function is a shorthand for the concatenation of a call to
705  \ref separableConvolveX() and \ref separableConvolveY() with a
706  Gaussian kernel of the given scale. If two scales are provided,
707  smoothing in x and y direction will have different strength.
708  The function uses <TT>BORDER_TREATMENT_REFLECT</TT>.
709 
710  Function \ref gaussianSmoothMultiArray() performs the same filter operation
711  on arbitrary dimensional arrays.
712 
713  <b> Declarations:</b>
714 
715  pass 2D array views:
716  \code
717  namespace vigra {
718  template <class T1, class S1,
719  class T2, class S2>
720  void
721  gaussianSmoothing(MultiArrayView<2, T1, S1> const & src,
722  MultiArrayView<2, T2, S2> dest,
723  double scale_x, double scale_y = scale_x);
724  }
725  \endcode
726 
727  \deprecatedAPI{gaussianSmoothing}
728  pass \ref ImageIterators and \ref DataAccessors :
729  \code
730  namespace vigra {
731  template <class SrcIterator, class SrcAccessor,
732  class DestIterator, class DestAccessor>
733  void gaussianSmoothing(SrcIterator supperleft,
734  SrcIterator slowerright, SrcAccessor sa,
735  DestIterator dupperleft, DestAccessor da,
736  double scale_x, double scale_y = scale_x);
737  }
738  \endcode
739  use argument objects in conjunction with \ref ArgumentObjectFactories :
740  \code
741  namespace vigra {
742  template <class SrcIterator, class SrcAccessor,
743  class DestIterator, class DestAccessor>
744  void
745  gaussianSmoothing(triple<SrcIterator, SrcIterator, SrcAccessor> src,
746  pair<DestIterator, DestAccessor> dest,
747  double scale_x, double scale_y = scale_x);
748  }
749  \endcode
750  \deprecatedEnd
751 
752  <b> Usage:</b>
753 
754  <b>\#include</b> <vigra/convolution.hxx><br/>
755  Namespace: vigra
756 
757  \code
758  MultiArray<2, float> src(w,h), dest(w,h);
759  ...
760 
761  // smooth with scale = 3.0
762  gaussianSmoothing(src, dest, 3.0);
763  \endcode
764 
765  \deprecatedUsage{gaussianSmoothing}
766  \code
767  vigra::FImage src(w,h), dest(w,h);
768  ...
769 
770  // smooth with scale = 3.0
771  vigra::gaussianSmoothing(srcImageRange(src), destImage(dest), 3.0);
772  \endcode
773  \deprecatedEnd
774 */
775 doxygen_overloaded_function(template <...> void gaussianSmoothing)
776 
777 template <class SrcIterator, class SrcAccessor,
778  class DestIterator, class DestAccessor>
779 void
780 gaussianSmoothing(SrcIterator supperleft, SrcIterator slowerright, SrcAccessor sa,
781  DestIterator dupperleft, DestAccessor da,
782  double scale_x, double scale_y)
783 {
784  typedef typename
785  NumericTraits<typename SrcAccessor::value_type>::RealPromote
786  TmpType;
787  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization);
788 
789  Kernel1D<double> smooth_x, smooth_y;
790  smooth_x.initGaussian(scale_x);
791  smooth_x.setBorderTreatment(BORDER_TREATMENT_REFLECT);
792  smooth_y.initGaussian(scale_y);
793  smooth_y.setBorderTreatment(BORDER_TREATMENT_REFLECT);
794 
795  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
796  destImage(tmp), kernel1d(smooth_x));
797  separableConvolveY(srcImageRange(tmp),
798  destIter(dupperleft, da), kernel1d(smooth_y));
799 }
800 
801 template <class SrcIterator, class SrcAccessor,
802  class DestIterator, class DestAccessor>
803 inline void
804 gaussianSmoothing(SrcIterator supperleft, SrcIterator slowerright, SrcAccessor sa,
805  DestIterator dupperleft, DestAccessor da,
806  double scale)
807 {
808  gaussianSmoothing(supperleft, slowerright, sa,
809  dupperleft, da,
810  scale, scale);
811 }
812 
813 template <class SrcIterator, class SrcAccessor,
814  class DestIterator, class DestAccessor>
815 inline void
816 gaussianSmoothing(triple<SrcIterator, SrcIterator, SrcAccessor> src,
817  pair<DestIterator, DestAccessor> dest,
818  double scale_x, double scale_y)
819 {
820  gaussianSmoothing(src.first, src.second, src.third,
821  dest.first, dest.second, scale_x, scale_y);
822 }
823 
824 template <class SrcIterator, class SrcAccessor,
825  class DestIterator, class DestAccessor>
826 inline void
827 gaussianSmoothing(triple<SrcIterator, SrcIterator, SrcAccessor> src,
828  pair<DestIterator, DestAccessor> dest,
829  double scale)
830 {
831  gaussianSmoothing(src.first, src.second, src.third,
832  dest.first, dest.second, scale, scale);
833 }
834 
835 template <class T1, class S1,
836  class T2, class S2>
837 inline void
838 gaussianSmoothing(MultiArrayView<2, T1, S1> const & src,
839  MultiArrayView<2, T2, S2> dest,
840  double scale_x, double scale_y)
841 {
842  vigra_precondition(src.shape() == dest.shape(),
843  "gaussianSmoothing(): shape mismatch between input and output.");
844  gaussianSmoothing(srcImageRange(src),
845  destImage(dest), scale_x, scale_y);
846 }
847 
848 template <class T1, class S1,
849  class T2, class S2>
850 inline void
851 gaussianSmoothing(MultiArrayView<2, T1, S1> const & src,
852  MultiArrayView<2, T2, S2> dest,
853  double scale)
854 {
855  vigra_precondition(src.shape() == dest.shape(),
856  "gaussianSmoothing(): shape mismatch between input and output.");
857  gaussianSmoothing(srcImageRange(src),
858  destImage(dest), scale, scale);
859 }
860 
861 /********************************************************/
862 /* */
863 /* gaussianGradient */
864 /* */
865 /********************************************************/
866 
867 /** \brief Calculate the gradient vector by means of a 1st derivatives of
868  Gaussian filter.
869 
870  This function is a shorthand for the concatenation of a call to
871  \ref separableConvolveX() and \ref separableConvolveY() with the
872  appropriate kernels at the given scale. Note that this function can either produce
873  two separate result images for the x- and y-components of the gradient, or write
874  into a vector valued image (with at least two components).
875 
876  Function \ref gaussianGradientMultiArray() performs the same filter operation
877  on arbitrary dimensional arrays.
878 
879  <b> Declarations:</b>
880 
881  pass 2D array views:
882  \code
883  namespace vigra {
884  // write x and y component of the gradient into separate images
885  template <class T1, class S1,
886  class T2X, class S2X,
887  class T2Y, class S2Y>
888  void
889  gaussianGradient(MultiArrayView<2, T1, S1> const & src,
890  MultiArrayView<2, T2X, S2X> destx,
891  MultiArrayView<2, T2Y, S2Y> desty,
892  double scale);
893 
894  // write x and y component of the gradient into a vector-valued image
895  template <class T1, class S1,
896  class T2, class S2>
897  void
898  gaussianGradient(MultiArrayView<2, T1, S1> const & src,
899  MultiArrayView<2, TinyVector<T2, 2>, S2> dest,
900  double scale);
901  }
902  \endcode
903 
904  \deprecatedAPI{gaussianGradient}
905  pass \ref ImageIterators and \ref DataAccessors :
906  \code
907  namespace vigra {
908  // write x and y component of the gradient into separate images
909  template <class SrcIterator, class SrcAccessor,
910  class DestIteratorX, class DestAccessorX,
911  class DestIteratorY, class DestAccessorY>
912  void gaussianGradient(SrcIterator supperleft,
913  SrcIterator slowerright, SrcAccessor sa,
914  DestIteratorX dupperleftx, DestAccessorX dax,
915  DestIteratorY dupperlefty, DestAccessorY day,
916  double scale);
917 
918  // write x and y component of the gradient into a vector-valued image
919  template <class SrcIterator, class SrcAccessor,
920  class DestIterator, class DestAccessor>
921  void gaussianGradient(SrcIterator supperleft,
922  SrcIterator slowerright, SrcAccessor src,
923  DestIterator dupperleft, DestAccessor dest,
924  double scale);
925  }
926  \endcode
927  use argument objects in conjunction with \ref ArgumentObjectFactories :
928  \code
929  namespace vigra {
930  // write x and y component of the gradient into separate images
931  template <class SrcIterator, class SrcAccessor,
932  class DestIteratorX, class DestAccessorX,
933  class DestIteratorY, class DestAccessorY>
934  void
935  gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src,
936  pair<DestIteratorX, DestAccessorX> destx,
937  pair<DestIteratorY, DestAccessorY> desty,
938  double scale);
939 
940  // write x and y component of the gradient into a vector-valued image
941  template <class SrcIterator, class SrcAccessor,
942  class DestIterator, class DestAccessor>
943  void
944  gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src,
945  pair<DestIterator, DestAccessor> dest,
946  double scale);
947  }
948  \endcode
949  \deprecatedEnd
950 
951  <b> Usage:</b>
952 
953  <b>\#include</b> <vigra/convolution.hxx><br/>
954  Namespace: vigra
955 
956  \code
957  MultiArray<2, float> src(w,h), gradx(w,h), grady(w,h);
958  ...
959 
960  // calculate gradient vector at scale = 3.0
961  gaussianGradient(src, gradx, grady, 3.0);
962 
963  // likewise, but use a vector image to store the gradient
964  MultiArray<2, TinyVector<float, 2> > dest(w,h);
965  gaussianGradient(src, dest, 3.0);
966  \endcode
967 
968  \deprecatedUsage{gaussianGradient}
969  \code
970  vigra::FImage src(w,h), gradx(w,h), grady(w,h);
971  ...
972 
973  // calculate gradient vector at scale = 3.0
974  vigra::gaussianGradient(srcImageRange(src),
975  destImage(gradx), destImage(grady), 3.0);
976  \endcode
977  \deprecatedEnd
978 */
979 doxygen_overloaded_function(template <...> void gaussianGradient)
980 
981 template <class SrcIterator, class SrcAccessor,
982  class DestIteratorX, class DestAccessorX,
983  class DestIteratorY, class DestAccessorY>
984 void gaussianGradient(SrcIterator supperleft,
985  SrcIterator slowerright, SrcAccessor sa,
986  DestIteratorX dupperleftx, DestAccessorX dax,
987  DestIteratorY dupperlefty, DestAccessorY day,
988  double scale)
989 {
990  typedef typename
991  NumericTraits<typename SrcAccessor::value_type>::RealPromote
992  TmpType;
993  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization);
994 
995  Kernel1D<double> smooth, grad;
996  smooth.initGaussian(scale);
997  grad.initGaussianDerivative(scale, 1);
998 
999  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1000  destImage(tmp), kernel1d(grad));
1001  separableConvolveY(srcImageRange(tmp),
1002  destIter(dupperleftx, dax), kernel1d(smooth));
1003  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1004  destImage(tmp), kernel1d(smooth));
1005  separableConvolveY(srcImageRange(tmp),
1006  destIter(dupperlefty, day), kernel1d(grad));
1007 }
1008 
1009 template <class SrcIterator, class SrcAccessor,
1010  class DestIterator, class DestAccessor>
1011 void gaussianGradient(SrcIterator supperleft,
1012  SrcIterator slowerright, SrcAccessor src,
1013  DestIterator dupperleft, DestAccessor dest,
1014  double scale)
1015 {
1016  VectorElementAccessor<DestAccessor> gradx(0, dest), grady(1, dest);
1017  gaussianGradient(supperleft, slowerright, src,
1018  dupperleft, gradx, dupperleft, grady, scale);
1019 }
1020 
1021 template <class SrcIterator, class SrcAccessor,
1022  class DestIteratorX, class DestAccessorX,
1023  class DestIteratorY, class DestAccessorY>
1024 inline void
1025 gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1026  pair<DestIteratorX, DestAccessorX> destx,
1027  pair<DestIteratorY, DestAccessorY> desty,
1028  double scale)
1029 {
1030  gaussianGradient(src.first, src.second, src.third,
1031  destx.first, destx.second, desty.first, desty.second, scale);
1032 }
1033 
1034 template <class SrcIterator, class SrcAccessor,
1035  class DestIterator, class DestAccessor>
1036 inline void
1037 gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1038  pair<DestIterator, DestAccessor> dest,
1039  double scale)
1040 {
1041  gaussianGradient(src.first, src.second, src.third,
1042  dest.first, dest.second, scale);
1043 }
1044 
1045 template <class T1, class S1,
1046  class T2X, class S2X,
1047  class T2Y, class S2Y>
1048 inline void
1049 gaussianGradient(MultiArrayView<2, T1, S1> const & src,
1050  MultiArrayView<2, T2X, S2X> destx,
1051  MultiArrayView<2, T2Y, S2Y> desty,
1052  double scale)
1053 {
1054  vigra_precondition(src.shape() == destx.shape(),
1055  "gaussianGradient(): shape mismatch between input and output.");
1056  gaussianGradient(srcImageRange(src),
1057  destImage(destx), destImage(desty), scale);
1058 }
1059 
1060 template <class T1, class S1,
1061  class T2, class S2>
1062 inline void
1063 gaussianGradient(MultiArrayView<2, T1, S1> const & src,
1064  MultiArrayView<2, TinyVector<T2, 2>, S2> dest,
1065  double scale)
1066 {
1067  vigra_precondition(src.shape() == dest.shape(),
1068  "gaussianGradient(): shape mismatch between input and output.");
1069  gaussianGradient(srcImageRange(src),
1070  destImage(dest), scale);
1071 }
1072 
1073 /** \brief Calculate the gradient magnitude by means of a 1st derivatives of
1074  Gaussian filter.
1075 
1076  This function calls gaussianGradient() and returns the pixel-wise magnitude of
1077  the resulting gradient vectors. If the original image has multiple bands,
1078  the squared gradient magnitude is computed for each band separately, and the
1079  return value is the square root of the sum of these squared magnitudes.
1080 
1081  <b> Declarations:</b>
1082 
1083  use arbitrary-dimensional arrays:
1084  \code
1085  namespace vigra {
1086  // pass filter scale explicitly
1087  template <unsigned int N, class T1, class S1,
1088  class T2, class S2>
1089  void
1090  gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
1091  MultiArrayView<N, T2, S2> dest,
1092  double sigma,
1093  ConvolutionOptions<N> opt = ConvolutionOptions<N>());
1094 
1095  template <unsigned int N, class MT, class S1,
1096  class T2, class S2>
1097  void
1098  gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<MT>, S1> const & src,
1099  MultiArrayView<N, T2, S2> dest,
1100  double sigma,
1101  ConvolutionOptions<N> opt = ConvolutionOptions<N>());
1102 
1103  // pass filter scale(s) in option object
1104  template <unsigned int N, class T1, class S1,
1105  class T2, class S2>
1106  void
1107  gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
1108  MultiArrayView<N, T2, S2> dest,
1109  ConvolutionOptions<N> const & opt);
1110 
1111  template <unsigned int N, class MT, class S1,
1112  class T2, class S2>
1113  void
1114  gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<MT>, S1> const & src,
1115  MultiArrayView<N, T2, S2> dest,
1116  ConvolutionOptions<N> const & opt);
1117  }
1118  \endcode
1119  Here, the input element types <tt>T1</tt> and <tt>MT</tt> can be arbitrary scalar types, and <tt>T1</tt>
1120  may also be <tt>TinyVector</tt> or <tt>RGBValue</tt>. The output element type <tt>T2</tt> should
1121  be the corresponding norm type (see \ref NormTraits "NormTraits"). In the <tt>Multiband<MT></tt>-version,
1122  the input array's right-most dimension is interpreted as a channel axis, therefore it must
1123  have one dimension more than the output array.
1124 
1125  \deprecatedAPI{gaussianGradientMagnitude}
1126  pass \ref ImageIterators and \ref DataAccessors :
1127  \code
1128  namespace vigra {
1129  template <class SrcIterator, class SrcAccessor,
1130  class DestIterator, class DestAccessor>
1131  void gaussianGradientMagnitude(SrcIterator sul,
1132  SrcIterator slr, SrcAccessor src,
1133  DestIterator dupperleft, DestAccessor dest,
1134  double scale);
1135  }
1136  \endcode
1137  use argument objects in conjunction with \ref ArgumentObjectFactories :
1138  \code
1139  namespace vigra {
1140  template <class SrcIterator, class SrcAccessor,
1141  class DestIterator, class DestAccessor>
1142  void
1143  gaussianGradientMagnitude(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1144  pair<DestIterator, DestAccessor> dest,
1145  double scale);
1146  }
1147  \endcode
1148  \deprecatedEnd
1149 
1150  <b> Usage:</b>
1151 
1152  <b>\#include</b> <vigra/convolution.hxx><br/>
1153  Namespace: vigra
1154 
1155  \code
1156  // example 1
1157  {
1158  // use a 3-dimensional float array
1159  MultiArray<3, float> volume(Shape3(w, h, d)), grad(volume.shape());
1160  ...
1161 
1162  // calculate gradient magnitude at scale = 3.0
1163  gaussianGradientMagnitude(volume, grad, 3.0);
1164  }
1165 
1166  // example 2
1167  {
1168  // use a 2-dimensional RGB array
1169  MultiArray<2, RGBValue<float> > rgb(Shape2(w, h));
1170  MultiArray<2, float> grad(rgb.shape());
1171  ...
1172 
1173  // calculate the color gradient magnitude at scale = 3.0
1174  gaussianGradientMagnitude(rgb, grad, 3.0);
1175  }
1176 
1177  // example 3
1178  {
1179  // use a 3-dimensional array whose right-most axis is interpreted as
1180  // a multi-spectral axis with arbitrary many channels
1181  MultiArray<3, Multiband<float> > spectral(Shape3(w, h, channelCount));
1182  MultiArray<2, float> grad(Shape2(w, h));
1183  ...
1184 
1185  // calculate the multi-channel gradient magnitude at scale = 3.0
1186  // (note that the template parameter N (number of spatial dimensions)
1187  // must be provided explicitly as gaussianGradientMagnitude<2>(...) )
1188  MultiArrayView<3, Multiband<float> > view(spectral);
1189  gaussianGradientMagnitude<2>(view, grad, 3.0);
1190  }
1191  \endcode
1192 
1193  \deprecatedUsage{gaussianGradientMagnitude}
1194  \code
1195  // use a traditional float or RGB image
1196  FImage image(w, h), grad(w, h);
1197  FRGBImage rgb(w, h);
1198  ...
1199 
1200  // calculate gradient magnitude at scale = 3.0
1201  gaussianGradientMagnitude(srcImageRange(image), destImage(grad), 3.0);
1202 
1203  // calculate color gradient magnitude at scale = 3.0
1204  gaussianGradientMagnitude(srcImageRange(rgb), destImage(grad), 3.0);
1205  \endcode
1206  \deprecatedEnd
1207 */
1208 doxygen_overloaded_function(template <...> void gaussianGradientMagnitude)
1209 
1210 template <class SrcIterator, class SrcAccessor,
1211  class DestIterator, class DestAccessor>
1212 void gaussianGradientMagnitude(SrcIterator sul,
1213  SrcIterator slr, SrcAccessor src,
1214  DestIterator dupperleft, DestAccessor dest,
1215  double scale)
1216 {
1217  typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
1218  BasicImage<TmpType> gradx(slr-sul, SkipInitialization), grady(slr-sul, SkipInitialization);
1219 
1220  gaussianGradient(srcIterRange(sul, slr, src),
1221  destImage(gradx), destImage(grady), scale);
1222  combineTwoImages(srcImageRange(gradx), srcImage(grady), destIter(dupperleft, dest),
1223  MagnitudeFunctor<TmpType>());
1224 }
1225 
1226 template <class SrcIterator, class SrcAccessor,
1227  class DestIterator, class DestAccessor>
1228 inline void
1229 gaussianGradientMagnitude(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1230  pair<DestIterator, DestAccessor> dest,
1231  double scale)
1232 {
1233  gaussianGradientMagnitude(src.first, src.second, src.third,
1234  dest.first, dest.second, scale);
1235 }
1236 
1237 /********************************************************/
1238 /* */
1239 /* laplacianOfGaussian */
1240 /* */
1241 /********************************************************/
1242 
1243 /** \brief Filter image with the Laplacian of Gaussian operator
1244  at the given scale.
1245 
1246  This function calls \ref separableConvolveX() and \ref separableConvolveY() with the appropriate 2nd derivative
1247  of Gaussian kernels in x- and y-direction and then sums the results
1248  to get the Laplacian.
1249 
1250  Function \ref laplacianOfGaussianMultiArray() performs the same filter operation
1251  on arbitrary dimensional arrays.
1252 
1253  <b> Declarations:</b>
1254 
1255  pass 2D array views:
1256  \code
1257  namespace vigra {
1258  template <class T1, class S1,
1259  class T2, class S2>
1260  void
1261  laplacianOfGaussian(MultiArrayView<2, T1, S1> const & src,
1262  MultiArrayView<2, T2, S2> dest,
1263  double scale);
1264  }
1265  \endcode
1266 
1267  \deprecatedAPI{laplacianOfGaussian}
1268  pass \ref ImageIterators and \ref DataAccessors :
1269  \code
1270  namespace vigra {
1271  template <class SrcIterator, class SrcAccessor,
1272  class DestIterator, class DestAccessor>
1273  void laplacianOfGaussian(SrcIterator supperleft,
1274  SrcIterator slowerright, SrcAccessor sa,
1275  DestIterator dupperleft, DestAccessor da,
1276  double scale);
1277  }
1278  \endcode
1279  use argument objects in conjunction with \ref ArgumentObjectFactories :
1280  \code
1281  namespace vigra {
1282  template <class SrcIterator, class SrcAccessor,
1283  class DestIterator, class DestAccessor>
1284  void
1285  laplacianOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1286  pair<DestIterator, DestAccessor> dest,
1287  double scale);
1288  }
1289  \endcode
1290  \deprecatedEnd
1291 
1292  <b> Usage:</b>
1293 
1294  <b>\#include</b> <vigra/convolution.hxx><br/>
1295  Namespace: vigra
1296 
1297  \code
1298  MultiArray<2, float> src(w,h), dest(w,h);
1299  ...
1300 
1301  // calculate Laplacian of Gaussian at scale = 3.0
1302  laplacianOfGaussian(src, dest, 3.0);
1303  \endcode
1304 
1305  \deprecatedUsage{laplacianOfGaussian}
1306  \code
1307  vigra::FImage src(w,h), dest(w,h);
1308  ...
1309 
1310  // calculate Laplacian of Gaussian at scale = 3.0
1311  vigra::laplacianOfGaussian(srcImageRange(src), destImage(dest), 3.0);
1312  \endcode
1313  \deprecatedEnd
1314 */
1315 doxygen_overloaded_function(template <...> void laplacianOfGaussian)
1316 
1317 template <class SrcIterator, class SrcAccessor,
1318  class DestIterator, class DestAccessor>
1319 void laplacianOfGaussian(SrcIterator supperleft,
1320  SrcIterator slowerright, SrcAccessor sa,
1321  DestIterator dupperleft, DestAccessor da,
1322  double scale)
1323 {
1324  typedef typename
1325  NumericTraits<typename SrcAccessor::value_type>::RealPromote
1326  TmpType;
1327  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization),
1328  tmpx(slowerright - supperleft, SkipInitialization),
1329  tmpy(slowerright - supperleft, SkipInitialization);
1330 
1331  Kernel1D<double> smooth, deriv;
1332  smooth.initGaussian(scale);
1333  deriv.initGaussianDerivative(scale, 2);
1334 
1335  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1336  destImage(tmp), kernel1d(deriv));
1337  separableConvolveY(srcImageRange(tmp),
1338  destImage(tmpx), kernel1d(smooth));
1339  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1340  destImage(tmp), kernel1d(smooth));
1341  separableConvolveY(srcImageRange(tmp),
1342  destImage(tmpy), kernel1d(deriv));
1343  combineTwoImages(srcImageRange(tmpx), srcImage(tmpy),
1344  destIter(dupperleft, da), std::plus<TmpType>());
1345 }
1346 
1347 template <class SrcIterator, class SrcAccessor,
1348  class DestIterator, class DestAccessor>
1349 inline void
1350 laplacianOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1351  pair<DestIterator, DestAccessor> dest,
1352  double scale)
1353 {
1354  laplacianOfGaussian(src.first, src.second, src.third,
1355  dest.first, dest.second, scale);
1356 }
1357 
1358 template <class T1, class S1,
1359  class T2, class S2>
1360 inline void
1361 laplacianOfGaussian(MultiArrayView<2, T1, S1> const & src,
1362  MultiArrayView<2, T2, S2> dest,
1363  double scale)
1364 {
1365  vigra_precondition(src.shape() == dest.shape(),
1366  "laplacianOfGaussian(): shape mismatch between input and output.");
1367  laplacianOfGaussian(srcImageRange(src),
1368  destImage(dest), scale);
1369 }
1370 
1371 /********************************************************/
1372 /* */
1373 /* hessianMatrixOfGaussian */
1374 /* */
1375 /********************************************************/
1376 
1377 /** \brief Filter image with the 2nd derivatives of the Gaussian
1378  at the given scale to get the Hessian matrix.
1379 
1380  The Hessian matrix is a symmetric matrix defined as:
1381 
1382  \f[
1383  \mbox{\rm Hessian}(I) = \left(
1384  \begin{array}{cc}
1385  G_{xx} \ast I & G_{xy} \ast I \\
1386  G_{xy} \ast I & G_{yy} \ast I
1387  \end{array} \right)
1388  \f]
1389 
1390  where \f$G_{xx}, G_{xy}, G_{yy}\f$ denote 2nd derivatives of Gaussians
1391  at the given scale, and
1392  \f$\ast\f$ is the convolution symbol. This function calls
1393  \ref separableConvolveX() and \ref separableConvolveY()
1394  with the appropriate 2nd derivative
1395  of Gaussian kernels and puts the results in
1396  the three destination images. The first destination image will
1397  contain the second derivative in x-direction, the second one the mixed
1398  derivative, and the third one holds the derivative in y-direction.
1399 
1400  Function \ref hessianOfGaussianMultiArray() performs the same filter operation
1401  on arbitrary dimensional arrays.
1402 
1403  <b> Declarations:</b>
1404 
1405  pass 2D array views:
1406  \code
1407  namespace vigra {
1408  template <class T1, class S1,
1409  class T2, class S2>
1410  void
1411  hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
1412  MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
1413  double scale);
1414  }
1415  \endcode
1416 
1417  \deprecatedAPI{hessianMatrixOfGaussian}
1418  pass \ref ImageIterators and \ref DataAccessors :
1419  \code
1420  namespace vigra {
1421  template <class SrcIterator, class SrcAccessor,
1422  class DestIteratorX, class DestAccessorX,
1423  class DestIteratorXY, class DestAccessorXY,
1424  class DestIteratorY, class DestAccessorY>
1425  void hessianMatrixOfGaussian(SrcIterator supperleft,
1426  SrcIterator slowerright, SrcAccessor sa,
1427  DestIteratorX dupperleftx, DestAccessorX dax,
1428  DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1429  DestIteratorY dupperlefty, DestAccessorY day,
1430  double scale);
1431  }
1432  \endcode
1433  use argument objects in conjunction with \ref ArgumentObjectFactories :
1434  \code
1435  namespace vigra {
1436  template <class SrcIterator, class SrcAccessor,
1437  class DestIteratorX, class DestAccessorX,
1438  class DestIteratorXY, class DestAccessorXY,
1439  class DestIteratorY, class DestAccessorY>
1440  void
1441  hessianMatrixOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1442  pair<DestIteratorX, DestAccessorX> destx,
1443  pair<DestIteratorXY, DestAccessorXY> destxy,
1444  pair<DestIteratorY, DestAccessorY> desty,
1445  double scale);
1446  }
1447  \endcode
1448  \deprecatedEnd
1449 
1450  <b> Usage:</b>
1451 
1452  <b>\#include</b> <vigra/convolution.hxx><br/>
1453  Namespace: vigra
1454 
1455  \code
1456  MultiArray<2, float> src(w,h);
1457  MultiArray<2, TinyVector<float, 3> > hessian(w,h); // will hold the three components of the Hessian
1458  ...
1459 
1460  // calculate Hessian of Gaussian at scale = 3.0, use a 3-band output image
1461  hessianMatrixOfGaussian(src, hessian, 3.0);
1462  \endcode
1463 
1464  \deprecatedUsage{hessianMatrixOfGaussian}
1465  \code
1466  vigra::FImage src(w,h),
1467  hxx(w,h), hxy(w,h), hyy(w,h); // use a separate image for each component of the Hessian
1468  ...
1469 
1470  // calculate Hessian of Gaussian at scale = 3.0, use 3 single.band output images
1471  vigra::hessianMatrixOfGaussian(srcImageRange(src),
1472  destImage(hxx), destImage(hxy), destImage(hyy), 3.0);
1473  \endcode
1474  \deprecatedEnd
1475 */
1476 doxygen_overloaded_function(template <...> void hessianMatrixOfGaussian)
1477 
1478 template <class SrcIterator, class SrcAccessor,
1479  class DestIteratorX, class DestAccessorX,
1480  class DestIteratorXY, class DestAccessorXY,
1481  class DestIteratorY, class DestAccessorY>
1482 void hessianMatrixOfGaussian(SrcIterator supperleft,
1483  SrcIterator slowerright, SrcAccessor sa,
1484  DestIteratorX dupperleftx, DestAccessorX dax,
1485  DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1486  DestIteratorY dupperlefty, DestAccessorY day,
1487  double scale)
1488 {
1489  typedef typename
1490  NumericTraits<typename SrcAccessor::value_type>::RealPromote
1491  TmpType;
1492  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization);
1493 
1494  Kernel1D<double> smooth, deriv1, deriv2;
1495  smooth.initGaussian(scale);
1496  deriv1.initGaussianDerivative(scale, 1);
1497  deriv2.initGaussianDerivative(scale, 2);
1498 
1499  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1500  destImage(tmp), kernel1d(deriv2));
1501  separableConvolveY(srcImageRange(tmp),
1502  destIter(dupperleftx, dax), kernel1d(smooth));
1503  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1504  destImage(tmp), kernel1d(smooth));
1505  separableConvolveY(srcImageRange(tmp),
1506  destIter(dupperlefty, day), kernel1d(deriv2));
1507  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1508  destImage(tmp), kernel1d(deriv1));
1509  separableConvolveY(srcImageRange(tmp),
1510  destIter(dupperleftxy, daxy), kernel1d(deriv1));
1511 }
1512 
1513 template <class SrcIterator, class SrcAccessor,
1514  class DestIteratorX, class DestAccessorX,
1515  class DestIteratorXY, class DestAccessorXY,
1516  class DestIteratorY, class DestAccessorY>
1517 inline void
1518 hessianMatrixOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1519  pair<DestIteratorX, DestAccessorX> destx,
1520  pair<DestIteratorXY, DestAccessorXY> destxy,
1521  pair<DestIteratorY, DestAccessorY> desty,
1522  double scale)
1523 {
1524  hessianMatrixOfGaussian(src.first, src.second, src.third,
1525  destx.first, destx.second,
1526  destxy.first, destxy.second,
1527  desty.first, desty.second,
1528  scale);
1529 }
1530 
1531 template <class T1, class S1,
1532  class T2X, class S2X,
1533  class T2XY, class S2XY,
1534  class T2Y, class S2Y>
1535 inline void
1536 hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
1537  MultiArrayView<2, T2X, S2X> destx,
1538  MultiArrayView<2, T2XY, S2XY> destxy,
1539  MultiArrayView<2, T2Y, S2Y> desty,
1540  double scale)
1541 {
1542  vigra_precondition(src.shape() == destx.shape() && src.shape() == destxy.shape() && src.shape() == desty.shape(),
1543  "hessianMatrixOfGaussian(): shape mismatch between input and output.");
1544  hessianMatrixOfGaussian(srcImageRange(src),
1545  destImage(destx),
1546  destImage(destxy),
1547  destImage(desty),
1548  scale);
1549 }
1550 
1551 template <class T1, class S1,
1552  class T2, class S2>
1553 inline void
1554 hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
1555  MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
1556  double scale)
1557 {
1558  vigra_precondition(src.shape() == dest.shape(),
1559  "hessianMatrixOfGaussian(): shape mismatch between input and output.");
1560 
1561  MultiArrayView<3, T2> expanded(dest.expandElements(0));
1562 
1563  hessianMatrixOfGaussian(srcImageRange(src),
1564  destImage(expanded.bind<0>(0)),
1565  destImage(expanded.bind<0>(1)),
1566  destImage(expanded.bind<0>(2)),
1567  scale);
1568 }
1569 
1570 /********************************************************/
1571 /* */
1572 /* structureTensor */
1573 /* */
1574 /********************************************************/
1575 
1576 /** \brief Calculate the Structure Tensor for each pixel of
1577  and image, using Gaussian (derivative) filters.
1578 
1579  The Structure Tensor is is a smoothed version of the Euclidean product
1580  of the gradient vector with itself. I.e. it's a symmetric matrix defined as:
1581 
1582  \f[
1583  \mbox{\rm StructurTensor}(I) = \left(
1584  \begin{array}{cc}
1585  G \ast (I_x I_x) & G \ast (I_x I_y) \\
1586  G \ast (I_x I_y) & G \ast (I_y I_y)
1587  \end{array} \right) = \left(
1588  \begin{array}{cc}
1589  A & C \\
1590  C & B
1591  \end{array} \right)
1592  \f]
1593 
1594  where \f$G\f$ denotes Gaussian smoothing at the <i>outer scale</i>,
1595  \f$I_x, I_y\f$ are the gradient components taken at the <i>inner scale</i>,
1596  \f$\ast\f$ is the convolution symbol, and \f$I_x I_x\f$ etc. are pixelwise
1597  products of the 1st derivative images. This function calls
1598  \ref separableConvolveX() and \ref separableConvolveY() with the
1599  appropriate Gaussian kernels and puts the results in
1600  the three separate destination images (where the first one will
1601  contain \f$G \ast (I_x I_x)\f$, the second one \f$G \ast (I_x I_y)\f$, and the
1602  third one holds \f$G \ast (I_y I_y)\f$), or into a single 3-band image (where the bands
1603  hold the result in the same order as above). The latter form is also applicable when
1604  the source image is a multi-band image (e.g. RGB). In this case, tensors are
1605  first computed for each band separately, and then summed up to get a single result tensor.
1606 
1607  Function \ref structureTensorMultiArray() performs the same filter operation
1608  on arbitrary dimensional arrays.
1609 
1610  <b> Declarations:</b>
1611 
1612  pass 2D array views:
1613  \code
1614  namespace vigra {
1615  // create three separate destination images
1616  template <class T, class S,
1617  class TX, class SX,
1618  class TXY, class SXY,
1619  class TY, class SY>
1620  void
1621  structureTensor(MultiArrayView<2, S, T> const & src,
1622  MultiArrayView<2, TX, SX> destx,
1623  MultiArrayView<2, TXY, SXY> destxy,
1624  MultiArrayView<2, TY, SY> desty,
1625  double inner_scale, double outer_scale);
1626 
1627  // create a single 3-band destination image
1628  template <class T1, class S1,
1629  class T2, class S2>
1630  void
1631  structureTensor(MultiArrayView<2, T1, S1> const & src,
1632  MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
1633  double inner_scale, double outer_scale);
1634  }
1635  \endcode
1636 
1637  \deprecatedAPI{structureTensor}
1638  pass \ref ImageIterators and \ref DataAccessors :
1639  \code
1640  namespace vigra {
1641  // create three separate destination images
1642  template <class SrcIterator, class SrcAccessor,
1643  class DestIteratorX, class DestAccessorX,
1644  class DestIteratorXY, class DestAccessorXY,
1645  class DestIteratorY, class DestAccessorY>
1646  void structureTensor(SrcIterator supperleft,
1647  SrcIterator slowerright, SrcAccessor sa,
1648  DestIteratorX dupperleftx, DestAccessorX dax,
1649  DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1650  DestIteratorY dupperlefty, DestAccessorY day,
1651  double inner_scale, double outer_scale);
1652 
1653  // create a single 3-band destination image
1654  template <class SrcIterator, class SrcAccessor,
1655  class DestIterator, class DestAccessor>
1656  void structureTensor(SrcIterator supperleft,
1657  SrcIterator slowerright, SrcAccessor sa,
1658  DestIterator dupperleft, DestAccessor da,
1659  double inner_scale, double outer_scale);
1660  }
1661  \endcode
1662  use argument objects in conjunction with \ref ArgumentObjectFactories :
1663  \code
1664  namespace vigra {
1665  // create three separate destination images
1666  template <class SrcIterator, class SrcAccessor,
1667  class DestIteratorX, class DestAccessorX,
1668  class DestIteratorXY, class DestAccessorXY,
1669  class DestIteratorY, class DestAccessorY>
1670  void
1671  structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1672  pair<DestIteratorX, DestAccessorX> destx,
1673  pair<DestIteratorXY, DestAccessorXY> destxy,
1674  pair<DestIteratorY, DestAccessorY> desty,
1675  double nner_scale, double outer_scale);
1676 
1677  // create a single 3-band destination image
1678  template <class SrcIterator, class SrcAccessor,
1679  class DestIterator, class DestAccessor>
1680  void
1681  structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1682  pair<DestIterator, DestAccessor> dest,
1683  double nner_scale, double outer_scale);
1684  }
1685  \endcode
1686  \deprecatedEnd
1687 
1688  <b> Usage:</b>
1689 
1690  <b>\#include</b> <vigra/convolution.hxx><br/>
1691  Namespace: vigra
1692 
1693  \code
1694  MultiArray<2, flost> src(w,h),
1695  stxx(w,h), stxy(w,h), styy(w,h); // use a separate image for each component
1696  ...
1697 
1698  // calculate Structure Tensor at inner scale = 1.0 and outer scale = 3.0
1699  structureTensor(src, stxx, stxy, styy, 1.0, 3.0);
1700 
1701  // likwise with a single 3-band destination image
1702  MultiArray<2, TinyVector<float, 3> > st(w,h);
1703  structureTensor(src, st, 1.0, 3.0);
1704  \endcode
1705 
1706  \deprecatedUsage{structureTensor}
1707  \code
1708  vigra::FImage src(w,h),
1709  stxx(w,h), stxy(w,h), styy(w,h);
1710  vigra::BasicImage<TinyVector<float, 3> > st(w,h);
1711  ...
1712 
1713  vigra::structureTensor(srcImageRange(src),
1714  destImage(stxx), destImage(stxy), destImage(styy), 1.0, 3.0);
1715 
1716  vigra::structureTensor(srcImageRange(src), destImage(st), 1.0, 3.0);
1717  \endcode
1718  \deprecatedEnd
1719 */
1720 doxygen_overloaded_function(template <...> void structureTensor)
1721 
1722 template <class SrcIterator, class SrcAccessor,
1723  class DestIteratorX, class DestAccessorX,
1724  class DestIteratorXY, class DestAccessorXY,
1725  class DestIteratorY, class DestAccessorY>
1726 void structureTensor(SrcIterator supperleft,
1727  SrcIterator slowerright, SrcAccessor sa,
1728  DestIteratorX dupperleftx, DestAccessorX dax,
1729  DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1730  DestIteratorY dupperlefty, DestAccessorY day,
1731  double inner_scale, double outer_scale)
1732 {
1733  typedef typename
1734  NumericTraits<typename SrcAccessor::value_type>::RealPromote
1735  TmpType;
1736  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization),
1737  tmpx(slowerright - supperleft, SkipInitialization),
1738  tmpy(slowerright - supperleft, SkipInitialization);
1739 
1740  gaussianGradient(srcIterRange(supperleft, slowerright, sa),
1741  destImage(tmpx), destImage(tmpy), inner_scale);
1742  combineTwoImages(srcImageRange(tmpx), srcImage(tmpx),
1743  destImage(tmp), std::multiplies<TmpType>());
1744  gaussianSmoothing(srcImageRange(tmp),
1745  destIter(dupperleftx, dax), outer_scale);
1746  combineTwoImages(srcImageRange(tmpy), srcImage(tmpy),
1747  destImage(tmp), std::multiplies<TmpType>());
1748  gaussianSmoothing(srcImageRange(tmp),
1749  destIter(dupperlefty, day), outer_scale);
1750  combineTwoImages(srcImageRange(tmpx), srcImage(tmpy),
1751  destImage(tmp), std::multiplies<TmpType>());
1752  gaussianSmoothing(srcImageRange(tmp),
1753  destIter(dupperleftxy, daxy), outer_scale);
1754 }
1755 
1756 template <class SrcIterator, class SrcAccessor,
1757  class DestIteratorX, class DestAccessorX,
1758  class DestIteratorXY, class DestAccessorXY,
1759  class DestIteratorY, class DestAccessorY>
1760 inline void
1761 structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1762  pair<DestIteratorX, DestAccessorX> destx,
1763  pair<DestIteratorXY, DestAccessorXY> destxy,
1764  pair<DestIteratorY, DestAccessorY> desty,
1765  double inner_scale, double outer_scale)
1766 {
1767  structureTensor(src.first, src.second, src.third,
1768  destx.first, destx.second,
1769  destxy.first, destxy.second,
1770  desty.first, desty.second,
1771  inner_scale, outer_scale);
1772 }
1773 
1774 template <class T, class S,
1775  class TX, class SX,
1776  class TXY, class SXY,
1777  class TY, class SY>
1778 inline void
1779 structureTensor(MultiArrayView<2, S, T> const & src,
1780  MultiArrayView<2, TX, SX> destx,
1781  MultiArrayView<2, TXY, SXY> destxy,
1782  MultiArrayView<2, TY, SY> desty,
1783  double inner_scale, double outer_scale)
1784 {
1785  vigra_precondition(src.shape() == destx.shape(),
1786  "structureTensor(): shape mismatch between input and output.");
1787  structureTensor(srcImageRange(src),
1788  destImage(destx), destImage(destxy), destImage(desty),
1789  inner_scale, outer_scale);
1790 }
1791 
1792 namespace detail {
1793 
1794 template <class SrcIterator, class SrcAccessor,
1795  class DestIterator, class DestAccessor>
1796 void structureTensor(SrcIterator supperleft,
1797  SrcIterator slowerright, SrcAccessor src,
1798  DestIterator dupperleft, DestAccessor dest,
1799  double inner_scale, double outer_scale,
1800  VigraTrueType /* isScalar */)
1801 {
1802  typedef VectorElementAccessor<DestAccessor> DA;
1803  structureTensor(supperleft, slowerright, src,
1804  dupperleft, DA(0, dest),
1805  dupperleft, DA(1, dest),
1806  dupperleft, DA(2, dest),
1807  inner_scale, outer_scale);
1808 }
1809 
1810 template <class SrcIterator, class SrcAccessor,
1811  class DestIterator, class DestAccessor>
1812 void structureTensor(SrcIterator supperleft,
1813  SrcIterator slowerright, SrcAccessor src,
1814  DestIterator dupperleft, DestAccessor dest,
1815  double inner_scale, double outer_scale,
1816  VigraFalseType /* isScalar */)
1817 {
1818  int bands = src.size(supperleft);
1819  typedef VectorElementAccessor<SrcAccessor> SA;
1820 
1821  structureTensor(supperleft, slowerright, SA(0, src),
1822  dupperleft, dest,
1823  inner_scale, outer_scale,
1824  VigraTrueType() /* isScalar */);
1825 
1826  BasicImage<typename DestAccessor::value_type> st(slowerright - supperleft, SkipInitialization);
1827  for(int k=1; k < bands; ++k)
1828  {
1829  structureTensor(supperleft, slowerright, SA(k, src),
1830  st.upperLeft(), st.accessor(),
1831  inner_scale, outer_scale,
1832  VigraTrueType() /* isScalar */);
1833  combineTwoImages(srcImageRange(st), srcIter(dupperleft, dest), destIter(dupperleft, dest),
1834  std::plus<typename DestAccessor::value_type>());
1835  }
1836 }
1837 
1838 } // namespace detail
1839 
1840 template <class SrcIterator, class SrcAccessor,
1841  class DestIterator, class DestAccessor>
1842 void structureTensor(SrcIterator supperleft,
1843  SrcIterator slowerright, SrcAccessor src,
1844  DestIterator dupperleft, DestAccessor dest,
1845  double inner_scale, double outer_scale)
1846 {
1847  typedef typename
1848  NumericTraits<typename SrcAccessor::value_type>::isScalar isScalar;
1849  detail::structureTensor(supperleft, slowerright, src,
1850  dupperleft, dest, inner_scale, outer_scale, isScalar());
1851 }
1852 
1853 template <class SrcIterator, class SrcAccessor,
1854  class DestIterator, class DestAccessor>
1855 inline void
1856 structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1857  pair<DestIterator, DestAccessor> dest,
1858  double inner_scale, double outer_scale)
1859 {
1860  structureTensor(src.first, src.second, src.third,
1861  dest.first, dest.second,
1862  inner_scale, outer_scale);
1863 }
1864 
1865 template <class T1, class S1,
1866  class T2, class S2>
1867 inline void
1868 structureTensor(MultiArrayView<2, T1, S1> const & src,
1869  MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
1870  double inner_scale, double outer_scale)
1871 {
1872  vigra_precondition(src.shape() == dest.shape(),
1873  "structureTensor(): shape mismatch between input and output.");
1874  structureTensor(srcImageRange(src),
1875  destImage(dest),
1876  inner_scale, outer_scale);
1877 }
1878 
1879 //@}
1880 
1881 } // namespace vigra
1882 
1883 #endif // VIGRA_CONVOLUTION_HXX
void simpleSharpening(...)
Perform simple sharpening function.
void gaussianGradient(...)
Calculate the gradient vector by means of a 1st derivatives of Gaussian filter.
void laplacianOfGaussian(...)
Filter image with the Laplacian of Gaussian operator at the given scale.
void gaussianGradientMagnitude(...)
Calculate the gradient magnitude by means of a 1st derivatives of Gaussian filter.
void gaussianSmoothing(...)
Perform isotropic Gaussian convolution.
void separableConvolveX(...)
Performs a 1 dimensional convolution in x direction.
void combineTwoImages(...)
Combine two source images into destination image.
void convolveImage(...)
Convolve an image with the given kernel(s).
void gaussianSharpening(...)
Perform sharpening function with gaussian filter.
void structureTensor(...)
Calculate the Structure Tensor for each pixel of and image, using Gaussian (derivative) filters...
void hessianMatrixOfGaussian(...)
Filter image with the 2nd derivatives of the Gaussian at the given scale to get the Hessian matrix...
void separableConvolveY(...)
Performs a 1 dimensional convolution in y direction.

© 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.10.0 (Tue Dec 31 2013)