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