[ 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 input pixel type <tt>T1</tt> must be a \ref LinearSpace "linear space" over
204 the kernel's value_type <tt>T</tt>, i.e. addition of source values, multiplication with kernel values,
205 and NumericTraits must be defined. The kernel's value_type must be an \ref AlgebraicField "algebraic field",
206 i.e. the arithmetic operations (+, -, *, /) and NumericTraits must be defined. Typically, you will use
207 <tt>double</tt> for the kernel type.
208
209 <b> Declarations:</b>
210
211 pass 2D array views:
212 \code
213 namespace vigra {
214 // use the same 1D kernel for all axes
215 template <class T1, class S1,
216 class T2, class S2,
217 class T>
218 void
219 convolveImage(MultiArrayView<2, T1, S1> const & src,
220 MultiArrayView<2, T2, S2> dest,
221 Kernel1D<T> const & k);
222
223 // use a different kernel for each axis
224 template <class T1, class S1,
225 class T2, class S2,
226 class T>
227 void
228 convolveImage(MultiArrayView<2, T1, S1> const & src,
229 MultiArrayView<2, T2, S2> dest,
230 Kernel1D<T> const & kx, Kernel1D<T> const & ky);
231
232 // use a non-separable 2D kernel
233 template <class T1, class S1,
234 class T2, class S2,
235 class T3>
236 void
237 convolveImage(MultiArrayView<2, T1, S1> const & src,
238 MultiArrayView<2, T2, S2> dest,
239 Kernel2D<T3> const & kernel);
240 }
241 \endcode
242
243 \deprecatedAPI{convolveImage}
244 pass \ref ImageIterators and \ref DataAccessors :
245 \code
246 namespace vigra {
247 // use a different kernel for each axis
248 template <class SrcIterator, class SrcAccessor,
249 class DestIterator, class DestAccessor,
250 class T>
251 void convolveImage(SrcIterator supperleft,
252 SrcIterator slowerright, SrcAccessor sa,
253 DestIterator dupperleft, DestAccessor da,
254 Kernel1D<T> const & kx, Kernel1D<T> const & ky);
255
256 // use a non-separable 2D kernel
257 template <class SrcIterator, class SrcAccessor,
258 class DestIterator, class DestAccessor,
259 class KernelIterator, class KernelAccessor>
260 void convolveImage(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
261 DestIterator dest_ul, DestAccessor dest_acc,
262 KernelIterator ki, KernelAccessor ak,
263 Diff2D kul, Diff2D klr, BorderTreatmentMode border);
264 }
265 \endcode
266 use argument objects in conjunction with \ref ArgumentObjectFactories :
267 \code
268 namespace vigra {
269 // use a different kernel for each axis
270 template <class SrcIterator, class SrcAccessor,
271 class DestIterator, class DestAccessor,
272 class T>
273 void
274 convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
275 pair<DestIterator, DestAccessor> dest,
276 Kernel1D<T> const & kx, Kernel1D<T> const & ky);
277
278 // use a non-separable 2D kernel
279 template <class SrcIterator, class SrcAccessor,
280 class DestIterator, class DestAccessor,
281 class KernelIterator, class KernelAccessor>
282 void convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
283 pair<DestIterator, DestAccessor> dest,
284 tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D,
285 BorderTreatmentMode> kernel);
286 }
287 \endcode
288 \deprecatedEnd
289
290 <b> Usage:</b>
291
292 <b>\#include</b> <vigra/convolution.hxx><br/>
293 Namespace: vigra
294
295 \code
296 MultiArray<2, float> src(w,h), dest1(w,h), dest2(w,h);
297 ...
298
299 // create horizontal sobel filter (symmetric difference in x-direction, smoothing in y direction)
300 Kernel1D<double> kx, ky;
301 kx.initSymmetricDifference();
302 ky.initBinomial(1);
303
304 // calls separable convolution with the two 1D kernels
305 convolveImage(src, dest1, kx, ky);
306
307 // create a 3x3 Laplacian filter
308 Kernel2D<double> laplace;
309 laplace.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) =
310 0.375, 0.25, 0.375,
311 0.25, -2.5, 0.25,
312 0.375, 0.25, 0.375;
313
314 // calls 2D convolution
315 convolveImage(src, dest2, laplace);
316 \endcode
317
318 \deprecatedUsage{convolveImage}
319 \code
320 vigra::FImage src(w,h), dest(w,h);
321 ...
322
323 // create horizontal sobel filter (symmetric difference in x-direction, smoothing in y direction)
324 Kernel1D<double> kx, ky;
325 kx.initSymmetricDifference();
326 ky.initBinomial(1);
327
328 // calls separable convolution with the two 1D kernels
329 vigra::convolveImage(srcImageRange(src), destImage(dest), kx, ky);
330
331 // create a 3x3 Laplacian filter
332 Kernel2D<double> laplace;
333 laplace.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) =
334 0.375, 0.25, 0.375,
335 0.25, -2.5, 0.25,
336 0.375, 0.25, 0.375;
337
338 // calls 2D convolution
339 vigra::convolveImage(srcImageRange(src), destImage(dest), kernel2d(laplace));
340 \endcode
341 \deprecatedEnd
342
343 <b> Preconditions:</b>
344
345 The image must be larger than the kernel radius.
346 <ul>
347 <li>For 1D kernels, <tt>w > std::max(xkernel.right(), -xkernel.keft())</tt> and
348 <tt>h > std::max(ykernel.right(), -ykernel.left())</tt> are required.
349 <li>For 2D kernels, <tt>w > std::max(kernel.lowerRight().x, -kernel.upperLeft().x)</tt> and
350 <tt>h > std::max(kernel.lowerRight().y, -kernel.upperLeft().y)</tt> are required.
351 </ul>
352 If <tt>BORDER_TREATMENT_CLIP</tt> is requested: the sum of kernel elements must be != 0.
353 */
354 doxygen_overloaded_function(template <...> void convolveImage)
355
356 template <class SrcIterator, class SrcAccessor,
357 class DestIterator, class DestAccessor,
358 class T>
359 void convolveImage(SrcIterator supperleft,
360 SrcIterator slowerright, SrcAccessor sa,
361 DestIterator dupperleft, DestAccessor da,
362 Kernel1D<T> const & kx, Kernel1D<T> const & ky)
363 {
364 typedef typename
365 NumericTraits<typename SrcAccessor::value_type>::RealPromote
366 TmpType;
367 BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization);
368
369 separableConvolveX(srcIterRange(supperleft, slowerright, sa),
370 destImage(tmp), kernel1d(kx));
371 separableConvolveY(srcImageRange(tmp),
372 destIter(dupperleft, da), kernel1d(ky));
373 }
374
375 template <class SrcIterator, class SrcAccessor,
376 class DestIterator, class DestAccessor,
377 class T>
378 inline void
379 convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
380 pair<DestIterator, DestAccessor> dest,
381 Kernel1D<T> const & kx, Kernel1D<T> const & ky)
382 {
383 convolveImage(src.first, src.second, src.third,
384 dest.first, dest.second, kx, ky);
385 }
386
387 template <class T1, class S1,
388 class T2, class S2,
389 class T>
390 inline void
391 convolveImage(MultiArrayView<2, T1, S1> const & src,
392 MultiArrayView<2, T2, S2> dest,
393 Kernel1D<T> const & k)
394 {
395 vigra_precondition(src.shape() == dest.shape(),
396 "convolveImage(): shape mismatch between input and output.");
397 convolveImage(srcImageRange(src),
398 destImage(dest), k, k);
399 }
400
401 template <class T1, class S1,
402 class T2, class S2,
403 class T>
404 inline void
405 convolveImage(MultiArrayView<2, T1, S1> const & src,
406 MultiArrayView<2, T2, S2> dest,
407 Kernel1D<T> const & kx, Kernel1D<T> const & ky)
408 {
409 vigra_precondition(src.shape() == dest.shape(),
410 "convolveImage(): shape mismatch between input and output.");
411 convolveImage(srcImageRange(src),
412 destImage(dest), kx, ky);
413 }
414
415 /********************************************************/
416 /* */
417 /* simpleSharpening */
418 /* */
419 /********************************************************/
420
421 /** \brief Perform simple sharpening function.
422
423 This function uses \ref convolveImage() with the following 3x3 filter:
424
425 \code
426 -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_factor/16.0,
427 -sharpening_factor/8.0, 1.0+sharpening_factor*0.75, -sharpening_factor/8.0,
428 -sharpening_factor/16.0, -sharpening_factor/8.0, -sharpening_factor/16.0;
429 \endcode
430
431 and uses <TT>BORDER_TREATMENT_REFLECT</TT> as border treatment mode.
432
433 <b> Preconditions:</b>
434 \code
435 1. sharpening_factor >= 0
436 2. scale >= 0
437 \endcode
438
439 <b> Declarations:</b>
440
441 pass 2D array views:
442 \code
443 namespace vigra {
444 template <class T1, class S1,
445 class T2, class S2>
446 void
447 simpleSharpening(MultiArrayView<2, T1, S1> const & src,
448 MultiArrayView<2, T2, S2> dest,
449 double sharpening_factor);
450 }
451 \endcode
452
453 \deprecatedAPI{simpleSharpening}
454 pass \ref ImageIterators and \ref DataAccessors :
455 \code
456 namespace vigra {
457 template <class SrcIterator, class SrcAccessor,
458 class DestIterator, class DestAccessor>
459 void simpleSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
460 DestIterator dest_ul, DestAccessor dest_acc, double sharpening_factor);
461 }
462 \endcode
463 use argument objects in conjunction with \ref ArgumentObjectFactories :
464 \code
465 namespace vigra {
466 template <class SrcIterator, class SrcAccessor,
467 class DestIterator, class DestAccessor>
468 void simpleSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
469 pair<DestIterator, DestAccessor> dest, double sharpening_factor);
470 }
471 \endcode
472 \deprecatedEnd
473
474 <b> Usage:</b>
475
476 <b>\#include</b> <vigra/convolution.hxx><br/>
477 Namespace: vigra
478
479 \code
480 MultiArray<2, float> src(w,h), dest(w,h);
481 ...
482
483 // sharpening with sharpening_factor = 0.1
484 vigra::simpleSharpening(src, dest, 0.1);
485 \endcode
486
487 \deprecatedUsage{simpleSharpening}
488 \code
489 vigra::FImage src(w,h), dest(w,h);
490 ...
491
492 // sharpening with sharpening_factor = 0.1
493 vigra::simpleSharpening(srcImageRange(src), destImage(dest), 0.1);
494
495 \endcode
496 \deprecatedEnd
497 */
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 Anisotropic data should be provided with appropriate \ref vigra::ConvolutionOptions
1082 to adjust the filter sizes for the resolution of each axis.
1083 Otherwise, the parameter <tt>opt</tt> is optional unless the parameter
1084 <tt>sigma</tt> is omitted.
1085
1086 If you pass \ref vigra::BlockwiseConvolutionOptions instead, the algorithm will
1087 be executed in parallel on data blocks of a certain size. The block size can be
1088 customized via <tt>BlockwiseConvolutionOptions::blockShape()</tt>, but the defaults
1089 usually work reasonably. By default, the number of threads equals the capabilities
1090 of your hardware, but you can change this via <tt>BlockwiseConvolutionOptions::numThreads()</tt>.
1091
1092 <b> Declarations:</b>
1093
1094 use arbitrary-dimensional arrays:
1095 \code
1096 namespace vigra {
1097 // pass filter scale explicitly
1098 template <unsigned int N, class T1, class S1,
1099 class T2, class S2>
1100 void
1101 gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
1102 MultiArrayView<N, T2, S2> dest,
1103 double sigma,
1104 ConvolutionOptions<N> opt = ConvolutionOptions<N>());
1105
1106 // likewise, but sum the contributions of each band
1107 template <unsigned int N, class MT, class S1,
1108 class T2, class S2>
1109 void
1110 gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<MT>, S1> const & src,
1111 MultiArrayView<N, T2, S2> dest,
1112 double sigma,
1113 ConvolutionOptions<N> opt = ConvolutionOptions<N>());
1114
1115 // pass filter scale(s) in option object
1116 template <unsigned int N, class T1, class S1,
1117 class T2, class S2>
1118 void
1119 gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
1120 MultiArrayView<N, T2, S2> dest,
1121 ConvolutionOptions<N> const & opt);
1122
1123 // likewise, but execute algorithm in parallel
1124 template <unsigned int N, class T1, class S1,
1125 class T2, class S2>
1126 void
1127 gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
1128 MultiArrayView<N, T2, S2> dest,
1129 BlockwiseConvolutionOptions<N> const & opt);
1130
1131 // pass filter scale(s) in option object and sum the contributions of each band
1132 template <unsigned int N, class MT, class S1,
1133 class T2, class S2>
1134 void
1135 gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<MT>, S1> const & src,
1136 MultiArrayView<N, T2, S2> dest,
1137 ConvolutionOptions<N> const & opt);
1138 }
1139 \endcode
1140 Here, the input element types <tt>T1</tt> and <tt>MT</tt> can be arbitrary scalar types, and <tt>T1</tt>
1141 may also be <tt>TinyVector</tt> or <tt>RGBValue</tt>. The output element type <tt>T2</tt> should
1142 be the corresponding norm type (see \ref NormTraits "NormTraits"). In the <tt>Multiband<MT></tt>-version,
1143 the input array's right-most dimension is interpreted as a channel axis, therefore it must
1144 have one dimension more than the output array.
1145
1146 \deprecatedAPI{gaussianGradientMagnitude}
1147 pass \ref ImageIterators and \ref DataAccessors :
1148 \code
1149 namespace vigra {
1150 template <class SrcIterator, class SrcAccessor,
1151 class DestIterator, class DestAccessor>
1152 void gaussianGradientMagnitude(SrcIterator sul,
1153 SrcIterator slr, SrcAccessor src,
1154 DestIterator dupperleft, DestAccessor dest,
1155 double scale);
1156 }
1157 \endcode
1158 use argument objects in conjunction with \ref ArgumentObjectFactories :
1159 \code
1160 namespace vigra {
1161 template <class SrcIterator, class SrcAccessor,
1162 class DestIterator, class DestAccessor>
1163 void
1164 gaussianGradientMagnitude(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1165 pair<DestIterator, DestAccessor> dest,
1166 double scale);
1167 }
1168 \endcode
1169 \deprecatedEnd
1170
1171 <b> Usage:</b>
1172
1173 <b>\#include</b> <vigra/multi_convolution.hxx> (sequential version)<br/>
1174 <b>\#include</b> <vigra/multi_blockwise.hxx> (parallel version)<br/>
1175 <b>\#include</b> <vigra/convolution.hxx> (deprecated API version)<br/>
1176 Namespace: vigra
1177
1178 \code
1179 // example 1
1180 {
1181 // use a 3-dimensional float array
1182 MultiArray<3, float> volume(Shape3(w, h, d)), grad(volume.shape());
1183 ...
1184
1185 // calculate gradient magnitude at scale = 3.0
1186 gaussianGradientMagnitude(volume, grad, 3.0);
1187 }
1188
1189 // example 2
1190 {
1191 // use a 2-dimensional RGB array
1192 MultiArray<2, RGBValue<float> > rgb(Shape2(w, h));
1193 MultiArray<2, float> grad(rgb.shape());
1194 ...
1195
1196 // calculate the color gradient magnitude at scale = 3.0
1197 gaussianGradientMagnitude(rgb, grad, 3.0);
1198 }
1199
1200 // example 3
1201 {
1202 // use a 3-dimensional array whose right-most axis is interpreted as
1203 // a multi-spectral axis with arbitrary many channels
1204 MultiArray<3, Multiband<float> > spectral(Shape3(w, h, channelCount));
1205 MultiArray<2, float> grad(Shape2(w, h));
1206 ...
1207
1208 // calculate the multi-channel gradient magnitude at scale = 3.0
1209 // (note that the template parameter N (number of spatial dimensions)
1210 // must be provided explicitly as gaussianGradientMagnitude<2>(...) )
1211 MultiArrayView<3, Multiband<float> > view(spectral);
1212 gaussianGradientMagnitude<2>(view, grad, 3.0);
1213 }
1214 \endcode
1215
1216 \deprecatedUsage{gaussianGradientMagnitude}
1217 \code
1218 // use a traditional float or RGB image
1219 FImage image(w, h), grad(w, h);
1220 FRGBImage rgb(w, h);
1221 ...
1222
1223 // calculate gradient magnitude at scale = 3.0
1224 gaussianGradientMagnitude(srcImageRange(image), destImage(grad), 3.0);
1225
1226 // calculate color gradient magnitude at scale = 3.0
1227 gaussianGradientMagnitude(srcImageRange(rgb), destImage(grad), 3.0);
1228 \endcode
1229 \deprecatedEnd
1230 */
1231 doxygen_overloaded_function(template <...> void gaussianGradientMagnitude)
1232
1233 template <class SrcIterator, class SrcAccessor,
1234 class DestIterator, class DestAccessor>
1235 void gaussianGradientMagnitude(SrcIterator sul,
1236 SrcIterator slr, SrcAccessor src,
1237 DestIterator dupperleft, DestAccessor dest,
1238 double scale)
1239 {
1240 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
1241 BasicImage<TmpType> gradx(slr-sul, SkipInitialization), grady(slr-sul, SkipInitialization);
1242
1243 gaussianGradient(srcIterRange(sul, slr, src),
1244 destImage(gradx), destImage(grady), scale);
1245 combineTwoImages(srcImageRange(gradx), srcImage(grady), destIter(dupperleft, dest),
1246 MagnitudeFunctor<TmpType>());
1247 }
1248
1249 template <class SrcIterator, class SrcAccessor,
1250 class DestIterator, class DestAccessor>
1251 inline void
1252 gaussianGradientMagnitude(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1253 pair<DestIterator, DestAccessor> dest,
1254 double scale)
1255 {
1256 gaussianGradientMagnitude(src.first, src.second, src.third,
1257 dest.first, dest.second, scale);
1258 }
1259
1260 /********************************************************/
1261 /* */
1262 /* laplacianOfGaussian */
1263 /* */
1264 /********************************************************/
1265
1266 /** \brief Filter image with the Laplacian of Gaussian operator
1267 at the given scale.
1268
1269 This function calls \ref separableConvolveX() and \ref separableConvolveY() with the appropriate 2nd derivative
1270 of Gaussian kernels in x- and y-direction and then sums the results
1271 to get the Laplacian.
1272
1273 Function \ref laplacianOfGaussianMultiArray() performs the same filter operation
1274 on arbitrary dimensional arrays.
1275
1276 <b> Declarations:</b>
1277
1278 pass 2D array views:
1279 \code
1280 namespace vigra {
1281 template <class T1, class S1,
1282 class T2, class S2>
1283 void
1284 laplacianOfGaussian(MultiArrayView<2, T1, S1> const & src,
1285 MultiArrayView<2, T2, S2> dest,
1286 double scale);
1287 }
1288 \endcode
1289
1290 \deprecatedAPI{laplacianOfGaussian}
1291 pass \ref ImageIterators and \ref DataAccessors :
1292 \code
1293 namespace vigra {
1294 template <class SrcIterator, class SrcAccessor,
1295 class DestIterator, class DestAccessor>
1296 void laplacianOfGaussian(SrcIterator supperleft,
1297 SrcIterator slowerright, SrcAccessor sa,
1298 DestIterator dupperleft, DestAccessor da,
1299 double scale);
1300 }
1301 \endcode
1302 use argument objects in conjunction with \ref ArgumentObjectFactories :
1303 \code
1304 namespace vigra {
1305 template <class SrcIterator, class SrcAccessor,
1306 class DestIterator, class DestAccessor>
1307 void
1308 laplacianOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1309 pair<DestIterator, DestAccessor> dest,
1310 double scale);
1311 }
1312 \endcode
1313 \deprecatedEnd
1314
1315 <b> Usage:</b>
1316
1317 <b>\#include</b> <vigra/convolution.hxx><br/>
1318 Namespace: vigra
1319
1320 \code
1321 MultiArray<2, float> src(w,h), dest(w,h);
1322 ...
1323
1324 // calculate Laplacian of Gaussian at scale = 3.0
1325 laplacianOfGaussian(src, dest, 3.0);
1326 \endcode
1327
1328 \deprecatedUsage{laplacianOfGaussian}
1329 \code
1330 vigra::FImage src(w,h), dest(w,h);
1331 ...
1332
1333 // calculate Laplacian of Gaussian at scale = 3.0
1334 vigra::laplacianOfGaussian(srcImageRange(src), destImage(dest), 3.0);
1335 \endcode
1336 \deprecatedEnd
1337 */
1338 doxygen_overloaded_function(template <...> void laplacianOfGaussian)
1339
1340 template <class SrcIterator, class SrcAccessor,
1341 class DestIterator, class DestAccessor>
1342 void laplacianOfGaussian(SrcIterator supperleft,
1343 SrcIterator slowerright, SrcAccessor sa,
1344 DestIterator dupperleft, DestAccessor da,
1345 double scale)
1346 {
1347 typedef typename
1348 NumericTraits<typename SrcAccessor::value_type>::RealPromote
1349 TmpType;
1350 BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization),
1351 tmpx(slowerright - supperleft, SkipInitialization),
1352 tmpy(slowerright - supperleft, SkipInitialization);
1353
1354 Kernel1D<double> smooth, deriv;
1355 smooth.initGaussian(scale);
1356 deriv.initGaussianDerivative(scale, 2);
1357
1358 separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1359 destImage(tmp), kernel1d(deriv));
1360 separableConvolveY(srcImageRange(tmp),
1361 destImage(tmpx), kernel1d(smooth));
1362 separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1363 destImage(tmp), kernel1d(smooth));
1364 separableConvolveY(srcImageRange(tmp),
1365 destImage(tmpy), kernel1d(deriv));
1366 combineTwoImages(srcImageRange(tmpx), srcImage(tmpy),
1367 destIter(dupperleft, da), std::plus<TmpType>());
1368 }
1369
1370 template <class SrcIterator, class SrcAccessor,
1371 class DestIterator, class DestAccessor>
1372 inline void
1373 laplacianOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1374 pair<DestIterator, DestAccessor> dest,
1375 double scale)
1376 {
1377 laplacianOfGaussian(src.first, src.second, src.third,
1378 dest.first, dest.second, scale);
1379 }
1380
1381 template <class T1, class S1,
1382 class T2, class S2>
1383 inline void
1384 laplacianOfGaussian(MultiArrayView<2, T1, S1> const & src,
1385 MultiArrayView<2, T2, S2> dest,
1386 double scale)
1387 {
1388 vigra_precondition(src.shape() == dest.shape(),
1389 "laplacianOfGaussian(): shape mismatch between input and output.");
1390 laplacianOfGaussian(srcImageRange(src),
1391 destImage(dest), scale);
1392 }
1393
1394 /********************************************************/
1395 /* */
1396 /* hessianMatrixOfGaussian */
1397 /* */
1398 /********************************************************/
1399
1400 /** \brief Filter image with the 2nd derivatives of the Gaussian
1401 at the given scale to get the Hessian matrix.
1402
1403 The Hessian matrix is a symmetric matrix defined as:
1404
1405 \f[
1406 \mbox{\rm Hessian}(I) = \left(
1407 \begin{array}{cc}
1408 G_{xx} \ast I & G_{xy} \ast I \\
1409 G_{xy} \ast I & G_{yy} \ast I
1410 \end{array} \right)
1411 \f]
1412
1413 where \f$G_{xx}, G_{xy}, G_{yy}\f$ denote 2nd derivatives of Gaussians
1414 at the given scale, and
1415 \f$\ast\f$ is the convolution symbol. This function calls
1416 \ref separableConvolveX() and \ref separableConvolveY()
1417 with the appropriate 2nd derivative
1418 of Gaussian kernels and puts the results in
1419 the three destination images. The first destination image will
1420 contain the second derivative in x-direction, the second one the mixed
1421 derivative, and the third one holds the derivative in y-direction.
1422
1423 Function \ref hessianOfGaussianMultiArray() performs the same filter operation
1424 on arbitrary dimensional arrays.
1425
1426 <b> Declarations:</b>
1427
1428 pass 2D array views:
1429 \code
1430 namespace vigra {
1431 template <class T1, class S1,
1432 class T2, class S2>
1433 void
1434 hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
1435 MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
1436 double scale);
1437 }
1438 \endcode
1439
1440 \deprecatedAPI{hessianMatrixOfGaussian}
1441 pass \ref ImageIterators and \ref DataAccessors :
1442 \code
1443 namespace vigra {
1444 template <class SrcIterator, class SrcAccessor,
1445 class DestIteratorX, class DestAccessorX,
1446 class DestIteratorXY, class DestAccessorXY,
1447 class DestIteratorY, class DestAccessorY>
1448 void hessianMatrixOfGaussian(SrcIterator supperleft,
1449 SrcIterator slowerright, SrcAccessor sa,
1450 DestIteratorX dupperleftx, DestAccessorX dax,
1451 DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1452 DestIteratorY dupperlefty, DestAccessorY day,
1453 double scale);
1454 }
1455 \endcode
1456 use argument objects in conjunction with \ref ArgumentObjectFactories :
1457 \code
1458 namespace vigra {
1459 template <class SrcIterator, class SrcAccessor,
1460 class DestIteratorX, class DestAccessorX,
1461 class DestIteratorXY, class DestAccessorXY,
1462 class DestIteratorY, class DestAccessorY>
1463 void
1464 hessianMatrixOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1465 pair<DestIteratorX, DestAccessorX> destx,
1466 pair<DestIteratorXY, DestAccessorXY> destxy,
1467 pair<DestIteratorY, DestAccessorY> desty,
1468 double scale);
1469 }
1470 \endcode
1471 \deprecatedEnd
1472
1473 <b> Usage:</b>
1474
1475 <b>\#include</b> <vigra/convolution.hxx><br/>
1476 Namespace: vigra
1477
1478 \code
1479 MultiArray<2, float> src(w,h);
1480 MultiArray<2, TinyVector<float, 3> > hessian(w,h); // will hold the three components of the Hessian
1481 ...
1482
1483 // calculate Hessian of Gaussian at scale = 3.0, use a 3-band output image
1484 hessianMatrixOfGaussian(src, hessian, 3.0);
1485 \endcode
1486
1487 \deprecatedUsage{hessianMatrixOfGaussian}
1488 \code
1489 vigra::FImage src(w,h),
1490 hxx(w,h), hxy(w,h), hyy(w,h); // use a separate image for each component of the Hessian
1491 ...
1492
1493 // calculate Hessian of Gaussian at scale = 3.0, use 3 single.band output images
1494 vigra::hessianMatrixOfGaussian(srcImageRange(src),
1495 destImage(hxx), destImage(hxy), destImage(hyy), 3.0);
1496 \endcode
1497 \deprecatedEnd
1498 */
1499 doxygen_overloaded_function(template <...> void hessianMatrixOfGaussian)
1500
1501 template <class SrcIterator, class SrcAccessor,
1502 class DestIteratorX, class DestAccessorX,
1503 class DestIteratorXY, class DestAccessorXY,
1504 class DestIteratorY, class DestAccessorY>
1505 void hessianMatrixOfGaussian(SrcIterator supperleft,
1506 SrcIterator slowerright, SrcAccessor sa,
1507 DestIteratorX dupperleftx, DestAccessorX dax,
1508 DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1509 DestIteratorY dupperlefty, DestAccessorY day,
1510 double scale)
1511 {
1512 typedef typename
1513 NumericTraits<typename SrcAccessor::value_type>::RealPromote
1514 TmpType;
1515 BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization);
1516
1517 Kernel1D<double> smooth, deriv1, deriv2;
1518 smooth.initGaussian(scale);
1519 deriv1.initGaussianDerivative(scale, 1);
1520 deriv2.initGaussianDerivative(scale, 2);
1521
1522 separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1523 destImage(tmp), kernel1d(deriv2));
1524 separableConvolveY(srcImageRange(tmp),
1525 destIter(dupperleftx, dax), kernel1d(smooth));
1526 separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1527 destImage(tmp), kernel1d(smooth));
1528 separableConvolveY(srcImageRange(tmp),
1529 destIter(dupperlefty, day), kernel1d(deriv2));
1530 separableConvolveX(srcIterRange(supperleft, slowerright, sa),
1531 destImage(tmp), kernel1d(deriv1));
1532 separableConvolveY(srcImageRange(tmp),
1533 destIter(dupperleftxy, daxy), kernel1d(deriv1));
1534 }
1535
1536 template <class SrcIterator, class SrcAccessor,
1537 class DestIteratorX, class DestAccessorX,
1538 class DestIteratorXY, class DestAccessorXY,
1539 class DestIteratorY, class DestAccessorY>
1540 inline void
1541 hessianMatrixOfGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1542 pair<DestIteratorX, DestAccessorX> destx,
1543 pair<DestIteratorXY, DestAccessorXY> destxy,
1544 pair<DestIteratorY, DestAccessorY> desty,
1545 double scale)
1546 {
1547 hessianMatrixOfGaussian(src.first, src.second, src.third,
1548 destx.first, destx.second,
1549 destxy.first, destxy.second,
1550 desty.first, desty.second,
1551 scale);
1552 }
1553
1554 template <class T1, class S1,
1555 class T2X, class S2X,
1556 class T2XY, class S2XY,
1557 class T2Y, class S2Y>
1558 inline void
1559 hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
1560 MultiArrayView<2, T2X, S2X> destx,
1561 MultiArrayView<2, T2XY, S2XY> destxy,
1562 MultiArrayView<2, T2Y, S2Y> desty,
1563 double scale)
1564 {
1565 vigra_precondition(src.shape() == destx.shape() && src.shape() == destxy.shape() && src.shape() == desty.shape(),
1566 "hessianMatrixOfGaussian(): shape mismatch between input and output.");
1567 hessianMatrixOfGaussian(srcImageRange(src),
1568 destImage(destx),
1569 destImage(destxy),
1570 destImage(desty),
1571 scale);
1572 }
1573
1574 template <class T1, class S1,
1575 class T2, class S2>
1576 inline void
1577 hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
1578 MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
1579 double scale)
1580 {
1581 vigra_precondition(src.shape() == dest.shape(),
1582 "hessianMatrixOfGaussian(): shape mismatch between input and output.");
1583
1584 MultiArrayView<3, T2> expanded(dest.expandElements(0));
1585 MultiArrayView<2, T2> dxx(expanded.template bind<0>(0));
1586 MultiArrayView<2, T2> dxy(expanded.template bind<0>(1));
1587 MultiArrayView<2, T2> dyy(expanded.template bind<0>(2));
1588
1589 hessianMatrixOfGaussian(srcImageRange(src),
1590 destImage(dxx),
1591 destImage(dxy),
1592 destImage(dyy),
1593 scale);
1594 }
1595
1596 /********************************************************/
1597 /* */
1598 /* structureTensor */
1599 /* */
1600 /********************************************************/
1601
1602 /** \brief Calculate the Structure Tensor for each pixel of
1603 and image, using Gaussian (derivative) filters.
1604
1605 The Structure Tensor is is a smoothed version of the Euclidean product
1606 of the gradient vector with itself. I.e. it's a symmetric matrix defined as:
1607
1608 \f[
1609 \mbox{\rm StructurTensor}(I) = \left(
1610 \begin{array}{cc}
1611 G \ast (I_x I_x) & G \ast (I_x I_y) \\
1612 G \ast (I_x I_y) & G \ast (I_y I_y)
1613 \end{array} \right) = \left(
1614 \begin{array}{cc}
1615 A & C \\
1616 C & B
1617 \end{array} \right)
1618 \f]
1619
1620 where \f$G\f$ denotes Gaussian smoothing at the <i>outer scale</i>,
1621 \f$I_x, I_y\f$ are the gradient components taken at the <i>inner scale</i>,
1622 \f$\ast\f$ is the convolution symbol, and \f$I_x I_x\f$ etc. are pixelwise
1623 products of the 1st derivative images. This function calls
1624 \ref separableConvolveX() and \ref separableConvolveY() with the
1625 appropriate Gaussian kernels and puts the results in
1626 the three separate destination images (where the first one will
1627 contain \f$G \ast (I_x I_x)\f$, the second one \f$G \ast (I_x I_y)\f$, and the
1628 third one holds \f$G \ast (I_y I_y)\f$), or into a single 3-band image (where the bands
1629 hold the result in the same order as above). The latter form is also applicable when
1630 the source image is a multi-band image (e.g. RGB). In this case, tensors are
1631 first computed for each band separately, and then summed up to get a single result tensor.
1632
1633 Function \ref structureTensorMultiArray() performs the same filter operation
1634 on arbitrary dimensional arrays.
1635
1636 <b> Declarations:</b>
1637
1638 pass 2D array views:
1639 \code
1640 namespace vigra {
1641 // create three separate destination images
1642 template <class T, class S,
1643 class TX, class SX,
1644 class TXY, class SXY,
1645 class TY, class SY>
1646 void
1647 structureTensor(MultiArrayView<2, S, T> const & src,
1648 MultiArrayView<2, TX, SX> destx,
1649 MultiArrayView<2, TXY, SXY> destxy,
1650 MultiArrayView<2, TY, SY> desty,
1651 double inner_scale, double outer_scale);
1652
1653 // create a single 3-band destination image
1654 template <class T1, class S1,
1655 class T2, class S2>
1656 void
1657 structureTensor(MultiArrayView<2, T1, S1> const & src,
1658 MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
1659 double inner_scale, double outer_scale);
1660 }
1661 \endcode
1662
1663 \deprecatedAPI{structureTensor}
1664 pass \ref ImageIterators and \ref DataAccessors :
1665 \code
1666 namespace vigra {
1667 // create three separate destination images
1668 template <class SrcIterator, class SrcAccessor,
1669 class DestIteratorX, class DestAccessorX,
1670 class DestIteratorXY, class DestAccessorXY,
1671 class DestIteratorY, class DestAccessorY>
1672 void structureTensor(SrcIterator supperleft,
1673 SrcIterator slowerright, SrcAccessor sa,
1674 DestIteratorX dupperleftx, DestAccessorX dax,
1675 DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1676 DestIteratorY dupperlefty, DestAccessorY day,
1677 double inner_scale, double outer_scale);
1678
1679 // create a single 3-band destination image
1680 template <class SrcIterator, class SrcAccessor,
1681 class DestIterator, class DestAccessor>
1682 void structureTensor(SrcIterator supperleft,
1683 SrcIterator slowerright, SrcAccessor sa,
1684 DestIterator dupperleft, DestAccessor da,
1685 double inner_scale, double outer_scale);
1686 }
1687 \endcode
1688 use argument objects in conjunction with \ref ArgumentObjectFactories :
1689 \code
1690 namespace vigra {
1691 // create three separate destination images
1692 template <class SrcIterator, class SrcAccessor,
1693 class DestIteratorX, class DestAccessorX,
1694 class DestIteratorXY, class DestAccessorXY,
1695 class DestIteratorY, class DestAccessorY>
1696 void
1697 structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1698 pair<DestIteratorX, DestAccessorX> destx,
1699 pair<DestIteratorXY, DestAccessorXY> destxy,
1700 pair<DestIteratorY, DestAccessorY> desty,
1701 double nner_scale, double outer_scale);
1702
1703 // create a single 3-band destination image
1704 template <class SrcIterator, class SrcAccessor,
1705 class DestIterator, class DestAccessor>
1706 void
1707 structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1708 pair<DestIterator, DestAccessor> dest,
1709 double nner_scale, double outer_scale);
1710 }
1711 \endcode
1712 \deprecatedEnd
1713
1714 <b> Usage:</b>
1715
1716 <b>\#include</b> <vigra/convolution.hxx><br/>
1717 Namespace: vigra
1718
1719 \code
1720 MultiArray<2, flost> src(w,h),
1721 stxx(w,h), stxy(w,h), styy(w,h); // use a separate image for each component
1722 ...
1723
1724 // calculate Structure Tensor at inner scale = 1.0 and outer scale = 3.0
1725 structureTensor(src, stxx, stxy, styy, 1.0, 3.0);
1726
1727 // likwise with a single 3-band destination image
1728 MultiArray<2, TinyVector<float, 3> > st(w,h);
1729 structureTensor(src, st, 1.0, 3.0);
1730 \endcode
1731
1732 \deprecatedUsage{structureTensor}
1733 \code
1734 vigra::FImage src(w,h),
1735 stxx(w,h), stxy(w,h), styy(w,h);
1736 vigra::BasicImage<TinyVector<float, 3> > st(w,h);
1737 ...
1738
1739 vigra::structureTensor(srcImageRange(src),
1740 destImage(stxx), destImage(stxy), destImage(styy), 1.0, 3.0);
1741
1742 vigra::structureTensor(srcImageRange(src), destImage(st), 1.0, 3.0);
1743 \endcode
1744 \deprecatedEnd
1745 */
1746 doxygen_overloaded_function(template <...> void structureTensor)
1747
1748 template <class SrcIterator, class SrcAccessor,
1749 class DestIteratorX, class DestAccessorX,
1750 class DestIteratorXY, class DestAccessorXY,
1751 class DestIteratorY, class DestAccessorY>
1752 void structureTensor(SrcIterator supperleft,
1753 SrcIterator slowerright, SrcAccessor sa,
1754 DestIteratorX dupperleftx, DestAccessorX dax,
1755 DestIteratorXY dupperleftxy, DestAccessorXY daxy,
1756 DestIteratorY dupperlefty, DestAccessorY day,
1757 double inner_scale, double outer_scale)
1758 {
1759 typedef typename
1760 NumericTraits<typename SrcAccessor::value_type>::RealPromote
1761 TmpType;
1762 BasicImage<TmpType> tmp(slowerright - supperleft, SkipInitialization),
1763 tmpx(slowerright - supperleft, SkipInitialization),
1764 tmpy(slowerright - supperleft, SkipInitialization);
1765
1766 gaussianGradient(srcIterRange(supperleft, slowerright, sa),
1767 destImage(tmpx), destImage(tmpy), inner_scale);
1768 combineTwoImages(srcImageRange(tmpx), srcImage(tmpx),
1769 destImage(tmp), std::multiplies<TmpType>());
1770 gaussianSmoothing(srcImageRange(tmp),
1771 destIter(dupperleftx, dax), outer_scale);
1772 combineTwoImages(srcImageRange(tmpy), srcImage(tmpy),
1773 destImage(tmp), std::multiplies<TmpType>());
1774 gaussianSmoothing(srcImageRange(tmp),
1775 destIter(dupperlefty, day), outer_scale);
1776 combineTwoImages(srcImageRange(tmpx), srcImage(tmpy),
1777 destImage(tmp), std::multiplies<TmpType>());
1778 gaussianSmoothing(srcImageRange(tmp),
1779 destIter(dupperleftxy, daxy), outer_scale);
1780 }
1781
1782 template <class SrcIterator, class SrcAccessor,
1783 class DestIteratorX, class DestAccessorX,
1784 class DestIteratorXY, class DestAccessorXY,
1785 class DestIteratorY, class DestAccessorY>
1786 inline void
1787 structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1788 pair<DestIteratorX, DestAccessorX> destx,
1789 pair<DestIteratorXY, DestAccessorXY> destxy,
1790 pair<DestIteratorY, DestAccessorY> desty,
1791 double inner_scale, double outer_scale)
1792 {
1793 structureTensor(src.first, src.second, src.third,
1794 destx.first, destx.second,
1795 destxy.first, destxy.second,
1796 desty.first, desty.second,
1797 inner_scale, outer_scale);
1798 }
1799
1800 template <class T, class S,
1801 class TX, class SX,
1802 class TXY, class SXY,
1803 class TY, class SY>
1804 inline void
1805 structureTensor(MultiArrayView<2, S, T> const & src,
1806 MultiArrayView<2, TX, SX> destx,
1807 MultiArrayView<2, TXY, SXY> destxy,
1808 MultiArrayView<2, TY, SY> desty,
1809 double inner_scale, double outer_scale)
1810 {
1811 vigra_precondition(src.shape() == destx.shape(),
1812 "structureTensor(): shape mismatch between input and output.");
1813 structureTensor(srcImageRange(src),
1814 destImage(destx), destImage(destxy), destImage(desty),
1815 inner_scale, outer_scale);
1816 }
1817
1818 namespace detail {
1819
1820 template <class SrcIterator, class SrcAccessor,
1821 class DestIterator, class DestAccessor>
1822 void structureTensor(SrcIterator supperleft,
1823 SrcIterator slowerright, SrcAccessor src,
1824 DestIterator dupperleft, DestAccessor dest,
1825 double inner_scale, double outer_scale,
1826 VigraTrueType /* isScalar */)
1827 {
1828 typedef VectorElementAccessor<DestAccessor> DA;
1829 structureTensor(supperleft, slowerright, src,
1830 dupperleft, DA(0, dest),
1831 dupperleft, DA(1, dest),
1832 dupperleft, DA(2, dest),
1833 inner_scale, outer_scale);
1834 }
1835
1836 template <class SrcIterator, class SrcAccessor,
1837 class DestIterator, class DestAccessor>
1838 void structureTensor(SrcIterator supperleft,
1839 SrcIterator slowerright, SrcAccessor src,
1840 DestIterator dupperleft, DestAccessor dest,
1841 double inner_scale, double outer_scale,
1842 VigraFalseType /* isScalar */)
1843 {
1844 int bands = src.size(supperleft);
1845 typedef VectorElementAccessor<SrcAccessor> SA;
1846
1847 structureTensor(supperleft, slowerright, SA(0, src),
1848 dupperleft, dest,
1849 inner_scale, outer_scale,
1850 VigraTrueType() /* isScalar */);
1851
1852 BasicImage<typename DestAccessor::value_type> st(slowerright - supperleft, SkipInitialization);
1853 for(int k=1; k < bands; ++k)
1854 {
1855 structureTensor(supperleft, slowerright, SA(k, src),
1856 st.upperLeft(), st.accessor(),
1857 inner_scale, outer_scale,
1858 VigraTrueType() /* isScalar */);
1859 combineTwoImages(srcImageRange(st), srcIter(dupperleft, dest), destIter(dupperleft, dest),
1860 std::plus<typename DestAccessor::value_type>());
1861 }
1862 }
1863
1864 } // namespace detail
1865
1866 template <class SrcIterator, class SrcAccessor,
1867 class DestIterator, class DestAccessor>
1868 void structureTensor(SrcIterator supperleft,
1869 SrcIterator slowerright, SrcAccessor src,
1870 DestIterator dupperleft, DestAccessor dest,
1871 double inner_scale, double outer_scale)
1872 {
1873 typedef typename
1874 NumericTraits<typename SrcAccessor::value_type>::isScalar isScalar;
1875 detail::structureTensor(supperleft, slowerright, src,
1876 dupperleft, dest, inner_scale, outer_scale, isScalar());
1877 }
1878
1879 template <class SrcIterator, class SrcAccessor,
1880 class DestIterator, class DestAccessor>
1881 inline void
1882 structureTensor(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1883 pair<DestIterator, DestAccessor> dest,
1884 double inner_scale, double outer_scale)
1885 {
1886 structureTensor(src.first, src.second, src.third,
1887 dest.first, dest.second,
1888 inner_scale, outer_scale);
1889 }
1890
1891 template <class T1, class S1,
1892 class T2, class S2>
1893 inline void
1894 structureTensor(MultiArrayView<2, T1, S1> const & src,
1895 MultiArrayView<2, TinyVector<T2, 3>, S2> dest,
1896 double inner_scale, double outer_scale)
1897 {
1898 vigra_precondition(src.shape() == dest.shape(),
1899 "structureTensor(): shape mismatch between input and output.");
1900 structureTensor(srcImageRange(src),
1901 destImage(dest),
1902 inner_scale, outer_scale);
1903 }
1904
1905 //@}
1906
1907 } // namespace vigra
1908
1909 #endif // VIGRA_CONVOLUTION_HXX
vigra::simpleSharpening
void simpleSharpening(...)
Perform simple sharpening function.
vigra::gaussianGradient
void gaussianGradient(...)
Calculate the gradient vector by means of a 1st derivatives of Gaussian filter.
vigra::BasicImage::Accessor
IteratorTraits< traverser >::DefaultAccessor Accessor
Definition: basicimage.hxx:571
vigra::laplacianOfGaussian
void laplacianOfGaussian(...)
Filter image with the Laplacian of Gaussian operator at the given scale.
vigra::gaussianGradientMagnitude
void gaussianGradientMagnitude(...)
Calculate the gradient magnitude by means of a 1st derivatives of Gaussian filter.
vigra::gaussianSmoothing
void gaussianSmoothing(...)
Perform isotropic Gaussian convolution.
vigra
Definition: accessor.hxx:43
vigra::separableConvolveX
void separableConvolveX(...)
Performs a 1 dimensional convolution in x direction.
vigra::BasicImage::traverser
BasicImageIterator< PIXELTYPE, PIXELTYPE ** > traverser
Definition: basicimage.hxx:526
vigra::doxygen_overloaded_function
doxygen_overloaded_function(template<... > void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
vigra::combineTwoImages
void combineTwoImages(...)
Combine two source images into destination image.
vigra::convolveImage
void convolveImage(...)
Convolve an image with the given kernel(s).
vigra::gaussianSharpening
void gaussianSharpening(...)
Perform sharpening function with gaussian filter.
vigra::structureTensor
void structureTensor(...)
Calculate the Structure Tensor for each pixel of and image, using Gaussian (derivative) filters...
vigra::hessianMatrixOfGaussian
void hessianMatrixOfGaussian(...)
Filter image with the 2nd derivatives of the Gaussian at the given scale to get the Hessian matrix...
vigra::separableConvolveY
void separableConvolveY(...)
Performs a 1 dimensional convolution in y direction.

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