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

multi_distance.hxx |

1 /************************************************************************/
2 /* */
3 /* Copyright 2003-2007 by Kasim Terzic, Christian-Dennis Rahn */
4 /* and Ullrich Koethe */
5 /* */
6 /* This file is part of the VIGRA computer vision library. */
7 /* The VIGRA Website is */
8 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
9 /* Please direct questions, bug reports, and contributions to */
10 /* ullrich.koethe@iwr.uni-heidelberg.de or */
11 /* vigra@informatik.uni-hamburg.de */
12 /* */
13 /* Permission is hereby granted, free of charge, to any person */
14 /* obtaining a copy of this software and associated documentation */
15 /* files (the "Software"), to deal in the Software without */
16 /* restriction, including without limitation the rights to use, */
17 /* copy, modify, merge, publish, distribute, sublicense, and/or */
18 /* sell copies of the Software, and to permit persons to whom the */
19 /* Software is furnished to do so, subject to the following */
20 /* conditions: */
21 /* */
22 /* The above copyright notice and this permission notice shall be */
23 /* included in all copies or substantial portions of the */
24 /* Software. */
25 /* */
26 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
27 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
28 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
29 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
30 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
31 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
32 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
33 /* OTHER DEALINGS IN THE SOFTWARE. */
34 /* */
35 /************************************************************************/
36
37 #ifndef VIGRA_MULTI_DISTANCE_HXX
38 #define VIGRA_MULTI_DISTANCE_HXX
39
40 #include <vector>
41 #include <functional>
42 #include "array_vector.hxx"
43 #include "multi_array.hxx"
44 #include "accessor.hxx"
45 #include "numerictraits.hxx"
46 #include "navigator.hxx"
47 #include "metaprogramming.hxx"
48 #include "multi_pointoperators.hxx"
49 #include "functorexpression.hxx"
50
51 namespace vigra
52 {
53
54 namespace detail
55 {
56
57 template <class Value>
58 struct DistParabolaStackEntry
59 {
60 double left, center, right;
61 Value prevVal;
62
63 DistParabolaStackEntry(Value const & p, double l, double c, double r)
64 : left(l), center(c), right(r), prevVal(p)
65 {}
66 };
67
68 /********************************************************/
69 /* */
70 /* distParabola */
71 /* */
72 /* Version with sigma (parabola spread) for morphology */
73 /* */
74 /********************************************************/
75
76 template <class SrcIterator, class SrcAccessor,
77 class DestIterator, class DestAccessor >
78 void distParabola(SrcIterator is, SrcIterator iend, SrcAccessor sa,
79 DestIterator id, DestAccessor da, double sigma )
80 {
81 // We assume that the data in the input is distance squared and treat it as such
82 double w = iend - is;
83 if(w <= 0)
84 return;
85
86 double sigma2 = sigma * sigma;
87 double sigma22 = 2.0 * sigma2;
88
89 typedef typename SrcAccessor::value_type SrcType;
90 typedef DistParabolaStackEntry<SrcType> Influence;
91 std::vector<Influence> _stack;
92 _stack.push_back(Influence(sa(is), 0.0, 0.0, w));
93
94 ++is;
95 double current = 1.0;
96 while(current < w )
97 {
98 Influence & s = _stack.back();
99 double diff = current - s.center;
100 double intersection = current + (sa(is) - s.prevVal - sigma2*sq(diff)) / (sigma22 * diff);
101
102 if( intersection < s.left) // previous point has no influence
103 {
104 _stack.pop_back();
105 if(_stack.empty())
106 {
107 _stack.push_back(Influence(sa(is), 0.0, current, w));
108 }
109 else
110 {
111 continue; // try new top of stack without advancing current
112 }
113 }
114 else if(intersection < s.right)
115 {
116 s.right = intersection;
117 _stack.push_back(Influence(sa(is), intersection, current, w));
118 }
119 ++is;
120 ++current;
121 }
122
123 // Now we have the stack indicating which rows are influenced by (and therefore
124 // closest to) which row. We can go through the stack and calculate the
125 // distance squared for each element of the column.
126 typename std::vector<Influence>::iterator it = _stack.begin();
127 for(current = 0.0; current < w; ++current, ++id)
128 {
129 while( current >= it->right)
130 ++it;
131 da.set(sigma2 * sq(current - it->center) + it->prevVal, id);
132 }
133 }
134
135 template <class SrcIterator, class SrcAccessor,
136 class DestIterator, class DestAccessor>
137 inline void distParabola(triple<SrcIterator, SrcIterator, SrcAccessor> src,
138 pair<DestIterator, DestAccessor> dest, double sigma)
139 {
140 distParabola(src.first, src.second, src.third,
141 dest.first, dest.second, sigma);
142 }
143
144 /********************************************************/
145 /* */
146 /* internalSeparableMultiArrayDistTmp */
147 /* */
148 /********************************************************/
149
150 template <class SrcIterator, class SrcShape, class SrcAccessor,
151 class DestIterator, class DestAccessor, class Array>
152 void internalSeparableMultiArrayDistTmp(
153 SrcIterator si, SrcShape const & shape, SrcAccessor src,
154 DestIterator di, DestAccessor dest, Array const & sigmas, bool invert)
155 {
156 // Sigma is the spread of the parabolas. It determines the structuring element size
157 // for ND morphology. When calculating the distance transforms, sigma is usually set to 1,
158 // unless one wants to account for anisotropic pixel pitch
159 enum { N = SrcShape::static_size};
160
161 // we need the Promote type here if we want to invert the image (dilation)
162 typedef typename NumericTraits<typename DestAccessor::value_type>::RealPromote TmpType;
163
164 // temporary array to hold the current line to enable in-place operation
165 ArrayVector<TmpType> tmp( shape[0] );
166
167 typedef MultiArrayNavigator<SrcIterator, N> SNavigator;
168 typedef MultiArrayNavigator<DestIterator, N> DNavigator;
169
170
171 // only operate on first dimension here
172 SNavigator snav( si, shape, 0 );
173 DNavigator dnav( di, shape, 0 );
174
175 using namespace vigra::functor;
176
177 for( ; snav.hasMore(); snav++, dnav++ )
178 {
179 // first copy source to temp for maximum cache efficiency
180 // Invert the values if necessary. Only needed for grayscale morphology
181 if(invert)
182 transformLine( snav.begin(), snav.end(), src, tmp.begin(),
183 typename AccessorTraits<TmpType>::default_accessor(),
184 Param(NumericTraits<TmpType>::zero())-Arg1());
185 else
186 copyLine( snav.begin(), snav.end(), src, tmp.begin(),
187 typename AccessorTraits<TmpType>::default_accessor() );
188
189 detail::distParabola( srcIterRange(tmp.begin(), tmp.end(),
190 typename AccessorTraits<TmpType>::default_const_accessor()),
191 destIter( dnav.begin(), dest ), sigmas[0] );
192 }
193
194 // operate on further dimensions
195 for( int d = 1; d < N; ++d )
196 {
197 DNavigator dnav( di, shape, d );
198
199 tmp.resize( shape[d] );
200
201
202 for( ; dnav.hasMore(); dnav++ )
203 {
204 // first copy source to temp for maximum cache efficiency
205 copyLine( dnav.begin(), dnav.end(), dest,
206 tmp.begin(), typename AccessorTraits<TmpType>::default_accessor() );
207
208 detail::distParabola( srcIterRange(tmp.begin(), tmp.end(),
209 typename AccessorTraits<TmpType>::default_const_accessor()),
210 destIter( dnav.begin(), dest ), sigmas[d] );
211 }
212 }
213 if(invert) transformMultiArray( di, shape, dest, di, dest, -Arg1());
214 }
215
216 template <class SrcIterator, class SrcShape, class SrcAccessor,
217 class DestIterator, class DestAccessor, class Array>
218 inline void internalSeparableMultiArrayDistTmp( SrcIterator si, SrcShape const & shape, SrcAccessor src,
219 DestIterator di, DestAccessor dest, Array const & sigmas)
220 {
221 internalSeparableMultiArrayDistTmp( si, shape, src, di, dest, sigmas, false );
222 }
223
224 template <class SrcIterator, class SrcShape, class SrcAccessor,
225 class DestIterator, class DestAccessor>
226 inline void internalSeparableMultiArrayDistTmp( SrcIterator si, SrcShape const & shape, SrcAccessor src,
227 DestIterator di, DestAccessor dest)
228 {
229 ArrayVector<double> sigmas(shape.size(), 1.0);
230 internalSeparableMultiArrayDistTmp( si, shape, src, di, dest, sigmas, false );
231 }
232
233 } // namespace detail
234
235 /** \addtogroup MultiArrayDistanceTransform Euclidean distance transform for multi-dimensional arrays.
236
237 These functions perform the Euclidean distance transform an arbitrary dimensional
238 array that is specified by iterators (compatible to \ref MultiIteratorPage)
239 and shape objects. It can therefore be applied to a wide range of data structures
240 (\ref vigra::MultiArrayView, \ref vigra::MultiArray etc.).
241 */
242 //@{
243
244 /********************************************************/
245 /* */
246 /* separableMultiDistSquared */
247 /* */
248 /********************************************************/
249
250 /** \brief Euclidean distance squared on multi-dimensional arrays.
251
252 The algorithm is taken from Donald Bailey: "An Efficient Euclidean Distance Transform",
253 Proc. IWCIA'04, Springer LNCS 3322, 2004.
254
255 <b> Declarations:</b>
256
257 pass arbitrary-dimensional array views:
258 \code
259 namespace vigra {
260 // explicitly specify pixel pitch for each coordinate
261 template <unsigned int N, class T1, class S1,
262 class T2, class S2,
263 class Array>
264 void
265 separableMultiDistSquared(MultiArrayView<N, T1, S1> const & source,
266 MultiArrayView<N, T2, S2> dest,
267 bool background,
268 Array const & pixelPitch);
269
270 // use default pixel pitch = 1.0 for each coordinate
271 template <unsigned int N, class T1, class S1,
272 class T2, class S2>
273 void
274 separableMultiDistSquared(MultiArrayView<N, T1, S1> const & source,
275 MultiArrayView<N, T2, S2> dest,
276 bool background);
277 }
278 \endcode
279
280 \deprecatedAPI{separableMultiDistSquared}
281 pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
282 \code
283 namespace vigra {
284 // explicitly specify pixel pitch for each coordinate
285 template <class SrcIterator, class SrcShape, class SrcAccessor,
286 class DestIterator, class DestAccessor, class Array>
287 void
288 separableMultiDistSquared( SrcIterator s, SrcShape const & shape, SrcAccessor src,
289 DestIterator d, DestAccessor dest,
290 bool background,
291 Array const & pixelPitch);
292
293 // use default pixel pitch = 1.0 for each coordinate
294 template <class SrcIterator, class SrcShape, class SrcAccessor,
295 class DestIterator, class DestAccessor>
296 void
297 separableMultiDistSquared(SrcIterator siter, SrcShape const & shape, SrcAccessor src,
298 DestIterator diter, DestAccessor dest,
299 bool background);
300
301 }
302 \endcode
303 use argument objects in conjunction with \ref ArgumentObjectFactories :
304 \code
305 namespace vigra {
306 // explicitly specify pixel pitch for each coordinate
307 template <class SrcIterator, class SrcShape, class SrcAccessor,
308 class DestIterator, class DestAccessor, class Array>
309 void
310 separableMultiDistSquared( triple<SrcIterator, SrcShape, SrcAccessor> const & source,
311 pair<DestIterator, DestAccessor> const & dest,
312 bool background,
313 Array const & pixelPitch);
314
315 // use default pixel pitch = 1.0 for each coordinate
316 template <class SrcIterator, class SrcShape, class SrcAccessor,
317 class DestIterator, class DestAccessor>
318 void
319 separableMultiDistSquared(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
320 pair<DestIterator, DestAccessor> const & dest,
321 bool background);
322
323 }
324 \endcode
325 \deprecatedEnd
326
327 This function performs a squared Euclidean squared distance transform on the given
328 multi-dimensional array. Both source and destination
329 arrays are represented by iterators, shape objects and accessors.
330 The destination array is required to already have the correct size.
331
332 This function expects a mask as its source, where background pixels are
333 marked as zero, and non-background pixels as non-zero. If the parameter
334 <i>background</i> is true, then the squared distance of all background
335 pixels to the nearest object is calculated. Otherwise, the distance of all
336 object pixels to the nearest background pixel is calculated.
337
338 Optionally, one can pass an array that specifies the pixel pitch in each direction.
339 This is necessary when the data have non-uniform resolution (as is common in confocal
340 microscopy, for example).
341
342 This function may work in-place, which means that <tt>siter == diter</tt> is allowed.
343 A full-sized internal array is only allocated if working on the destination
344 array directly would cause overflow errors (i.e. if
345 <tt> NumericTraits<typename DestAccessor::value_type>::max() < N * M*M</tt>, where M is the
346 size of the largest dimension of the array.
347
348 <b> Usage:</b>
349
350 <b>\#include</b> <vigra/multi_distance.hxx><br/>
351 Namespace: vigra
352
353 \code
354 Shape3 shape(width, height, depth);
355 MultiArray<3, unsigned char> source(shape);
356 MultiArray<3, unsigned int> dest(shape);
357 ...
358
359 // Calculate Euclidean distance squared for all background pixels
360 separableMultiDistSquared(source, dest, true);
361 \endcode
362
363 \see vigra::distanceTransform(), vigra::separableMultiDistance()
364 */
365 doxygen_overloaded_function(template <...> void separableMultiDistSquared)
366
367 template <class SrcIterator, class SrcShape, class SrcAccessor,
368 class DestIterator, class DestAccessor, class Array>
369 void separableMultiDistSquared( SrcIterator s, SrcShape const & shape, SrcAccessor src,
370 DestIterator d, DestAccessor dest, bool background,
371 Array const & pixelPitch)
372 {
373 int N = shape.size();
374
375 typedef typename SrcAccessor::value_type SrcType;
376 typedef typename DestAccessor::value_type DestType;
377 typedef typename NumericTraits<DestType>::RealPromote Real;
378
379 SrcType zero = NumericTraits<SrcType>::zero();
380
381 double dmax = 0.0;
382 bool pixelPitchIsReal = false;
383 for( int k=0; k<N; ++k)
384 {
385 if(int(pixelPitch[k]) != pixelPitch[k])
386 pixelPitchIsReal = true;
387 dmax += sq(pixelPitch[k]*shape[k]);
388 }
389
390 using namespace vigra::functor;
391
392 if(dmax > NumericTraits<DestType>::toRealPromote(NumericTraits<DestType>::max())
393 || pixelPitchIsReal) // need a temporary array to avoid overflows
394 {
395 // Threshold the values so all objects have infinity value in the beginning
396 Real maxDist = (Real)dmax, rzero = (Real)0.0;
397 MultiArray<SrcShape::static_size, Real> tmpArray(shape);
398 if(background == true)
399 transformMultiArray( s, shape, src,
400 tmpArray.traverser_begin(), typename AccessorTraits<Real>::default_accessor(),
401 ifThenElse( Arg1() == Param(zero), Param(maxDist), Param(rzero) ));
402 else
403 transformMultiArray( s, shape, src,
404 tmpArray.traverser_begin(), typename AccessorTraits<Real>::default_accessor(),
405 ifThenElse( Arg1() != Param(zero), Param(maxDist), Param(rzero) ));
406
407 detail::internalSeparableMultiArrayDistTmp( tmpArray.traverser_begin(),
408 shape, typename AccessorTraits<Real>::default_accessor(),
409 tmpArray.traverser_begin(),
410 typename AccessorTraits<Real>::default_accessor(), pixelPitch);
411
412 copyMultiArray(srcMultiArrayRange(tmpArray), destIter(d, dest));
413 }
414 else // work directly on the destination array
415 {
416 // Threshold the values so all objects have infinity value in the beginning
417 DestType maxDist = DestType(std::ceil(dmax)), rzero = (DestType)0;
418 if(background == true)
419 transformMultiArray( s, shape, src, d, dest,
420 ifThenElse( Arg1() == Param(zero), Param(maxDist), Param(rzero) ));
421 else
422 transformMultiArray( s, shape, src, d, dest,
423 ifThenElse( Arg1() != Param(zero), Param(maxDist), Param(rzero) ));
424
425 detail::internalSeparableMultiArrayDistTmp( d, shape, dest, d, dest, pixelPitch);
426 }
427 }
428
429 template <class SrcIterator, class SrcShape, class SrcAccessor,
430 class DestIterator, class DestAccessor>
431 inline
432 void separableMultiDistSquared( SrcIterator s, SrcShape const & shape, SrcAccessor src,
433 DestIterator d, DestAccessor dest, bool background)
434 {
435 ArrayVector<double> pixelPitch(shape.size(), 1.0);
436 separableMultiDistSquared( s, shape, src, d, dest, background, pixelPitch );
437 }
438
439 template <class SrcIterator, class SrcShape, class SrcAccessor,
440 class DestIterator, class DestAccessor, class Array>
441 inline void separableMultiDistSquared( triple<SrcIterator, SrcShape, SrcAccessor> const & source,
442 pair<DestIterator, DestAccessor> const & dest, bool background,
443 Array const & pixelPitch)
444 {
445 separableMultiDistSquared( source.first, source.second, source.third,
446 dest.first, dest.second, background, pixelPitch );
447 }
448
449 template <class SrcIterator, class SrcShape, class SrcAccessor,
450 class DestIterator, class DestAccessor>
451 inline void separableMultiDistSquared( triple<SrcIterator, SrcShape, SrcAccessor> const & source,
452 pair<DestIterator, DestAccessor> const & dest, bool background)
453 {
454 separableMultiDistSquared( source.first, source.second, source.third,
455 dest.first, dest.second, background );
456 }
457
458 template <unsigned int N, class T1, class S1,
459 class T2, class S2,
460 class Array>
461 inline void
462 separableMultiDistSquared(MultiArrayView<N, T1, S1> const & source,
463 MultiArrayView<N, T2, S2> dest, bool background,
464 Array const & pixelPitch)
465 {
466 vigra_precondition(source.shape() == dest.shape(),
467 "separableMultiDistSquared(): shape mismatch between input and output.");
468 separableMultiDistSquared( srcMultiArrayRange(source),
469 destMultiArray(dest), background, pixelPitch );
470 }
471
472 template <unsigned int N, class T1, class S1,
473 class T2, class S2>
474 inline void
475 separableMultiDistSquared(MultiArrayView<N, T1, S1> const & source,
476 MultiArrayView<N, T2, S2> dest, bool background)
477 {
478 vigra_precondition(source.shape() == dest.shape(),
479 "separableMultiDistSquared(): shape mismatch between input and output.");
480 separableMultiDistSquared( srcMultiArrayRange(source),
481 destMultiArray(dest), background );
482 }
483
484 /********************************************************/
485 /* */
486 /* separableMultiDistance */
487 /* */
488 /********************************************************/
489
490 /** \brief Euclidean distance on multi-dimensional arrays.
491
492 <b> Declarations:</b>
493
494 pass arbitrary-dimensional array views:
495 \code
496 namespace vigra {
497 // explicitly specify pixel pitch for each coordinate
498 template <unsigned int N, class T1, class S1,
499 class T2, class S2, class Array>
500 void
501 separableMultiDistance(MultiArrayView<N, T1, S1> const & source,
502 MultiArrayView<N, T2, S2> dest,
503 bool background,
504 Array const & pixelPitch);
505
506 // use default pixel pitch = 1.0 for each coordinate
507 template <unsigned int N, class T1, class S1,
508 class T2, class S2>
509 void
510 separableMultiDistance(MultiArrayView<N, T1, S1> const & source,
511 MultiArrayView<N, T2, S2> dest,
512 bool background);
513 }
514 \endcode
515
516 \deprecatedAPI{separableMultiDistance}
517 pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
518 \code
519 namespace vigra {
520 // explicitly specify pixel pitch for each coordinate
521 template <class SrcIterator, class SrcShape, class SrcAccessor,
522 class DestIterator, class DestAccessor, class Array>
523 void
524 separableMultiDistance( SrcIterator s, SrcShape const & shape, SrcAccessor src,
525 DestIterator d, DestAccessor dest,
526 bool background,
527 Array const & pixelPitch);
528
529 // use default pixel pitch = 1.0 for each coordinate
530 template <class SrcIterator, class SrcShape, class SrcAccessor,
531 class DestIterator, class DestAccessor>
532 void
533 separableMultiDistance(SrcIterator siter, SrcShape const & shape, SrcAccessor src,
534 DestIterator diter, DestAccessor dest,
535 bool background);
536
537 }
538 \endcode
539 use argument objects in conjunction with \ref ArgumentObjectFactories :
540 \code
541 namespace vigra {
542 // explicitly specify pixel pitch for each coordinate
543 template <class SrcIterator, class SrcShape, class SrcAccessor,
544 class DestIterator, class DestAccessor, class Array>
545 void
546 separableMultiDistance( triple<SrcIterator, SrcShape, SrcAccessor> const & source,
547 pair<DestIterator, DestAccessor> const & dest,
548 bool background,
549 Array const & pixelPitch);
550
551 // use default pixel pitch = 1.0 for each coordinate
552 template <class SrcIterator, class SrcShape, class SrcAccessor,
553 class DestIterator, class DestAccessor>
554 void
555 separableMultiDistance(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
556 pair<DestIterator, DestAccessor> const & dest,
557 bool background);
558
559 }
560 \endcode
561 \deprecatedEnd
562
563 This function performs a Euclidean distance transform on the given
564 multi-dimensional array. It simply calls \ref separableMultiDistSquared()
565 and takes the pixel-wise square root of the result. See \ref separableMultiDistSquared()
566 for more documentation.
567
568 <b> Usage:</b>
569
570 <b>\#include</b> <vigra/multi_distance.hxx><br/>
571 Namespace: vigra
572
573 \code
574 Shape3 shape(width, height, depth);
575 MultiArray<3, unsigned char> source(shape);
576 MultiArray<3, float> dest(shape);
577 ...
578
579 // Calculate Euclidean distance squared for all background pixels
580 separableMultiDistance(source, dest, true);
581 \endcode
582
583 \see vigra::distanceTransform(), vigra::separableMultiDistSquared()
584 */
585 doxygen_overloaded_function(template <...> void separableMultiDistance)
586
587 template <class SrcIterator, class SrcShape, class SrcAccessor,
588 class DestIterator, class DestAccessor, class Array>
589 void separableMultiDistance( SrcIterator s, SrcShape const & shape, SrcAccessor src,
590 DestIterator d, DestAccessor dest, bool background,
591 Array const & pixelPitch)
592 {
593 separableMultiDistSquared( s, shape, src, d, dest, background, pixelPitch);
594
595 // Finally, calculate the square root of the distances
596 using namespace vigra::functor;
597
598 transformMultiArray( d, shape, dest, d, dest, sqrt(Arg1()) );
599 }
600
601 template <class SrcIterator, class SrcShape, class SrcAccessor,
602 class DestIterator, class DestAccessor>
603 void separableMultiDistance( SrcIterator s, SrcShape const & shape, SrcAccessor src,
604 DestIterator d, DestAccessor dest, bool background)
605 {
606 separableMultiDistSquared( s, shape, src, d, dest, background);
607
608 // Finally, calculate the square root of the distances
609 using namespace vigra::functor;
610
611 transformMultiArray( d, shape, dest, d, dest, sqrt(Arg1()) );
612 }
613
614 template <class SrcIterator, class SrcShape, class SrcAccessor,
615 class DestIterator, class DestAccessor, class Array>
616 inline void separableMultiDistance( triple<SrcIterator, SrcShape, SrcAccessor> const & source,
617 pair<DestIterator, DestAccessor> const & dest, bool background,
618 Array const & pixelPitch)
619 {
620 separableMultiDistance( source.first, source.second, source.third,
621 dest.first, dest.second, background, pixelPitch );
622 }
623
624 template <class SrcIterator, class SrcShape, class SrcAccessor,
625 class DestIterator, class DestAccessor>
626 inline void separableMultiDistance( triple<SrcIterator, SrcShape, SrcAccessor> const & source,
627 pair<DestIterator, DestAccessor> const & dest, bool background)
628 {
629 separableMultiDistance( source.first, source.second, source.third,
630 dest.first, dest.second, background );
631 }
632
633 template <unsigned int N, class T1, class S1,
634 class T2, class S2, class Array>
635 inline void
636 separableMultiDistance(MultiArrayView<N, T1, S1> const & source,
637 MultiArrayView<N, T2, S2> dest,
638 bool background,
639 Array const & pixelPitch)
640 {
641 vigra_precondition(source.shape() == dest.shape(),
642 "separableMultiDistance(): shape mismatch between input and output.");
643 separableMultiDistance( srcMultiArrayRange(source),
644 destMultiArray(dest), background, pixelPitch );
645 }
646
647 template <unsigned int N, class T1, class S1,
648 class T2, class S2>
649 inline void
650 separableMultiDistance(MultiArrayView<N, T1, S1> const & source,
651 MultiArrayView<N, T2, S2> dest,
652 bool background)
653 {
654 vigra_precondition(source.shape() == dest.shape(),
655 "separableMultiDistance(): shape mismatch between input and output.");
656 separableMultiDistance( srcMultiArrayRange(source),
657 destMultiArray(dest), background );
658 }
659
660 //@}
661
662 } //-- namespace vigra
663
664
665 #endif //-- VIGRA_MULTI_DISTANCE_HXX

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