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

convolution.hxx
1 /************************************************************************/
2 /* */
3 /* Copyright 1998-2002 by Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 
37 #ifndef VIGRA_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 
47 /** \page Convolution Functions to Convolve Images and Signals
48 
49  1D and 2D filters, including separable and recursive convolution, and non-linear diffusion
50 
51  <b>\#include</b> <<a href="convolution_8hxx-source.html">vigra/convolution.hxx</a>><br>
52  Namespace: vigra
53 
54  <UL style="list-style-image:url(documents/bullet.gif)">
55  <LI> \ref CommonConvolutionFilters
56  <BR>&nbsp;&nbsp;&nbsp;<em>Short-hands for the most common 2D convolution filters</em>
57  <LI> \ref MultiArrayConvolutionFilters
58  <BR>&nbsp;&nbsp;&nbsp;<em>Convolution filters for arbitrary dimensional arrays (MultiArray etc.)</em>
59  <LI> \ref ResamplingConvolutionFilters
60  <BR>&nbsp;&nbsp;&nbsp;<em>Resampling convolution filters</em>
61  <LI> \ref StandardConvolution
62  <BR>&nbsp;&nbsp;&nbsp;<em>2D non-separable convolution, with and without ROI mask </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
129  \ref SeparableConvolution "one-dimensional and separable convolution functions".
130 
131  \section Kernel2dFactory kernel2d()
132 
133  Pass a \ref vigra::Kernel2D to a 2D (non-separable) convolution algorithm.
134 
135  These factories can be used to create argument objects when we
136  are given instances or subclasses of \ref vigra::Kernel2D
137  (analogous to the \ref ArgumentObjectFactories for images).
138  These factory functions access <TT>kernel.center()</TT>,
139  <TT>kernel.upperLeft()</TT>, <TT>kernel.lowerRight()</TT>, <TT>kernel.accessor()</TT>,
140  and <TT>kernel.borderTreatment()</TT> to obtain the necessary
141  information. The following factory functions are provided:
142 
143  <table>
144  <tr><th bgcolor="#f0e0c0" colspan=2 align=left>
145  <TT>\ref vigra::Kernel2D "vigra::Kernel2D<SomeType>" kernel;</TT>
146  </th>
147  </tr>
148  <tr><td>
149  <TT>kernel2d(kernel)</TT>
150  </td><td>
151  create argument object from information provided by
152  kernel
153 
154  </td></tr>
155  <tr><td>
156  <TT>kernel2d(kernel, vigra::BORDER_TREATMENT_CLIP)</TT>
157  </td><td>
158  create argument object from information provided by
159  kernel, but use given border treatment mode
160 
161  </td></tr>
162  <tr><td>
163  <TT>kernel2d(kerneliterator, kernelaccessor,</TT>
164  <TT> upperleft, lowerright,</TT>
165  <TT> vigra::BORDER_TREATMENT_CLIP)</TT>
166  </td><td>
167  create argument object from explicitly given iterator
168  (pointing to the center of th kernel), accessor,
169  upper left and lower right corners, and border treatment mode
170 
171  </table>
172 
173  For usage examples see \ref StandardConvolution "two-dimensional convolution functions".
174 */
175 
176 namespace vigra {
177 
178 
179 
180 /********************************************************/
181 /* */
182 /* Common convolution filters */
183 /* */
184 /********************************************************/
185 
186 /** \addtogroup CommonConvolutionFilters Common Filters
187 
188  These functions calculate common filters by appropriate sequences of calls
189  to \ref separableConvolveX() and \ref separableConvolveY().
190 */
191 //@{
192 
193 /********************************************************/
194 /* */
195 /* convolveImage */
196 /* */
197 /********************************************************/
198 
199 /** \brief Apply two separable filters successively, the first in x-direction,
200  the second in y-direction.
201 
202  This function is a shorthand for the concatenation of a call to
203  \ref separableConvolveX() and \ref separableConvolveY()
204  with the given kernels.
205 
206  <b> Declarations:</b>
207 
208  pass arguments explicitly:
209  \code
210  namespace vigra {
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  \endcode
220 
221 
222  use argument objects in conjunction with \ref ArgumentObjectFactories :
223  \code
224  namespace vigra {
225  template <class SrcIterator, class SrcAccessor,
226  class DestIterator, class DestAccessor,
227  class T>
228  inline void
229  convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
230  pair<DestIterator, DestAccessor> dest,
231  Kernel1D<T> const & kx, Kernel1D<T> const & ky);
232  }
233  \endcode
234 
235  <b> Usage:</b>
236 
237  <b>\#include</b> <<a href="convolution_8hxx-source.html">vigra/convolution.hxx</a>>
238 
239 
240  \code
241  vigra::FImage src(w,h), dest(w,h);
242  ...
243 
244  // implement sobel filter in x-direction
245  Kernel1D<double> kx, ky;
246  kx.initSymmetricGradient();
247  ky.initBinomial(1);
248 
249  vigra::convolveImage(srcImageRange(src), destImage(dest), kx, ky);
250 
251  \endcode
252 
253 */
254 template <class SrcIterator, class SrcAccessor,
255  class DestIterator, class DestAccessor,
256  class T>
257 void convolveImage(SrcIterator supperleft,
258  SrcIterator slowerright, SrcAccessor sa,
259  DestIterator dupperleft, DestAccessor da,
260  Kernel1D<T> const & kx, Kernel1D<T> const & ky)
261 {
262  typedef typename
263  NumericTraits<typename SrcAccessor::value_type>::RealPromote
264  TmpType;
265  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization);
266 
267  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
268  destImage(tmp), kernel1d(kx));
269  separableConvolveY(srcImageRange(tmp),
270  destIter(dupperleft, da), kernel1d(ky));
271 }
272 
273 template <class SrcIterator, class SrcAccessor,
274  class DestIterator, class DestAccessor,
275  class T>
276 inline void
277 convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
278  pair<DestIterator, DestAccessor> dest,
279  Kernel1D<T> const & kx, Kernel1D<T> const & ky)
280 {
281  convolveImage(src.first, src.second, src.third,
282  dest.first, dest.second, kx, ky);
283 }
284 
285 /********************************************************/
286 /* */
287 /* simpleSharpening */
288 /* */
289 /********************************************************/
290 
291 /** \brief Perform simple sharpening function.
292 
293  This function uses \ref convolveImage() with the following filter:
294 
295  \code
296  -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_factor/16.0,
297  -sharpening_factor/8.0, 1.0+sharpening_factor*0.75, -sharpening_factor/8.0,
298  -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_factor/16.0;
299  \endcode
300 
301  and uses <TT>BORDER_TREATMENT_REFLECT</TT> as border treatment mode.
302 
303  <b> Preconditions:</b>
304  \code
305  1. sharpening_factor >= 0
306  2. scale >= 0
307  \endcode
308 
309  <b> Declarations:</b>
310 
311  <b> Declarations:</b>
312 
313  pass arguments explicitly:
314  \code
315  namespace vigra {
316  template <class SrcIterator, class SrcAccessor,
317  class DestIterator, class DestAccessor>
318  void simpleSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
319  DestIterator dest_ul, DestAccessor dest_acc, double sharpening_factor)
320 
321  }
322  \endcode
323 
324 
325  use argument objects in conjunction with \ref ArgumentObjectFactories :
326  \code
327  namespace vigra {
328  template <class SrcIterator, class SrcAccessor,
329  class DestIterator, class DestAccessor>
330  inline
331  void simpleSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
332  pair<DestIterator, DestAccessor> dest, double sharpening_factor)
333  {
334  simpleSharpening(src.first, src.second, src.third,
335  dest.first, dest.second, sharpening_factor);
336  }
337 
338  }
339  \endcode
340 
341  <b> Usage:</b>
342 
343  <b>\#include</b> <<a href="convolution_8hxx-source.html">vigra/convolution.hxx</a>>
344 
345 
346  \code
347  vigra::FImage src(w,h), dest(w,h);
348  ...
349 
350  // sharpening with sharpening_factor = 0.1
351  vigra::simpleSharpening(srcImageRange(src), destImage(dest), 0.1);
352 
353  \endcode
354 
355 */
357 
358 template <class SrcIterator, class SrcAccessor,
359  class DestIterator, class DestAccessor>
360 void simpleSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
361  DestIterator dest_ul, DestAccessor dest_acc, double sharpening_factor)
362 {
363 
364  vigra_precondition(sharpening_factor >= 0.0,
365  "simpleSharpening(): amount of sharpening must be >= 0.");
366 
367  Kernel2D<double> kernel;
368 
369  kernel.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) = -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_factor/16.0,
370  -sharpening_factor/8.0, 1.0+sharpening_factor*0.75, -sharpening_factor/8.0,
371  -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_factor/16.0;
372 
373  convolveImage(src_ul, src_lr, src_acc, dest_ul, dest_acc,
374  kernel.center(), kernel.accessor(),
375  kernel.upperLeft(), kernel.lowerRight() , BORDER_TREATMENT_REFLECT );
376 }
377 
378 template <class SrcIterator, class SrcAccessor,
379  class DestIterator, class DestAccessor>
380 inline
381 void simpleSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
382  pair<DestIterator, DestAccessor> dest, double sharpening_factor)
383 {
384  simpleSharpening(src.first, src.second, src.third,
385  dest.first, dest.second, sharpening_factor);
386 }
387 
388 
389 /********************************************************/
390 /* */
391 /* gaussianSharpening */
392 /* */
393 /********************************************************/
394 
395 /** \brief Perform sharpening function with gaussian filter.
396 
397 
398  This function uses \ref gaussianSmoothing() at the given scale to create a
399  temporary image 'smooth' and than blends the original and smoothed image
400  according to the formula
401 
402  \code
403  dest = (1 + sharpening_factor)*src - sharpening_factor*smooth
404  \endcode
405 
406  <b> Preconditions:</b>
407  \code
408  1. sharpening_factor >= 0
409  2. scale >= 0
410  \endcode
411 
412  <b> Declarations:</b>
413 
414  pass arguments explicitly:
415  \code
416  namespace vigra {
417  template <class SrcIterator, class SrcAccessor,
418  class DestIterator, class DestAccessor>
419  void gaussianSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
420  DestIterator dest_ul, DestAccessor dest_acc,
421  double sharpening_factor, double scale)
422  }
423  \endcode
424 
425 
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 gaussianSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
432  pair<DestIterator, DestAccessor> dest,
433  double sharpening_factor, double scale)
434  }
435  \endcode
436 
437  <b> Usage:</b>
438 
439  <b>\#include</b> <<a href="convolution_8hxx-source.html">vigra/convolution.hxx</a>>
440 
441 
442  \code
443  vigra::FImage src(w,h), dest(w,h);
444  ...
445 
446  // sharpening with sharpening_factor = 3.0
447  // smoothing with scale = 0.5
448  vigra::gaussianSmoothing(srcImageRange(src), destImage(dest), 3.0, 0.5);
449 
450  \endcode
451 
452 */
454 
455 template <class SrcIterator, class SrcAccessor,
456  class DestIterator, class DestAccessor>
457 void gaussianSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
458  DestIterator dest_ul, DestAccessor dest_acc, double sharpening_factor,
459  double scale)
460 {
461  vigra_precondition(sharpening_factor >= 0.0,
462  "gaussianSharpening(): amount of sharpening must be >= 0");
463  vigra_precondition(scale >= 0.0,
464  "gaussianSharpening(): scale parameter should be >= 0.");
465 
466  typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote ValueType;
467 
468  BasicImage<ValueType> tmp(src_lr - src_ul, SkipInitialization);
469 
470  gaussianSmoothing(src_ul, src_lr, src_acc, tmp.upperLeft(), tmp.accessor(), scale);
471 
472  SrcIterator i_src = src_ul;
473  DestIterator i_dest = dest_ul;
474  typename BasicImage<ValueType>::traverser tmp_ul = tmp.upperLeft();
475  typename BasicImage<ValueType>::traverser i_tmp = tmp_ul;
476  typename BasicImage<ValueType>::Accessor tmp_acc = tmp.accessor();
477 
478  for(; i_src.y != src_lr.y ; i_src.y++, i_dest.y++, i_tmp.y++ )
479  {
480  for (;i_src.x != src_lr.x ; i_src.x++, i_dest.x++, i_tmp.x++ )
481  {
482  dest_acc.set((1.0 + sharpening_factor)*src_acc(i_src) - sharpening_factor*tmp_acc(i_tmp), i_dest);
483  }
484  i_src.x = src_ul.x;
485  i_dest.x = dest_ul.x;
486  i_tmp.x = tmp_ul.x;
487  }
488 }
489 
490 template <class SrcIterator, class SrcAccessor,
491  class DestIterator, class DestAccessor>
492 void gaussianSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
493  pair<DestIterator, DestAccessor> dest, double sharpening_factor,
494  double scale)
495 {
496  gaussianSharpening(src.first, src.second, src.third,
497  dest.first, dest.second,
498  sharpening_factor, scale);
499 }
500 
501 
502 
503 /********************************************************/
504 /* */
505 /* gaussianSmoothing */
506 /* */
507 /********************************************************/
508 
509 /** \brief Perform isotropic Gaussian convolution.
510 
511  This function is a shorthand for the concatenation of a call to
512  \ref separableConvolveX() and \ref separableConvolveY() with a
513  Gaussian kernel of the given scale. If two scales are provided,
514  smoothing in x and y direction will have different strength.
515  The function uses <TT>BORDER_TREATMENT_REFLECT</TT>.
516 
517  <b> Declarations:</b>
518 
519  pass arguments explicitly:
520  \code
521  namespace vigra {
522  template <class SrcIterator, class SrcAccessor,
523  class DestIterator, class DestAccessor>
524  void gaussianSmoothing(SrcIterator supperleft,
525  SrcIterator slowerright, SrcAccessor sa,
526  DestIterator dupperleft, DestAccessor da,
527  double scale_x, double scale_y = scale_x);
528  }
529  \endcode
530 
531 
532  use argument objects in conjunction with \ref ArgumentObjectFactories :
533  \code
534  namespace vigra {
535  template <class SrcIterator, class SrcAccessor,
536  class DestIterator, class DestAccessor>
537  inline void
538  gaussianSmoothing(triple<SrcIterator, SrcIterator, SrcAccessor> src,
539  pair<DestIterator, DestAccessor> dest,
540  double scale_x, double scale_y = scale_x);
541  }
542  \endcode
543 
544  <b> Usage:</b>
545 
546  <b>\#include</b> <<a href="convolution_8hxx-source.html">vigra/convolution.hxx</a>>
547 
548 
549  \code
550  vigra::FImage src(w,h), dest(w,h);
551  ...
552 
553  // smooth with scale = 3.0
554  vigra::gaussianSmoothing(srcImageRange(src), destImage(dest), 3.0);
555 
556  \endcode
557 
558 */
560 
561 template <class SrcIterator, class SrcAccessor,
562  class DestIterator, class DestAccessor>
563 void
564 gaussianSmoothing(SrcIterator supperleft, SrcIterator slowerright, SrcAccessor sa,
565  DestIterator dupperleft, DestAccessor da,
566  double scale_x, double scale_y)
567 {
568  typedef typename
569  NumericTraits<typename SrcAccessor::value_type>::RealPromote
570  TmpType;
571  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization);
572 
573  Kernel1D<double> smooth_x, smooth_y;
574  smooth_x.initGaussian(scale_x);
575  smooth_x.setBorderTreatment(BORDER_TREATMENT_REFLECT);
576  smooth_y.initGaussian(scale_y);
577  smooth_y.setBorderTreatment(BORDER_TREATMENT_REFLECT);
578 
579  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
580  destImage(tmp), kernel1d(smooth_x));
581  separableConvolveY(srcImageRange(tmp),
582  destIter(dupperleft, da), kernel1d(smooth_y));
583 }
584 
585 template <class SrcIterator, class SrcAccessor,
586  class DestIterator, class DestAccessor>
587 inline void
588 gaussianSmoothing(SrcIterator supperleft, SrcIterator slowerright, SrcAccessor sa,
589  DestIterator dupperleft, DestAccessor da,
590  double scale)
591 {
592  gaussianSmoothing(supperleft, slowerright, sa,
593  dupperleft, da,
594  scale, scale);
595 }
596 
597 template <class SrcIterator, class SrcAccessor,
598  class DestIterator, class DestAccessor>
599 inline void
600 gaussianSmoothing(triple<SrcIterator, SrcIterator, SrcAccessor> src,
601  pair<DestIterator, DestAccessor> dest,
602  double scale_x, double scale_y)
603 {
604  gaussianSmoothing(src.first, src.second, src.third,
605  dest.first, dest.second, scale_x, scale_y);
606 }
607 
608 template <class SrcIterator, class SrcAccessor,
609  class DestIterator, class DestAccessor>
610 inline void
611 gaussianSmoothing(triple<SrcIterator, SrcIterator, SrcAccessor> src,
612  pair<DestIterator, DestAccessor> dest,
613  double scale)
614 {
615  gaussianSmoothing(src.first, src.second, src.third,
616  dest.first, dest.second, scale, scale);
617 }
618 
619 /********************************************************/
620 /* */
621 /* gaussianGradient */
622 /* */
623 /********************************************************/
624 
625 /** \brief Calculate the gradient vector by means of a 1st derivatives of
626  Gaussian filter.
627 
628  This function is a shorthand for the concatenation of a call to
629  \ref separableConvolveX() and \ref separableConvolveY() with the
630  appropriate kernels at the given scale. Note that this function can either produce
631  two separate result images for the x- and y-components of the gradient, or write
632  into a vector valued image (with at least two components).
633 
634  <b> Declarations:</b>
635 
636  pass arguments explicitly:
637  \code
638  namespace vigra {
639  // write x and y component of the gradient into separate images
640  template <class SrcIterator, class SrcAccessor,
641  class DestIteratorX, class DestAccessorX,
642  class DestIteratorY, class DestAccessorY>
643  void gaussianGradient(SrcIterator supperleft,
644  SrcIterator slowerright, SrcAccessor sa,
645  DestIteratorX dupperleftx, DestAccessorX dax,
646  DestIteratorY dupperlefty, DestAccessorY day,
647  double scale);
648 
649  // write x and y component of the gradient into a vector-valued image
650  template <class SrcIterator, class SrcAccessor,
651  class DestIterator, class DestAccessor>
652  void gaussianGradient(SrcIterator supperleft,
653  SrcIterator slowerright, SrcAccessor src,
654  DestIterator dupperleft, DestAccessor dest,
655  double scale);
656  }
657  \endcode
658 
659 
660  use argument objects in conjunction with \ref ArgumentObjectFactories :
661  \code
662  namespace vigra {
663  // write x and y component of the gradient into separate images
664  template <class SrcIterator, class SrcAccessor,
665  class DestIteratorX, class DestAccessorX,
666  class DestIteratorY, class DestAccessorY>
667  void
668  gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src,
669  pair<DestIteratorX, DestAccessorX> destx,
670  pair<DestIteratorY, DestAccessorY> desty,
671  double scale);
672 
673  // write x and y component of the gradient into a vector-valued image
674  template <class SrcIterator, class SrcAccessor,
675  class DestIterator, class DestAccessor>
676  void
677  gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src,
678  pair<DestIterator, DestAccessor> dest,
679  double scale);
680  }
681  \endcode
682 
683  <b> Usage:</b>
684 
685  <b>\#include</b> <<a href="convolution_8hxx-source.html">vigra/convolution.hxx</a>>
686 
687 
688  \code
689  vigra::FImage src(w,h), gradx(w,h), grady(w,h);
690  ...
691 
692  // calculate gradient vector at scale = 3.0
693  vigra::gaussianGradient(srcImageRange(src),
694  destImage(gradx), destImage(grady), 3.0);
695 
696  \endcode
697 
698 */
700 
701 template <class SrcIterator, class SrcAccessor,
702  class DestIteratorX, class DestAccessorX,
703  class DestIteratorY, class DestAccessorY>
704 void gaussianGradient(SrcIterator supperleft,
705  SrcIterator slowerright, SrcAccessor sa,
706  DestIteratorX dupperleftx, DestAccessorX dax,
707  DestIteratorY dupperlefty, DestAccessorY day,
708  double scale)
709 {
710  typedef typename
711  NumericTraits<typename SrcAccessor::value_type>::RealPromote
712  TmpType;
713  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization);
714 
715  Kernel1D<double> smooth, grad;
716  smooth.initGaussian(scale);
717  grad.initGaussianDerivative(scale, 1);
718 
719  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
720  destImage(tmp), kernel1d(grad));
721  separableConvolveY(srcImageRange(tmp),
722  destIter(dupperleftx, dax), kernel1d(smooth));
723  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
724  destImage(tmp), kernel1d(smooth));
725  separableConvolveY(srcImageRange(tmp),
726  destIter(dupperlefty, day), kernel1d(grad));
727 }
728 
729 template <class SrcIterator, class SrcAccessor,
730  class DestIterator, class DestAccessor>
731 void gaussianGradient(SrcIterator supperleft,
732  SrcIterator slowerright, SrcAccessor src,
733  DestIterator dupperleft, DestAccessor dest,
734  double scale)
735 {
736  VectorElementAccessor<DestAccessor> gradx(0, dest), grady(1, dest);
737  gaussianGradient(supperleft, slowerright, src,
738  dupperleft, gradx, dupperleft, grady, scale);
739 }
740 
741 template <class SrcIterator, class SrcAccessor,
742  class DestIteratorX, class DestAccessorX,
743  class DestIteratorY, class DestAccessorY>
744 inline void
745 gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src,
746  pair<DestIteratorX, DestAccessorX> destx,
747  pair<DestIteratorY, DestAccessorY> desty,
748  double scale)
749 {
750  gaussianGradient(src.first, src.second, src.third,
751  destx.first, destx.second, desty.first, desty.second, scale);
752 }
753 
754 template <class SrcIterator, class SrcAccessor,
755  class DestIterator, class DestAccessor>
756 inline void
757 gaussianGradient(triple<SrcIterator, SrcIterator, SrcAccessor> src,
758  pair<DestIterator, DestAccessor> dest,
759  double scale)
760 {
761  gaussianGradient(src.first, src.second, src.third,
762  dest.first, dest.second, scale);
763 }
764 
765 /** \brief Calculate the gradient magnitude by means of a 1st derivatives of
766  Gaussian filter.
767 
768  This function calls gaussianGradient() and returns the pixel-wise magnitude of
769  the resulting gradient vectors. If the original image has multiple bands,
770  the squared gradient magnitude is computed for each band separately, and the
771  return value is the square root of the sum of these sqaured magnitudes.
772 
773  <b> Declarations:</b>
774 
775  pass arguments explicitly:
776  \code
777  namespace vigra {
778  template <class SrcIterator, class SrcAccessor,
779  class DestIterator, class DestAccessor>
780  void gaussianGradientMagnitude(SrcIterator sul,
781  SrcIterator slr, SrcAccessor src,
782  DestIterator dupperleft, DestAccessor dest,
783  double scale);
784  }
785  \endcode
786 
787 
788  use argument objects in conjunction with \ref ArgumentObjectFactories :
789  \code
790  namespace vigra {
791  template <class SrcIterator, class SrcAccessor,
792  class DestIterator, class DestAccessor>
793  void
794  gaussianGradientMagnitude(triple<SrcIterator, SrcIterator, SrcAccessor> src,
795  pair<DestIterator, DestAccessor> dest,
796  double scale);
797  }
798  \endcode
799 
800  <b> Usage:</b>
801 
802  <b>\#include</b> <<a href="convolution_8hxx-source.html">vigra/convolution.hxx</a>>
803 
804 
805  \code
806  vigra::FImage src(w,h), grad(w,h);
807  ...
808 
809  // calculate gradient magnitude at scale = 3.0
810  vigra::gaussianGradientMagnitude(srcImageRange(src), destImage(grad), 3.0);
811 
812  \endcode
813 
814 */
816 
817 template <class SrcIterator, class SrcAccessor,
818  class DestIterator, class DestAccessor>
819 void gaussianGradientMagnitude(SrcIterator sul,
820  SrcIterator slr, SrcAccessor src,
821  DestIterator dupperleft, DestAccessor dest,
822  double scale)
823 {
824  typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
825  BasicImage<TmpType> gradx(slr-sul, SkipInitialization), grady(slr-sul, SkipInitialization);
826 
827  gaussianGradient(srcIterRange(sul, slr, src),
828  destImage(gradx), destImage(grady), scale);
829  combineTwoImages(srcImageRange(gradx), srcImage(grady), destIter(dupperleft, dest),
830  MagnitudeFunctor<TmpType>());
831 }
832 
833 template <class SrcIterator, class SrcAccessor,
834  class DestIterator, class DestAccessor>
835 inline void
836 gaussianGradientMagnitude(triple<SrcIterator, SrcIterator, SrcAccessor> src,
837  pair<DestIterator, DestAccessor> dest,
838  double scale)
839 {
840  gaussianGradientMagnitude(src.first, src.second, src.third,
841  dest.first, dest.second, scale);
842 }
843 
844 /********************************************************/
845 /* */
846 /* laplacianOfGaussian */
847 /* */
848 /********************************************************/
849 
850 /** \brief Filter image with the Laplacian of Gaussian operator
851  at the given scale.
852 
853  This function calls \ref separableConvolveX() and \ref separableConvolveY() with the appropriate 2nd derivative
854  of Gaussian kernels in x- and y-direction and then sums the results
855  to get the Laplacian.
856 
857  <b> Declarations:</b>
858 
859  pass arguments explicitly:
860  \code
861  namespace vigra {
862  template <class SrcIterator, class SrcAccessor,
863  class DestIterator, class DestAccessor>
864  void laplacianOfGaussian(SrcIterator supperleft,
865  SrcIterator slowerright, SrcAccessor sa,
866  DestIterator dupperleft, DestAccessor da,
867  double scale);
868  }
869  \endcode
870 
871 
872  use argument objects in conjunction with \ref ArgumentObjectFactories :
873  \code
874  namespace vigra {
875  template <class SrcIterator, class SrcAccessor,
876  class DestIterator, class DestAccessor>
877  inline void
878  laplacianOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
879  pair<DestIterator, DestAccessor> dest,
880  double scale);
881  }
882  \endcode
883 
884  <b> Usage:</b>
885 
886  <b>\#include</b> <<a href="convolution_8hxx-source.html">vigra/convolution.hxx</a>>
887 
888 
889  \code
890  vigra::FImage src(w,h), dest(w,h);
891  ...
892 
893  // calculate Laplacian of Gaussian at scale = 3.0
894  vigra::laplacianOfGaussian(srcImageRange(src), destImage(dest), 3.0);
895 
896  \endcode
897 
898 */
900 
901 template <class SrcIterator, class SrcAccessor,
902  class DestIterator, class DestAccessor>
903 void laplacianOfGaussian(SrcIterator supperleft,
904  SrcIterator slowerright, SrcAccessor sa,
905  DestIterator dupperleft, DestAccessor da,
906  double scale)
907 {
908  typedef typename
909  NumericTraits<typename SrcAccessor::value_type>::RealPromote
910  TmpType;
911  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization),
912  tmpx(slowerright - supperleft, SkipInitialization),
913  tmpy(slowerright - supperleft, SkipInitialization);
914 
915  Kernel1D<double> smooth, deriv;
916  smooth.initGaussian(scale);
917  deriv.initGaussianDerivative(scale, 2);
918 
919  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
920  destImage(tmp), kernel1d(deriv));
921  separableConvolveY(srcImageRange(tmp),
922  destImage(tmpx), kernel1d(smooth));
923  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
924  destImage(tmp), kernel1d(smooth));
925  separableConvolveY(srcImageRange(tmp),
926  destImage(tmpy), kernel1d(deriv));
927  combineTwoImages(srcImageRange(tmpx), srcImage(tmpy),
928  destIter(dupperleft, da), std::plus<TmpType>());
929 }
930 
931 template <class SrcIterator, class SrcAccessor,
932  class DestIterator, class DestAccessor>
933 inline void
934 laplacianOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
935  pair<DestIterator, DestAccessor> dest,
936  double scale)
937 {
938  laplacianOfGaussian(src.first, src.second, src.third,
939  dest.first, dest.second, scale);
940 }
941 
942 /********************************************************/
943 /* */
944 /* hessianMatrixOfGaussian */
945 /* */
946 /********************************************************/
947 
948 /** \brief Filter image with the 2nd derivatives of the Gaussian
949  at the given scale to get the Hessian matrix.
950 
951  The Hessian matrix is a symmetric matrix defined as:
952 
953  \f[
954  \mbox{\rm Hessian}(I) = \left(
955  \begin{array}{cc}
956  G_{xx} \ast I & G_{xy} \ast I \\
957  G_{xy} \ast I & G_{yy} \ast I
958  \end{array} \right)
959  \f]
960 
961  where \f$G_{xx}, G_{xy}, G_{yy}\f$ denote 2nd derivatives of Gaussians
962  at the given scale, and
963  \f$\ast\f$ is the convolution symbol. This function calls
964  \ref separableConvolveX() and \ref separableConvolveY()
965  with the appropriate 2nd derivative
966  of Gaussian kernels and puts the results in
967  the three destination images. The first destination image will
968  contain the second derivative in x-direction, the second one the mixed
969  derivative, and the third one holds the derivative in y-direction.
970 
971  <b> Declarations:</b>
972 
973  pass arguments explicitly:
974  \code
975  namespace vigra {
976  template <class SrcIterator, class SrcAccessor,
977  class DestIteratorX, class DestAccessorX,
978  class DestIteratorXY, class DestAccessorXY,
979  class DestIteratorY, class DestAccessorY>
980  void hessianMatrixOfGaussian(SrcIterator supperleft,
981  SrcIterator slowerright, SrcAccessor sa,
982  DestIteratorX dupperleftx, DestAccessorX dax,
983  DestIteratorXY dupperleftxy, DestAccessorXY daxy,
984  DestIteratorY dupperlefty, DestAccessorY day,
985  double scale);
986  }
987  \endcode
988 
989 
990  use argument objects in conjunction with \ref ArgumentObjectFactories :
991  \code
992  namespace vigra {
993  template <class SrcIterator, class SrcAccessor,
994  class DestIteratorX, class DestAccessorX,
995  class DestIteratorXY, class DestAccessorXY,
996  class DestIteratorY, class DestAccessorY>
997  inline void
998  hessianMatrixOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
999  pair<DestIteratorX, DestAccessorX> destx,
1000  pair<DestIteratorXY, DestAccessorXY> destxy,
1001  pair<DestIteratorY, DestAccessorY> desty,
1002  double scale);
1003  }
1004  \endcode
1005 
1006  <b> Usage:</b>
1007 
1008  <b>\#include</b> <<a href="convolution_8hxx-source.html">vigra/convolution.hxx</a>>
1009 
1010 
1011  \code
1012  vigra::FImage src(w,h), hxx(w,h), hxy(w,h), hyy(w,h);
1013  ...
1014 
1015  // calculate Hessian of Gaussian at scale = 3.0
1016  vigra::hessianMatrixOfGaussian(srcImageRange(src),
1017  destImage(hxx), destImage(hxy), destImage(hyy), 3.0);
1018 
1019  \endcode
1020 
1021 */
1023 
1024 template <class SrcIterator, class SrcAccessor,
1025  class DestIteratorX, class DestAccessorX,
1026  class DestIteratorXY, class DestAccessorXY,
1027  class DestIteratorY, class DestAccessorY>
1028 void hessianMatrixOfGaussian(SrcIterator supperleft,
1029  SrcIterator slowerright, SrcAccessor sa,
1030  DestIteratorX dupperleftx, DestAccessorX dax,
1031  DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1032  DestIteratorY dupperlefty, DestAccessorY day,
1033  double scale)
1034 {
1035  typedef typename
1036  NumericTraits<typename SrcAccessor::value_type>::RealPromote
1037  TmpType;
1038  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization);
1039 
1040  Kernel1D<double> smooth, deriv1, deriv2;
1041  smooth.initGaussian(scale);
1042  deriv1.initGaussianDerivative(scale, 1);
1043  deriv2.initGaussianDerivative(scale, 2);
1044 
1045  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1046  destImage(tmp), kernel1d(deriv2));
1047  separableConvolveY(srcImageRange(tmp),
1048  destIter(dupperleftx, dax), kernel1d(smooth));
1049  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1050  destImage(tmp), kernel1d(smooth));
1051  separableConvolveY(srcImageRange(tmp),
1052  destIter(dupperlefty, day), kernel1d(deriv2));
1053  separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1054  destImage(tmp), kernel1d(deriv1));
1055  separableConvolveY(srcImageRange(tmp),
1056  destIter(dupperleftxy, daxy), kernel1d(deriv1));
1057 }
1058 
1059 template <class SrcIterator, class SrcAccessor,
1060  class DestIteratorX, class DestAccessorX,
1061  class DestIteratorXY, class DestAccessorXY,
1062  class DestIteratorY, class DestAccessorY>
1063 inline void
1064 hessianMatrixOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1065  pair<DestIteratorX, DestAccessorX> destx,
1066  pair<DestIteratorXY, DestAccessorXY> destxy,
1067  pair<DestIteratorY, DestAccessorY> desty,
1068  double scale)
1069 {
1070  hessianMatrixOfGaussian(src.first, src.second, src.third,
1071  destx.first, destx.second,
1072  destxy.first, destxy.second,
1073  desty.first, desty.second,
1074  scale);
1075 }
1076 
1077 /********************************************************/
1078 /* */
1079 /* structureTensor */
1080 /* */
1081 /********************************************************/
1082 
1083 /** \brief Calculate the Structure Tensor for each pixel of
1084  and image, using Gaussian (derivative) filters.
1085 
1086  The Structure Tensor is is a smoothed version of the Euclidean product
1087  of the gradient vector with itself. I.e. it's a symmetric matrix defined as:
1088 
1089  \f[
1090  \mbox{\rm StructurTensor}(I) = \left(
1091  \begin{array}{cc}
1092  G \ast (I_x I_x) & G \ast (I_x I_y) \\
1093  G \ast (I_x I_y) & G \ast (I_y I_y)
1094  \end{array} \right) = \left(
1095  \begin{array}{cc}
1096  A & C \\
1097  C & B
1098  \end{array} \right)
1099  \f]
1100 
1101  where \f$G\f$ denotes Gaussian smoothing at the <i>outer scale</i>,
1102  \f$I_x, I_y\f$ are the gradient components taken at the <i>inner scale</i>,
1103  \f$\ast\f$ is the convolution symbol, and \f$I_x I_x\f$ etc. are pixelwise
1104  products of the 1st derivative images. This function calls
1105  \ref separableConvolveX() and \ref separableConvolveY() with the
1106  appropriate Gaussian kernels and puts the results in
1107  the three separate destination images (where the first one will
1108  contain \f$G \ast (I_x I_x)\f$, the second one \f$G \ast (I_x I_y)\f$, and the
1109  third one holds \f$G \ast (I_y I_y)\f$), or into a single 3-band image (where the bands
1110  hold the result in the same order as above). The latter form is also applicable when
1111  the source image is a multi-band image (e.g. RGB). In this case, tensors are
1112  first computed for each band separately, and then summed up to get a single result tensor.
1113 
1114  <b> Declarations:</b>
1115 
1116  pass arguments explicitly:
1117  \code
1118  namespace vigra {
1119  // create three separate destination images
1120  template <class SrcIterator, class SrcAccessor,
1121  class DestIteratorX, class DestAccessorX,
1122  class DestIteratorXY, class DestAccessorXY,
1123  class DestIteratorY, class DestAccessorY>
1124  void structureTensor(SrcIterator supperleft,
1125  SrcIterator slowerright, SrcAccessor sa,
1126  DestIteratorX dupperleftx, DestAccessorX dax,
1127  DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1128  DestIteratorY dupperlefty, DestAccessorY day,
1129  double inner_scale, double outer_scale);
1130 
1131  // create a single 3-band destination image
1132  template <class SrcIterator, class SrcAccessor,
1133  class DestIterator, class DestAccessor>
1134  void structureTensor(SrcIterator supperleft,
1135  SrcIterator slowerright, SrcAccessor sa,
1136  DestIterator dupperleft, DestAccessor da,
1137  double inner_scale, double outer_scale);
1138  }
1139  \endcode
1140 
1141 
1142  use argument objects in conjunction with \ref ArgumentObjectFactories :
1143  \code
1144  namespace vigra {
1145  // create three separate destination images
1146  template <class SrcIterator, class SrcAccessor,
1147  class DestIteratorX, class DestAccessorX,
1148  class DestIteratorXY, class DestAccessorXY,
1149  class DestIteratorY, class DestAccessorY>
1150  void
1151  structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1152  pair<DestIteratorX, DestAccessorX> destx,
1153  pair<DestIteratorXY, DestAccessorXY> destxy,
1154  pair<DestIteratorY, DestAccessorY> desty,
1155  double nner_scale, double outer_scale);
1156 
1157  // create a single 3-band destination image
1158  template <class SrcIterator, class SrcAccessor,
1159  class DestIterator, class DestAccessor>
1160  void
1161  structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1162  pair<DestIterator, DestAccessor> dest,
1163  double nner_scale, double outer_scale);
1164  }
1165  \endcode
1166 
1167  <b> Usage:</b>
1168 
1169  <b>\#include</b> <<a href="convolution_8hxx-source.html">vigra/convolution.hxx</a>>
1170 
1171 
1172  \code
1173  vigra::FImage src(w,h), stxx(w,h), stxy(w,h), styy(w,h);
1174  vigra::BasicImage<TinyVector<float, 3> > st(w,h);
1175  ...
1176 
1177  // calculate Structure Tensor at inner scale = 1.0 and outer scale = 3.0
1178  vigra::structureTensor(srcImageRange(src),
1179  destImage(stxx), destImage(stxy), destImage(styy), 1.0, 3.0);
1180 
1181  // dto. with a single 3-band destination image
1182  vigra::structureTensor(srcImageRange(src), destImage(st), 1.0, 3.0);
1183 
1184  \endcode
1185 
1186 */
1187 doxygen_overloaded_function(template <...> void structureTensor)
1188 
1189 template <class SrcIterator, class SrcAccessor,
1190  class DestIteratorX, class DestAccessorX,
1191  class DestIteratorXY, class DestAccessorXY,
1192  class DestIteratorY, class DestAccessorY>
1193 void structureTensor(SrcIterator supperleft,
1194  SrcIterator slowerright, SrcAccessor sa,
1195  DestIteratorX dupperleftx, DestAccessorX dax,
1196  DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1197  DestIteratorY dupperlefty, DestAccessorY day,
1198  double inner_scale, double outer_scale)
1199 {
1200  typedef typename
1201  NumericTraits<typename SrcAccessor::value_type>::RealPromote
1202  TmpType;
1203  BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization),
1204  tmpx(slowerright - supperleft, SkipInitialization),
1205  tmpy(slowerright - supperleft, SkipInitialization);
1206 
1207  gaussianGradient(srcIterRange(supperleft, slowerright, sa),
1208  destImage(tmpx), destImage(tmpy), inner_scale);
1209  combineTwoImages(srcImageRange(tmpx), srcImage(tmpx),
1210  destImage(tmp), std::multiplies<TmpType>());
1211  gaussianSmoothing(srcImageRange(tmp),
1212  destIter(dupperleftx, dax), outer_scale);
1213  combineTwoImages(srcImageRange(tmpy), srcImage(tmpy),
1214  destImage(tmp), std::multiplies<TmpType>());
1215  gaussianSmoothing(srcImageRange(tmp),
1216  destIter(dupperlefty, day), outer_scale);
1217  combineTwoImages(srcImageRange(tmpx), srcImage(tmpy),
1218  destImage(tmp), std::multiplies<TmpType>());
1219  gaussianSmoothing(srcImageRange(tmp),
1220  destIter(dupperleftxy, daxy), outer_scale);
1221 }
1222 
1223 template <class SrcIterator, class SrcAccessor,
1224  class DestIteratorX, class DestAccessorX,
1225  class DestIteratorXY, class DestAccessorXY,
1226  class DestIteratorY, class DestAccessorY>
1227 inline void
1228 structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1229  pair<DestIteratorX, DestAccessorX> destx,
1230  pair<DestIteratorXY, DestAccessorXY> destxy,
1231  pair<DestIteratorY, DestAccessorY> desty,
1232  double inner_scale, double outer_scale)
1233 {
1234  structureTensor(src.first, src.second, src.third,
1235  destx.first, destx.second,
1236  destxy.first, destxy.second,
1237  desty.first, desty.second,
1238  inner_scale, outer_scale);
1239 }
1240 
1241 namespace detail {
1242 
1243 template <class SrcIterator, class SrcAccessor,
1244  class DestIterator, class DestAccessor>
1245 void structureTensor(SrcIterator supperleft,
1246  SrcIterator slowerright, SrcAccessor src,
1247  DestIterator dupperleft, DestAccessor dest,
1248  double inner_scale, double outer_scale,
1249  VigraTrueType /* isScalar */)
1250 {
1251  typedef VectorElementAccessor<DestAccessor> DA;
1252  structureTensor(supperleft, slowerright, src,
1253  dupperleft, DA(0, dest),
1254  dupperleft, DA(1, dest),
1255  dupperleft, DA(2, dest),
1256  inner_scale, outer_scale);
1257 }
1258 
1259 template <class SrcIterator, class SrcAccessor,
1260  class DestIterator, class DestAccessor>
1261 void structureTensor(SrcIterator supperleft,
1262  SrcIterator slowerright, SrcAccessor src,
1263  DestIterator dupperleft, DestAccessor dest,
1264  double inner_scale, double outer_scale,
1265  VigraFalseType /* isScalar */)
1266 {
1267  int bands = src.size(supperleft);
1268  typedef VectorElementAccessor<SrcAccessor> SA;
1269 
1270  structureTensor(supperleft, slowerright, SA(0, src),
1271  dupperleft, dest,
1272  inner_scale, outer_scale,
1273  VigraTrueType() /* isScalar */);
1274 
1275  BasicImage<typename DestAccessor::value_type> st(slowerright - supperleft, SkipInitialization);
1276  for(int k=1; k < bands; ++k)
1277  {
1278  structureTensor(supperleft, slowerright, SA(k, src),
1279  st.upperLeft(), st.accessor(),
1280  inner_scale, outer_scale,
1281  VigraTrueType() /* isScalar */);
1282  combineTwoImages(srcImageRange(st), srcIter(dupperleft, dest), destIter(dupperleft, dest),
1283  std::plus<typename DestAccessor::value_type>());
1284  }
1285 }
1286 
1287 } // namespace detail
1288 
1289 template <class SrcIterator, class SrcAccessor,
1290  class DestIterator, class DestAccessor>
1291 void structureTensor(SrcIterator supperleft,
1292  SrcIterator slowerright, SrcAccessor src,
1293  DestIterator dupperleft, DestAccessor dest,
1294  double inner_scale, double outer_scale)
1295 {
1296  typedef typename
1297  NumericTraits<typename SrcAccessor::value_type>::isScalar isScalar;
1298  detail::structureTensor(supperleft, slowerright, src,
1299  dupperleft, dest, inner_scale, outer_scale, isScalar());
1300 }
1301 
1302 template <class SrcIterator, class SrcAccessor,
1303  class DestIterator, class DestAccessor>
1304 inline void
1305 structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1306  pair<DestIterator, DestAccessor> dest,
1307  double inner_scale, double outer_scale)
1308 {
1309  structureTensor(src.first, src.second, src.third,
1310  dest.first, dest.second,
1311  inner_scale, outer_scale);
1312 }
1313 
1314 //@}
1315 
1316 } // namespace vigra
1317 
1318 #endif // VIGRA_CONVOLUTION_HXX

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.7.1 (Wed Mar 12 2014)