vigra - vigra/convolution.hxx Source File

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

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany | html generated using doxygen and Python vigra 1.10.0 (Mon Nov 18 2013)