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