[ 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 input 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 */
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 */
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 */
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 */
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  Anisotropic data should be provided with appropriate \ref vigra::ConvolutionOptions
1082  to adjust the filter sizes for the resolution of each axis.
1083  Otherwise, the parameter <tt>opt</tt> is optional unless the parameter
1084  <tt>sigma</tt> is omitted.
1085 
1086  If you pass \ref vigra::BlockwiseConvolutionOptions instead, the algorithm will
1087  be executed in parallel on data blocks of a certain size. The block size can be
1088  customized via <tt>BlockwiseConvolutionOptions::blockShape()</tt>, but the defaults
1089  usually work reasonably. By default, the number of threads equals the capabilities
1090  of your hardware, but you can change this via <tt>BlockwiseConvolutionOptions::numThreads()</tt>.
1091 
1092  <b> Declarations:</b>
1093 
1094  use arbitrary-dimensional arrays:
1095  \code
1096  namespace vigra {
1097  // pass filter scale explicitly
1098  template <unsigned int N, class T1, class S1,
1099  class T2, class S2>
1100  void
1101  gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
1102  MultiArrayView<N, T2, S2> dest,
1103  double sigma,
1104  ConvolutionOptions<N> opt = ConvolutionOptions<N>());
1105 
1106  // likewise, but sum the contributions of each band
1107  template <unsigned int N, class MT, class S1,
1108  class T2, class S2>
1109  void
1110  gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<MT>, S1> const & src,
1111  MultiArrayView<N, T2, S2> dest,
1112  double sigma,
1113  ConvolutionOptions<N> opt = ConvolutionOptions<N>());
1114 
1115  // pass filter scale(s) in option object
1116  template <unsigned int N, class T1, class S1,
1117  class T2, class S2>
1118  void
1119  gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
1120  MultiArrayView<N, T2, S2> dest,
1121  ConvolutionOptions<N> const & opt);
1122 
1123  // likewise, but execute algorithm in parallel
1124  template <unsigned int N, class T1, class S1,
1125  class T2, class S2>
1126  void
1127  gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
1128  MultiArrayView<N, T2, S2> dest,
1129  BlockwiseConvolutionOptions<N> const & opt);
1130 
1131  // pass filter scale(s) in option object and sum the contributions of each band
1132  template <unsigned int N, class MT, class S1,
1133  class T2, class S2>
1134  void
1135  gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<MT>, S1> const & src,
1136  MultiArrayView<N, T2, S2> dest,
1137  ConvolutionOptions<N> const & opt);
1138  }
1139  \endcode
1140  Here, the input element types <tt>T1</tt> and <tt>MT</tt> can be arbitrary scalar types, and <tt>T1</tt>
1141  may also be <tt>TinyVector</tt> or <tt>RGBValue</tt>. The output element type <tt>T2</tt> should
1142  be the corresponding norm type (see \ref NormTraits "NormTraits"). In the <tt>Multiband<MT></tt>-version,
1143  the input array's right-most dimension is interpreted as a channel axis, therefore it must
1144  have one dimension more than the output array.
1145 
1146  \deprecatedAPI{gaussianGradientMagnitude}
1147  pass \ref ImageIterators and \ref DataAccessors :
1148  \code
1149  namespace vigra {
1150  template <class SrcIterator, class SrcAccessor,
1151  class DestIterator, class DestAccessor>
1152  void gaussianGradientMagnitude(SrcIterator sul,
1153  SrcIterator slr, SrcAccessor src,
1154  DestIterator dupperleft, DestAccessor dest,
1155  double scale);
1156  }
1157  \endcode
1158  use argument objects in conjunction with \ref ArgumentObjectFactories :
1159  \code
1160  namespace vigra {
1161  template <class SrcIterator, class SrcAccessor,
1162  class DestIterator, class DestAccessor>
1163  void
1164  gaussianGradientMagnitude(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1165  pair<DestIterator, DestAccessor> dest,
1166  double scale);
1167  }
1168  \endcode
1169  \deprecatedEnd
1170 
1171  <b> Usage:</b>
1172 
1173  <b>\#include</b> <vigra/multi_convolution.hxx> (sequential version)<br/>
1174  <b>\#include</b> <vigra/multi_blockwise.hxx> (parallel version)<br/>
1175  <b>\#include</b> <vigra/convolution.hxx> (deprecated API version)<br/>
1176  Namespace: vigra
1177 
1178  \code
1179  // example 1
1180  {
1181  // use a 3-dimensional float array
1182  MultiArray<3, float> volume(Shape3(w, h, d)), grad(volume.shape());
1183  ...
1184 
1185  // calculate gradient magnitude at scale = 3.0
1186  gaussianGradientMagnitude(volume, grad, 3.0);
1187  }
1188 
1189  // example 2
1190  {
1191  // use a 2-dimensional RGB array
1192  MultiArray<2, RGBValue<float> > rgb(Shape2(w, h));
1193  MultiArray<2, float> grad(rgb.shape());
1194  ...
1195 
1196  // calculate the color gradient magnitude at scale = 3.0
1197  gaussianGradientMagnitude(rgb, grad, 3.0);
1198  }
1199 
1200  // example 3
1201  {
1202  // use a 3-dimensional array whose right-most axis is interpreted as
1203  // a multi-spectral axis with arbitrary many channels
1204  MultiArray<3, Multiband<float> > spectral(Shape3(w, h, channelCount));
1205  MultiArray<2, float> grad(Shape2(w, h));
1206  ...
1207 
1208  // calculate the multi-channel gradient magnitude at scale = 3.0
1209  // (note that the template parameter N (number of spatial dimensions)
1210  // must be provided explicitly as gaussianGradientMagnitude<2>(...) )
1211  MultiArrayView<3, Multiband<float> > view(spectral);
1212  gaussianGradientMagnitude<2>(view, grad, 3.0);
1213  }
1214  \endcode
1215 
1216  \deprecatedUsage{gaussianGradientMagnitude}
1217  \code
1218  // use a traditional float or RGB image
1219  FImage image(w, h), grad(w, h);
1220  FRGBImage rgb(w, h);
1221  ...
1222 
1223  // calculate gradient magnitude at scale = 3.0
1224  gaussianGradientMagnitude(srcImageRange(image), destImage(grad), 3.0);
1225 
1226  // calculate color gradient magnitude at scale = 3.0
1227  gaussianGradientMagnitude(srcImageRange(rgb), destImage(grad), 3.0);
1228  \endcode
1229  \deprecatedEnd
1230 */
1232 
1233 template <class SrcIterator, class SrcAccessor,
1234  class DestIterator, class DestAccessor>
1235 void gaussianGradientMagnitude(SrcIterator sul,
1236  SrcIterator slr, SrcAccessor src,
1237  DestIterator dupperleft, DestAccessor dest,
1238  double scale)
1239 {
1240  typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
1241  BasicImage<TmpType> gradx(slr-sul, SkipInitialization), grady(slr-sul, SkipInitialization);
1242 
1243  gaussianGradient(srcIterRange(sul, slr, src),
1244  destImage(gradx), destImage(grady), scale);
1245  combineTwoImages(srcImageRange(gradx), srcImage(grady), destIter(dupperleft, dest),
1246  MagnitudeFunctor<TmpType>());
1247 }
1248 
1249 template <class SrcIterator, class SrcAccessor,
1250  class DestIterator, class DestAccessor>
1251 inline void
1252 gaussianGradientMagnitude(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1253  pair<DestIterator, DestAccessor> dest,
1254  double scale)
1255 {
1256  gaussianGradientMagnitude(src.first, src.second, src.third,
1257  dest.first, dest.second, scale);
1258 }
1259 
1260 /********************************************************/
1261 /* */
1262 /* laplacianOfGaussian */
1263 /* */
1264 /********************************************************/
1265 
1266 /** \brief Filter image with the Laplacian of Gaussian operator
1267  at the given scale.
1268 
1269  This function calls \ref separableConvolveX() and \ref separableConvolveY() with the appropriate 2nd derivative
1270  of Gaussian kernels in x- and y-direction and then sums the results
1271  to get the Laplacian.
1272 
1273  Function \ref laplacianOfGaussianMultiArray() performs the same filter operation
1274  on arbitrary dimensional arrays.
1275 
1276  <b> Declarations:</b>
1277 
1278  pass 2D array views:
1279  \code
1280  namespace vigra {
1281  template <class T1, class S1,
1282  class T2, class S2>
1283  void
1284  laplacianOfGaussian(MultiArrayView<2, T1, S1> const & src,
1285  MultiArrayView<2, T2, S2> dest,
1286  double scale);
1287  }
1288  \endcode
1289 
1290  \deprecatedAPI{laplacianOfGaussian}
1291  pass \ref ImageIterators and \ref DataAccessors :
1292  \code
1293  namespace vigra {
1294  template <class SrcIterator, class SrcAccessor,
1295  class DestIterator, class DestAccessor>
1296  void laplacianOfGaussian(SrcIterator supperleft,
1297  SrcIterator slowerright, SrcAccessor sa,
1298  DestIterator dupperleft, DestAccessor da,
1299  double scale);
1300  }
1301  \endcode
1302  use argument objects in conjunction with \ref ArgumentObjectFactories :
1303  \code
1304  namespace vigra {
1305  template <class SrcIterator, class SrcAccessor,
1306  class DestIterator, class DestAccessor>
1307  void
1308  laplacianOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1309  pair<DestIterator, DestAccessor> dest,
1310  double scale);
1311  }
1312  \endcode
1313  \deprecatedEnd
1314 
1315  <b> Usage:</b>
1316 
1317  <b>\#include</b> <vigra/convolution.hxx><br/>
1318  Namespace: vigra
1319 
1320  \code
1321  MultiArray<2, float> src(w,h), dest(w,h);
1322  ...
1323 
1324  // calculate Laplacian of Gaussian at scale = 3.0
1325  laplacianOfGaussian(src, dest, 3.0);
1326  \endcode
1327 
1328  \deprecatedUsage{laplacianOfGaussian}
1329  \code
1330  vigra::FImage src(w,h), dest(w,h);
1331  ...
1332 
1333  // calculate Laplacian of Gaussian at scale = 3.0
1334  vigra::laplacianOfGaussian(srcImageRange(src), destImage(dest), 3.0);
1335  \endcode
1336  \deprecatedEnd
1337 */
1339 
1340 template <class SrcIterator, class SrcAccessor,
1341  class DestIterator, class DestAccessor>
1342 void laplacianOfGaussian(SrcIterator supperleft,
1343  SrcIterator slowerright, SrcAccessor sa,
1344  DestIterator dupperleft, DestAccessor da,
1345  double scale)
1346 {
1347  typedef typename
1348  NumericTraits<typename SrcAccessor::value_type>::RealPromote
1349  TmpType;
1350  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization),
1351  tmpx(slowerright - supperleft, SkipInitialization),
1352  tmpy(slowerright - supperleft, SkipInitialization);
1353 
1354  Kernel1D<double> smooth, deriv;
1355  smooth.initGaussian(scale);
1356  deriv.initGaussianDerivative(scale, 2);
1357 
1358  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1359  destImage(tmp), kernel1d(deriv));
1360  separableConvolveY(srcImageRange(tmp),
1361  destImage(tmpx), kernel1d(smooth));
1362  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1363  destImage(tmp), kernel1d(smooth));
1364  separableConvolveY(srcImageRange(tmp),
1365  destImage(tmpy), kernel1d(deriv));
1366  combineTwoImages(srcImageRange(tmpx), srcImage(tmpy),
1367  destIter(dupperleft, da), std::plus<TmpType>());
1368 }
1369 
1370 template <class SrcIterator, class SrcAccessor,
1371  class DestIterator, class DestAccessor>
1372 inline void
1373 laplacianOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1374  pair<DestIterator, DestAccessor> dest,
1375  double scale)
1376 {
1377  laplacianOfGaussian(src.first, src.second, src.third,
1378  dest.first, dest.second, scale);
1379 }
1380 
1381 template <class T1, class S1,
1382  class T2, class S2>
1383 inline void
1384 laplacianOfGaussian(MultiArrayView<2, T1, S1> const & src,
1385  MultiArrayView<2, T2, S2> dest,
1386  double scale)
1387 {
1388  vigra_precondition(src.shape() == dest.shape(),
1389  "laplacianOfGaussian(): shape mismatch between input and output.");
1390  laplacianOfGaussian(srcImageRange(src),
1391  destImage(dest), scale);
1392 }
1393 
1394 /********************************************************/
1395 /* */
1396 /* hessianMatrixOfGaussian */
1397 /* */
1398 /********************************************************/
1399 
1400 /** \brief Filter image with the 2nd derivatives of the Gaussian
1401  at the given scale to get the Hessian matrix.
1402 
1403  The Hessian matrix is a symmetric matrix defined as:
1404 
1405  \f[
1406  \mbox{\rm Hessian}(I) = \left(
1407  \begin{array}{cc}
1408  G_{xx} \ast I & G_{xy} \ast I \\
1409  G_{xy} \ast I & G_{yy} \ast I
1410  \end{array} \right)
1411  \f]
1412 
1413  where \f$G_{xx}, G_{xy}, G_{yy}\f$ denote 2nd derivatives of Gaussians
1414  at the given scale, and
1415  \f$\ast\f$ is the convolution symbol. This function calls
1416  \ref separableConvolveX() and \ref separableConvolveY()
1417  with the appropriate 2nd derivative
1418  of Gaussian kernels and puts the results in
1419  the three destination images. The first destination image will
1420  contain the second derivative in x-direction, the second one the mixed
1421  derivative, and the third one holds the derivative in y-direction.
1422 
1423  Function \ref hessianOfGaussianMultiArray() performs the same filter operation
1424  on arbitrary dimensional arrays.
1425 
1426  <b> Declarations:</b>
1427 
1428  pass 2D array views:
1429  \code
1430  namespace vigra {
1431  template <class T1, class S1,
1432  class T2, class S2>
1433  void
1434  hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
1435  MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
1436  double scale);
1437  }
1438  \endcode
1439 
1440  \deprecatedAPI{hessianMatrixOfGaussian}
1441  pass \ref ImageIterators and \ref DataAccessors :
1442  \code
1443  namespace vigra {
1444  template <class SrcIterator, class SrcAccessor,
1445  class DestIteratorX, class DestAccessorX,
1446  class DestIteratorXY, class DestAccessorXY,
1447  class DestIteratorY, class DestAccessorY>
1448  void hessianMatrixOfGaussian(SrcIterator supperleft,
1449  SrcIterator slowerright, SrcAccessor sa,
1450  DestIteratorX dupperleftx, DestAccessorX dax,
1451  DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1452  DestIteratorY dupperlefty, DestAccessorY day,
1453  double scale);
1454  }
1455  \endcode
1456  use argument objects in conjunction with \ref ArgumentObjectFactories :
1457  \code
1458  namespace vigra {
1459  template <class SrcIterator, class SrcAccessor,
1460  class DestIteratorX, class DestAccessorX,
1461  class DestIteratorXY, class DestAccessorXY,
1462  class DestIteratorY, class DestAccessorY>
1463  void
1464  hessianMatrixOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1465  pair<DestIteratorX, DestAccessorX> destx,
1466  pair<DestIteratorXY, DestAccessorXY> destxy,
1467  pair<DestIteratorY, DestAccessorY> desty,
1468  double scale);
1469  }
1470  \endcode
1471  \deprecatedEnd
1472 
1473  <b> Usage:</b>
1474 
1475  <b>\#include</b> <vigra/convolution.hxx><br/>
1476  Namespace: vigra
1477 
1478  \code
1479  MultiArray<2, float> src(w,h);
1480  MultiArray<2, TinyVector<float, 3> > hessian(w,h); // will hold the three components of the Hessian
1481  ...
1482 
1483  // calculate Hessian of Gaussian at scale = 3.0, use a 3-band output image
1484  hessianMatrixOfGaussian(src, hessian, 3.0);
1485  \endcode
1486 
1487  \deprecatedUsage{hessianMatrixOfGaussian}
1488  \code
1489  vigra::FImage src(w,h),
1490  hxx(w,h), hxy(w,h), hyy(w,h); // use a separate image for each component of the Hessian
1491  ...
1492 
1493  // calculate Hessian of Gaussian at scale = 3.0, use 3 single.band output images
1494  vigra::hessianMatrixOfGaussian(srcImageRange(src),
1495  destImage(hxx), destImage(hxy), destImage(hyy), 3.0);
1496  \endcode
1497  \deprecatedEnd
1498 */
1500 
1501 template <class SrcIterator, class SrcAccessor,
1502  class DestIteratorX, class DestAccessorX,
1503  class DestIteratorXY, class DestAccessorXY,
1504  class DestIteratorY, class DestAccessorY>
1505 void hessianMatrixOfGaussian(SrcIterator supperleft,
1506  SrcIterator slowerright, SrcAccessor sa,
1507  DestIteratorX dupperleftx, DestAccessorX dax,
1508  DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1509  DestIteratorY dupperlefty, DestAccessorY day,
1510  double scale)
1511 {
1512  typedef typename
1513  NumericTraits<typename SrcAccessor::value_type>::RealPromote
1514  TmpType;
1515  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization);
1516 
1517  Kernel1D<double> smooth, deriv1, deriv2;
1518  smooth.initGaussian(scale);
1519  deriv1.initGaussianDerivative(scale, 1);
1520  deriv2.initGaussianDerivative(scale, 2);
1521 
1522  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1523  destImage(tmp), kernel1d(deriv2));
1524  separableConvolveY(srcImageRange(tmp),
1525  destIter(dupperleftx, dax), kernel1d(smooth));
1526  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1527  destImage(tmp), kernel1d(smooth));
1528  separableConvolveY(srcImageRange(tmp),
1529  destIter(dupperlefty, day), kernel1d(deriv2));
1530  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1531  destImage(tmp), kernel1d(deriv1));
1532  separableConvolveY(srcImageRange(tmp),
1533  destIter(dupperleftxy, daxy), kernel1d(deriv1));
1534 }
1535 
1536 template <class SrcIterator, class SrcAccessor,
1537  class DestIteratorX, class DestAccessorX,
1538  class DestIteratorXY, class DestAccessorXY,
1539  class DestIteratorY, class DestAccessorY>
1540 inline void
1541 hessianMatrixOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1542  pair<DestIteratorX, DestAccessorX> destx,
1543  pair<DestIteratorXY, DestAccessorXY> destxy,
1544  pair<DestIteratorY, DestAccessorY> desty,
1545  double scale)
1546 {
1547  hessianMatrixOfGaussian(src.first, src.second, src.third,
1548  destx.first, destx.second,
1549  destxy.first, destxy.second,
1550  desty.first, desty.second,
1551  scale);
1552 }
1553 
1554 template <class T1, class S1,
1555  class T2X, class S2X,
1556  class T2XY, class S2XY,
1557  class T2Y, class S2Y>
1558 inline void
1559 hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
1560  MultiArrayView<2, T2X, S2X> destx,
1561  MultiArrayView<2, T2XY, S2XY> destxy,
1562  MultiArrayView<2, T2Y, S2Y> desty,
1563  double scale)
1564 {
1565  vigra_precondition(src.shape() == destx.shape() && src.shape() == destxy.shape() && src.shape() == desty.shape(),
1566  "hessianMatrixOfGaussian(): shape mismatch between input and output.");
1567  hessianMatrixOfGaussian(srcImageRange(src),
1568  destImage(destx),
1569  destImage(destxy),
1570  destImage(desty),
1571  scale);
1572 }
1573 
1574 template <class T1, class S1,
1575  class T2, class S2>
1576 inline void
1577 hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
1578  MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
1579  double scale)
1580 {
1581  vigra_precondition(src.shape() == dest.shape(),
1582  "hessianMatrixOfGaussian(): shape mismatch between input and output.");
1583 
1584  MultiArrayView<3, T2> expanded(dest.expandElements(0));
1585  MultiArrayView<2, T2> dxx(expanded.template bind<0>(0));
1586  MultiArrayView<2, T2> dxy(expanded.template bind<0>(1));
1587  MultiArrayView<2, T2> dyy(expanded.template bind<0>(2));
1588 
1589  hessianMatrixOfGaussian(srcImageRange(src),
1590  destImage(dxx),
1591  destImage(dxy),
1592  destImage(dyy),
1593  scale);
1594 }
1595 
1596 /********************************************************/
1597 /* */
1598 /* structureTensor */
1599 /* */
1600 /********************************************************/
1601 
1602 /** \brief Calculate the Structure Tensor for each pixel of
1603  and image, using Gaussian (derivative) filters.
1604 
1605  The Structure Tensor is is a smoothed version of the Euclidean product
1606  of the gradient vector with itself. I.e. it's a symmetric matrix defined as:
1607 
1608  \f[
1609  \mbox{\rm StructurTensor}(I) = \left(
1610  \begin{array}{cc}
1611  G \ast (I_x I_x) & G \ast (I_x I_y) \\
1612  G \ast (I_x I_y) & G \ast (I_y I_y)
1613  \end{array} \right) = \left(
1614  \begin{array}{cc}
1615  A & C \\
1616  C & B
1617  \end{array} \right)
1618  \f]
1619 
1620  where \f$G\f$ denotes Gaussian smoothing at the <i>outer scale</i>,
1621  \f$I_x, I_y\f$ are the gradient components taken at the <i>inner scale</i>,
1622  \f$\ast\f$ is the convolution symbol, and \f$I_x I_x\f$ etc. are pixelwise
1623  products of the 1st derivative images. This function calls
1624  \ref separableConvolveX() and \ref separableConvolveY() with the
1625  appropriate Gaussian kernels and puts the results in
1626  the three separate destination images (where the first one will
1627  contain \f$G \ast (I_x I_x)\f$, the second one \f$G \ast (I_x I_y)\f$, and the
1628  third one holds \f$G \ast (I_y I_y)\f$), or into a single 3-band image (where the bands
1629  hold the result in the same order as above). The latter form is also applicable when
1630  the source image is a multi-band image (e.g. RGB). In this case, tensors are
1631  first computed for each band separately, and then summed up to get a single result tensor.
1632 
1633  Function \ref structureTensorMultiArray() performs the same filter operation
1634  on arbitrary dimensional arrays.
1635 
1636  <b> Declarations:</b>
1637 
1638  pass 2D array views:
1639  \code
1640  namespace vigra {
1641  // create three separate destination images
1642  template <class T, class S,
1643  class TX, class SX,
1644  class TXY, class SXY,
1645  class TY, class SY>
1646  void
1647  structureTensor(MultiArrayView<2, S, T> const & src,
1648  MultiArrayView<2, TX, SX> destx,
1649  MultiArrayView<2, TXY, SXY> destxy,
1650  MultiArrayView<2, TY, SY> desty,
1651  double inner_scale, double outer_scale);
1652 
1653  // create a single 3-band destination image
1654  template <class T1, class S1,
1655  class T2, class S2>
1656  void
1657  structureTensor(MultiArrayView<2, T1, S1> const & src,
1658  MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
1659  double inner_scale, double outer_scale);
1660  }
1661  \endcode
1662 
1663  \deprecatedAPI{structureTensor}
1664  pass \ref ImageIterators and \ref DataAccessors :
1665  \code
1666  namespace vigra {
1667  // create three separate destination images
1668  template <class SrcIterator, class SrcAccessor,
1669  class DestIteratorX, class DestAccessorX,
1670  class DestIteratorXY, class DestAccessorXY,
1671  class DestIteratorY, class DestAccessorY>
1672  void structureTensor(SrcIterator supperleft,
1673  SrcIterator slowerright, SrcAccessor sa,
1674  DestIteratorX dupperleftx, DestAccessorX dax,
1675  DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1676  DestIteratorY dupperlefty, DestAccessorY day,
1677  double inner_scale, double outer_scale);
1678 
1679  // create a single 3-band destination image
1680  template <class SrcIterator, class SrcAccessor,
1681  class DestIterator, class DestAccessor>
1682  void structureTensor(SrcIterator supperleft,
1683  SrcIterator slowerright, SrcAccessor sa,
1684  DestIterator dupperleft, DestAccessor da,
1685  double inner_scale, double outer_scale);
1686  }
1687  \endcode
1688  use argument objects in conjunction with \ref ArgumentObjectFactories :
1689  \code
1690  namespace vigra {
1691  // create three separate destination images
1692  template <class SrcIterator, class SrcAccessor,
1693  class DestIteratorX, class DestAccessorX,
1694  class DestIteratorXY, class DestAccessorXY,
1695  class DestIteratorY, class DestAccessorY>
1696  void
1697  structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1698  pair<DestIteratorX, DestAccessorX> destx,
1699  pair<DestIteratorXY, DestAccessorXY> destxy,
1700  pair<DestIteratorY, DestAccessorY> desty,
1701  double nner_scale, double outer_scale);
1702 
1703  // create a single 3-band destination image
1704  template <class SrcIterator, class SrcAccessor,
1705  class DestIterator, class DestAccessor>
1706  void
1707  structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1708  pair<DestIterator, DestAccessor> dest,
1709  double nner_scale, double outer_scale);
1710  }
1711  \endcode
1712  \deprecatedEnd
1713 
1714  <b> Usage:</b>
1715 
1716  <b>\#include</b> <vigra/convolution.hxx><br/>
1717  Namespace: vigra
1718 
1719  \code
1720  MultiArray<2, flost> src(w,h),
1721  stxx(w,h), stxy(w,h), styy(w,h); // use a separate image for each component
1722  ...
1723 
1724  // calculate Structure Tensor at inner scale = 1.0 and outer scale = 3.0
1725  structureTensor(src, stxx, stxy, styy, 1.0, 3.0);
1726 
1727  // likwise with a single 3-band destination image
1728  MultiArray<2, TinyVector<float, 3> > st(w,h);
1729  structureTensor(src, st, 1.0, 3.0);
1730  \endcode
1731 
1732  \deprecatedUsage{structureTensor}
1733  \code
1734  vigra::FImage src(w,h),
1735  stxx(w,h), stxy(w,h), styy(w,h);
1736  vigra::BasicImage<TinyVector<float, 3> > st(w,h);
1737  ...
1738 
1739  vigra::structureTensor(srcImageRange(src),
1740  destImage(stxx), destImage(stxy), destImage(styy), 1.0, 3.0);
1741 
1742  vigra::structureTensor(srcImageRange(src), destImage(st), 1.0, 3.0);
1743  \endcode
1744  \deprecatedEnd
1745 */
1746 doxygen_overloaded_function(template <...> void structureTensor)
1747 
1748 template <class SrcIterator, class SrcAccessor,
1749  class DestIteratorX, class DestAccessorX,
1750  class DestIteratorXY, class DestAccessorXY,
1751  class DestIteratorY, class DestAccessorY>
1752 void structureTensor(SrcIterator supperleft,
1753  SrcIterator slowerright, SrcAccessor sa,
1754  DestIteratorX dupperleftx, DestAccessorX dax,
1755  DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1756  DestIteratorY dupperlefty, DestAccessorY day,
1757  double inner_scale, double outer_scale)
1758 {
1759  typedef typename
1760  NumericTraits<typename SrcAccessor::value_type>::RealPromote
1761  TmpType;
1762  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization),
1763  tmpx(slowerright - supperleft, SkipInitialization),
1764  tmpy(slowerright - supperleft, SkipInitialization);
1765 
1766  gaussianGradient(srcIterRange(supperleft, slowerright, sa),
1767  destImage(tmpx), destImage(tmpy), inner_scale);
1768  combineTwoImages(srcImageRange(tmpx), srcImage(tmpx),
1769  destImage(tmp), std::multiplies<TmpType>());
1770  gaussianSmoothing(srcImageRange(tmp),
1771  destIter(dupperleftx, dax), outer_scale);
1772  combineTwoImages(srcImageRange(tmpy), srcImage(tmpy),
1773  destImage(tmp), std::multiplies<TmpType>());
1774  gaussianSmoothing(srcImageRange(tmp),
1775  destIter(dupperlefty, day), outer_scale);
1776  combineTwoImages(srcImageRange(tmpx), srcImage(tmpy),
1777  destImage(tmp), std::multiplies<TmpType>());
1778  gaussianSmoothing(srcImageRange(tmp),
1779  destIter(dupperleftxy, daxy), outer_scale);
1780 }
1781 
1782 template <class SrcIterator, class SrcAccessor,
1783  class DestIteratorX, class DestAccessorX,
1784  class DestIteratorXY, class DestAccessorXY,
1785  class DestIteratorY, class DestAccessorY>
1786 inline void
1787 structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1788  pair<DestIteratorX, DestAccessorX> destx,
1789  pair<DestIteratorXY, DestAccessorXY> destxy,
1790  pair<DestIteratorY, DestAccessorY> desty,
1791  double inner_scale, double outer_scale)
1792 {
1793  structureTensor(src.first, src.second, src.third,
1794  destx.first, destx.second,
1795  destxy.first, destxy.second,
1796  desty.first, desty.second,
1797  inner_scale, outer_scale);
1798 }
1799 
1800 template <class T, class S,
1801  class TX, class SX,
1802  class TXY, class SXY,
1803  class TY, class SY>
1804 inline void
1805 structureTensor(MultiArrayView<2, S, T> const & src,
1806  MultiArrayView<2, TX, SX> destx,
1807  MultiArrayView<2, TXY, SXY> destxy,
1808  MultiArrayView<2, TY, SY> desty,
1809  double inner_scale, double outer_scale)
1810 {
1811  vigra_precondition(src.shape() == destx.shape(),
1812  "structureTensor(): shape mismatch between input and output.");
1813  structureTensor(srcImageRange(src),
1814  destImage(destx), destImage(destxy), destImage(desty),
1815  inner_scale, outer_scale);
1816 }
1817 
1818 namespace detail {
1819 
1820 template <class SrcIterator, class SrcAccessor,
1821  class DestIterator, class DestAccessor>
1822 void structureTensor(SrcIterator supperleft,
1823  SrcIterator slowerright, SrcAccessor src,
1824  DestIterator dupperleft, DestAccessor dest,
1825  double inner_scale, double outer_scale,
1826  VigraTrueType /* isScalar */)
1827 {
1828  typedef VectorElementAccessor<DestAccessor> DA;
1829  structureTensor(supperleft, slowerright, src,
1830  dupperleft, DA(0, dest),
1831  dupperleft, DA(1, dest),
1832  dupperleft, DA(2, dest),
1833  inner_scale, outer_scale);
1834 }
1835 
1836 template <class SrcIterator, class SrcAccessor,
1837  class DestIterator, class DestAccessor>
1838 void structureTensor(SrcIterator supperleft,
1839  SrcIterator slowerright, SrcAccessor src,
1840  DestIterator dupperleft, DestAccessor dest,
1841  double inner_scale, double outer_scale,
1842  VigraFalseType /* isScalar */)
1843 {
1844  int bands = src.size(supperleft);
1845  typedef VectorElementAccessor<SrcAccessor> SA;
1846 
1847  structureTensor(supperleft, slowerright, SA(0, src),
1848  dupperleft, dest,
1849  inner_scale, outer_scale,
1850  VigraTrueType() /* isScalar */);
1851 
1852  BasicImage<typename DestAccessor::value_type> st(slowerright - supperleft, SkipInitialization);
1853  for(int k=1; k < bands; ++k)
1854  {
1855  structureTensor(supperleft, slowerright, SA(k, src),
1856  st.upperLeft(), st.accessor(),
1857  inner_scale, outer_scale,
1858  VigraTrueType() /* isScalar */);
1859  combineTwoImages(srcImageRange(st), srcIter(dupperleft, dest), destIter(dupperleft, dest),
1860  std::plus<typename DestAccessor::value_type>());
1861  }
1862 }
1863 
1864 } // namespace detail
1865 
1866 template <class SrcIterator, class SrcAccessor,
1867  class DestIterator, class DestAccessor>
1868 void structureTensor(SrcIterator supperleft,
1869  SrcIterator slowerright, SrcAccessor src,
1870  DestIterator dupperleft, DestAccessor dest,
1871  double inner_scale, double outer_scale)
1872 {
1873  typedef typename
1874  NumericTraits<typename SrcAccessor::value_type>::isScalar isScalar;
1875  detail::structureTensor(supperleft, slowerright, src,
1876  dupperleft, dest, inner_scale, outer_scale, isScalar());
1877 }
1878 
1879 template <class SrcIterator, class SrcAccessor,
1880  class DestIterator, class DestAccessor>
1881 inline void
1882 structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1883  pair<DestIterator, DestAccessor> dest,
1884  double inner_scale, double outer_scale)
1885 {
1886  structureTensor(src.first, src.second, src.third,
1887  dest.first, dest.second,
1888  inner_scale, outer_scale);
1889 }
1890 
1891 template <class T1, class S1,
1892  class T2, class S2>
1893 inline void
1894 structureTensor(MultiArrayView<2, T1, S1> const & src,
1895  MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
1896  double inner_scale, double outer_scale)
1897 {
1898  vigra_precondition(src.shape() == dest.shape(),
1899  "structureTensor(): shape mismatch between input and output.");
1900  structureTensor(srcImageRange(src),
1901  destImage(dest),
1902  inner_scale, outer_scale);
1903 }
1904 
1905 //@}
1906 
1907 } // namespace vigra
1908 
1909 #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.
IteratorTraits< traverser >::DefaultAccessor Accessor
Definition: basicimage.hxx:571
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.
Definition: accessor.hxx:43
void separableConvolveX(...)
Performs a 1 dimensional convolution in x direction.
BasicImageIterator< PIXELTYPE, PIXELTYPE ** > traverser
Definition: basicimage.hxx:526
doxygen_overloaded_function(template<... > void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
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