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

multi_morphology.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_MORPHOLOGY_HXX
38 #define VIGRA_MULTI_MORPHOLOGY_HXX
39 
40 #include <vector>
41 #include <cmath>
42 #include "multi_distance.hxx"
43 #include "array_vector.hxx"
44 #include "multi_array.hxx"
45 #include "accessor.hxx"
46 #include "numerictraits.hxx"
47 #include "navigator.hxx"
48 #include "metaprogramming.hxx"
49 #include "multi_pointoperators.hxx"
50 #include "functorexpression.hxx"
51 
52 namespace vigra
53 {
54 
55 namespace detail {
56 
57 // this class simplifies the design, but more importantly, it makes sure
58 // that the in-place code doesn't get compiled for boolean arrays
59 // (were it would never executed anyway -- see the specializations below)
60 template <class DestType, class TmpType>
61 struct MultiBinaryMorphologyImpl
62 {
63  template <class SrcIterator, class SrcShape, class SrcAccessor,
64  class DestIterator, class DestAccessor>
65  static void
66  exec( SrcIterator s, SrcShape const & shape, SrcAccessor src,
67  DestIterator d, DestAccessor dest,
68  double radius, bool dilation)
69  {
70  using namespace vigra::functor;
71 
72  // Allocate a new temporary array if the distances squared wouldn't fit
73  MultiArray<SrcShape::static_size, TmpType> tmpArray(shape);
74 
75  separableMultiDistSquared(s, shape, src,
76  tmpArray.traverser_begin(), typename AccessorTraits<TmpType>::default_accessor(), dilation );
77 
78  // threshold everything less than radius away from the edge
79  double radius2 = radius * radius;
80  DestType foreground = dilation
81  ? NumericTraits<DestType>::zero()
82  : NumericTraits<DestType>::one(),
83  background = dilation
84  ? NumericTraits<DestType>::one()
85  : NumericTraits<DestType>::zero();
86  transformMultiArray( tmpArray.traverser_begin(), shape, StandardValueAccessor<double>(),
87  d, dest,
88  ifThenElse( Arg1() >= Param(radius2),
89  Param(foreground), Param(background) ) );
90  }
91 };
92 
93 template <class DestType>
94 struct MultiBinaryMorphologyImpl<DestType, DestType>
95 {
96  template <class SrcIterator, class SrcShape, class SrcAccessor,
97  class DestIterator, class DestAccessor>
98  static void
99  exec( SrcIterator s, SrcShape const & shape, SrcAccessor src,
100  DestIterator d, DestAccessor dest,
101  double radius, bool dilation)
102  {
103  using namespace vigra::functor;
104 
105  separableMultiDistSquared( s, shape, src, d, dest, dilation );
106 
107  // threshold everything less than radius away from the edge
108  DestType radius2 = detail::RequiresExplicitCast<DestType>::cast(radius * radius);
109  DestType foreground = dilation
110  ? NumericTraits<DestType>::zero()
111  : NumericTraits<DestType>::one(),
112  background = dilation
113  ? NumericTraits<DestType>::one()
114  : NumericTraits<DestType>::zero();
115  transformMultiArray( d, shape, dest, d, dest,
116  ifThenElse( Arg1() > Param(radius2),
117  Param(foreground), Param(background) ) );
118  }
119 };
120 
121 template <>
122 struct MultiBinaryMorphologyImpl<bool, bool>
123 {
124  template <class SrcIterator, class SrcShape, class SrcAccessor,
125  class DestIterator, class DestAccessor>
126  static void
127  exec( SrcIterator s, SrcShape const & shape, SrcAccessor src,
128  DestIterator d, DestAccessor dest, double radius, bool dilation)
129  {
130  vigra_fail("multiBinaryMorphology(): Internal error (this function should never be called).");
131  }
132 };
133 
134 } // namespace detail
135 
136 /** \addtogroup MultiArrayMorphology Morphological operators for multi-dimensional arrays.
137 
138  These functions perform morphological operations on an arbitrary
139  dimensional array that is specified by iterators (compatible to \ref MultiIteratorPage)
140  and shape objects. It can therefore be applied to a wide range of data structures
141  (\ref vigra::MultiArrayView, \ref vigra::MultiArray etc.).
142 */
143 //@{
144 
145 /********************************************************/
146 /* */
147 /* multiBinaryErosion */
148 /* */
149 /********************************************************/
150 /** \brief Binary erosion on multi-dimensional arrays.
151 
152  This function applies a flat circular erosion operator with a given radius. The
153  operation is isotropic. The input is interpreted as a binary multi-dimensional
154  array where non-zero pixels represent foreground and zero pixels represent
155  background. In the output, foreground is always represented by ones
156  (i.e. NumericTrais<typename DestAccessor::value_type>::one()).
157 
158  This function may work in-place, which means that <tt>siter == diter</tt> is allowed.
159  A temporary internal array is only allocated if working on the destination
160  array directly would cause overflow errors (that is if
161  <tt> NumericTraits<typename DestAccessor::value_type>::max() < squaredNorm(shape)</tt>,
162  i.e. the squared length of the image diagonal doesn't fit into the destination type).
163 
164  <b> Declarations:</b>
165 
166  pass arguments explicitly:
167  \code
168  namespace vigra {
169  template <class SrcIterator, class SrcShape, class SrcAccessor,
170  class DestIterator, class DestAccessor>
171  void
172  multiBinaryErosion(SrcIterator siter, SrcShape const & shape, SrcAccessor src,
173  DestIterator diter, DestAccessor dest, int radius);
174 
175  }
176  \endcode
177 
178  use argument objects in conjunction with \ref ArgumentObjectFactories :
179  \code
180  namespace vigra {
181  template <class SrcIterator, class SrcShape, class SrcAccessor,
182  class DestIterator, class DestAccessor>
183  void
184  multiBinaryErosion(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
185  pair<DestIterator, DestAccessor> const & dest,
186  int radius);
187 
188  }
189  \endcode
190 
191  <b> Usage:</b>
192 
193  <b>\#include</b> <vigra/multi_morphology.hxx>
194 
195  \code
196  MultiArray<3, unsigned char>::size_type shape(width, height, depth);
197  MultiArray<3, unsigned char> source(shape);
198  MultiArray<3, unsigned char> dest(shape);
199  ...
200 
201  // perform isotropic binary erosion
202  multiBinaryErosion(srcMultiArrayRange(source), destMultiArray(dest), 3);
203  \endcode
204 
205  \see vigra::discErosion()
206 */
207 doxygen_overloaded_function(template <...> void multiBinaryErosion)
208 
209 template <class SrcIterator, class SrcShape, class SrcAccessor,
210  class DestIterator, class DestAccessor>
211 void
212 multiBinaryErosion( SrcIterator s, SrcShape const & shape, SrcAccessor src,
213  DestIterator d, DestAccessor dest, double radius)
214 {
215  typedef typename DestAccessor::value_type DestType;
216  typedef Int32 TmpType;
217 
218  double dmax = squaredNorm(shape);
219 
220  // Get the distance squared transform of the image
221  if(dmax > NumericTraits<DestType>::toRealPromote(NumericTraits<DestType>::max()))
222  {
223  detail::MultiBinaryMorphologyImpl<DestType, TmpType>::exec(s, shape, src, d, dest, radius, false);
224  }
225  else // work directly on the destination array
226  {
227  detail::MultiBinaryMorphologyImpl<DestType, DestType>::exec(s, shape, src, d, dest, radius, false);
228  }
229 }
230 
231 template <class SrcIterator, class SrcShape, class SrcAccessor,
232  class DestIterator, class DestAccessor>
233 inline
234 void multiBinaryErosion(
235  triple<SrcIterator, SrcShape, SrcAccessor> const & source,
236  pair<DestIterator, DestAccessor> const & dest, double radius)
237 {
238  multiBinaryErosion( source.first, source.second, source.third,
239  dest.first, dest.second, radius );
240 }
241 
242 
243 /********************************************************/
244 /* */
245 /* multiBinaryDilation */
246 /* */
247 /********************************************************/
248 
249 /** \brief Binary dilation on multi-dimensional arrays.
250 
251  This function applies a flat circular dilation operator with a given radius. The
252  operation is isotropic. The input is interpreted as a binary multi-dimensional
253  array where non-zero pixels represent foreground and zero pixels represent
254  background. In the output, foreground is always represented by ones
255  (i.e. NumericTrais<typename DestAccessor::value_type>::one()).
256 
257  This function may work in-place, which means that <tt>siter == diter</tt> is allowed.
258  A temporary internal array is only allocated if working on the destination
259  array directly would cause overflow errors (that is if
260  <tt> NumericTraits<typename DestAccessor::value_type>::max() < squaredNorm(shape)</tt>,
261  i.e. the squared length of the image diagonal doesn't fit into the destination type).
262 
263  <b> Declarations:</b>
264 
265  pass arguments explicitly:
266  \code
267  namespace vigra {
268  template <class SrcIterator, class SrcShape, class SrcAccessor,
269  class DestIterator, class DestAccessor>
270  void
271  multiBinaryDilation(SrcIterator siter, SrcShape const & shape, SrcAccessor src,
272  DestIterator diter, DestAccessor dest, int radius);
273 
274  }
275  \endcode
276 
277  use argument objects in conjunction with \ref ArgumentObjectFactories :
278  \code
279  namespace vigra {
280  template <class SrcIterator, class SrcShape, class SrcAccessor,
281  class DestIterator, class DestAccessor>
282  void
283  multiBinaryDilation(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
284  pair<DestIterator, DestAccessor> const & dest,
285  int radius);
286 
287  }
288  \endcode
289 
290  <b> Usage:</b>
291 
292  <b>\#include</b> <vigra/multi_morphology.hxx>
293 
294  \code
295  MultiArray<3, unsigned char>::size_type shape(width, height, depth);
296  MultiArray<3, unsigned char> source(shape);
297  MultiArray<3, unsigned char> dest(shape);
298  ...
299 
300  // perform isotropic binary erosion
301  multiBinaryDilation(srcMultiArrayRange(source), destMultiArray(dest), 3);
302  \endcode
303 
304  \see vigra::discDilation()
305 */
306 doxygen_overloaded_function(template <...> void multiBinaryDilation)
307 
308 template <class SrcIterator, class SrcShape, class SrcAccessor,
309  class DestIterator, class DestAccessor>
310 void
311 multiBinaryDilation( SrcIterator s, SrcShape const & shape, SrcAccessor src,
312  DestIterator d, DestAccessor dest, double radius)
313 {
314  typedef typename DestAccessor::value_type DestType;
315  typedef Int32 TmpType;
316 
317  double dmax = squaredNorm(shape);
318 
319  // Get the distance squared transform of the image
320  if(dmax > NumericTraits<DestType>::toRealPromote(NumericTraits<DestType>::max()))
321  {
322  detail::MultiBinaryMorphologyImpl<DestType, TmpType>::exec(s, shape, src, d, dest, radius, true);
323  }
324  else // work directly on the destination array
325  {
326  detail::MultiBinaryMorphologyImpl<DestType, DestType>::exec(s, shape, src, d, dest, radius, true);
327  }
328 }
329 
330 template <class SrcIterator, class SrcShape, class SrcAccessor,
331  class DestIterator, class DestAccessor>
332 inline
334  triple<SrcIterator, SrcShape, SrcAccessor> const & source,
335  pair<DestIterator, DestAccessor> const & dest, double radius)
336 {
337  multiBinaryDilation( source.first, source.second, source.third,
338  dest.first, dest.second, radius );
339 }
340 
341 /********************************************************/
342 /* */
343 /* multiGrayscaleErosion */
344 /* */
345 /********************************************************/
346 /** \brief Parabolic grayscale erosion on multi-dimensional arrays.
347 
348  This function applies a parabolic erosion operator with a given spread (sigma) on
349  a grayscale array. The operation is isotropic.
350  The input is a grayscale multi-dimensional array.
351 
352  This function may work in-place, which means that <tt>siter == diter</tt> is allowed.
353  A full-sized internal array is only allocated if working on the destination
354  array directly would cause overflow errors (i.e. if
355  <tt> typeid(typename DestAccessor::value_type) < N * M*M</tt>, where M is the
356  size of the largest dimension of the array.
357 
358  <b> Declarations:</b>
359 
360  pass arguments explicitly:
361  \code
362  namespace vigra {
363  template <class SrcIterator, class SrcShape, class SrcAccessor,
364  class DestIterator, class DestAccessor>
365  void
366  multiGrayscaleErosion(SrcIterator siter, SrcShape const & shape, SrcAccessor src,
367  DestIterator diter, DestAccessor dest, double sigma);
368 
369  }
370  \endcode
371 
372  use argument objects in conjunction with \ref ArgumentObjectFactories :
373  \code
374  namespace vigra {
375  template <class SrcIterator, class SrcShape, class SrcAccessor,
376  class DestIterator, class DestAccessor>
377  void
378  multiGrayscaleErosion(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
379  pair<DestIterator, DestAccessor> const & dest,
380  double sigma);
381 
382  }
383  \endcode
384 
385  <b> Usage:</b>
386 
387  <b>\#include</b> <vigra/multi_morphology.hxx>
388 
389  \code
390  MultiArray<3, unsigned char>::size_type shape(width, height, depth);
391  MultiArray<3, unsigned char> source(shape);
392  MultiArray<3, unsigned char> dest(shape);
393  ...
394 
395  // perform isotropic grayscale erosion
396  multiGrayscaleErosion(srcMultiArrayRange(source), destMultiArray(dest), 3.0);
397  \endcode
398 
399  \see vigra::discErosion()
400 */
401 doxygen_overloaded_function(template <...> void multiGrayscaleErosion)
402 
403 template <class SrcIterator, class SrcShape, class SrcAccessor,
404  class DestIterator, class DestAccessor>
405 void
406 multiGrayscaleErosion( SrcIterator s, SrcShape const & shape, SrcAccessor src,
407  DestIterator d, DestAccessor dest, double sigma)
408 {
409  typedef typename NumericTraits<typename DestAccessor::value_type>::ValueType DestType;
410  typedef typename NumericTraits<typename DestAccessor::value_type>::Promote TmpType;
411  DestType MaxValue = NumericTraits<DestType>::max();
412  enum { N = 1 + SrcIterator::level };
413 
414  // temporary array to hold the current line to enable in-place operation
415  ArrayVector<TmpType> tmp( shape[0] );
416 
417  typedef MultiArrayNavigator<SrcIterator, N> SNavigator;
418  typedef MultiArrayNavigator<DestIterator, N> DNavigator;
419 
420  int MaxDim = 0;
421  for( int i=0; i<N; i++)
422  if(MaxDim < shape[i]) MaxDim = shape[i];
423 
424  using namespace vigra::functor;
425 
426  ArrayVector<double> sigmas(shape.size(), sigma);
427 
428  // Allocate a new temporary array if the distances squared wouldn't fit
429  if(N*MaxDim*MaxDim > MaxValue)
430  {
431  MultiArray<SrcShape::static_size, TmpType> tmpArray(shape);
432 
433  detail::internalSeparableMultiArrayDistTmp( s, shape, src, tmpArray.traverser_begin(),
434  typename AccessorTraits<TmpType>::default_accessor(), sigmas );
435 
436  transformMultiArray( tmpArray.traverser_begin(), shape,
437  typename AccessorTraits<TmpType>::default_accessor(), d, dest,
438  ifThenElse( Arg1() > Param(MaxValue), Param(MaxValue), Arg1() ) );
439  //copyMultiArray( tmpArray.traverser_begin(), shape,
440  // typename AccessorTraits<TmpType>::default_accessor(), d, dest );
441  }
442  else
443  {
444  detail::internalSeparableMultiArrayDistTmp( s, shape, src, d, dest, sigmas );
445  }
446 
447 }
448 
449 template <class SrcIterator, class SrcShape, class SrcAccessor,
450  class DestIterator, class DestAccessor>
451 inline
453  triple<SrcIterator, SrcShape, SrcAccessor> const & source,
454  pair<DestIterator, DestAccessor> const & dest, double sigma)
455 {
456  multiGrayscaleErosion( source.first, source.second, source.third,
457  dest.first, dest.second, sigma);
458 }
459 
460 /********************************************************/
461 /* */
462 /* multiGrayscaleDilation */
463 /* */
464 /********************************************************/
465 /** \brief Parabolic grayscale dilation on multi-dimensional arrays.
466 
467  This function applies a parabolic dilation operator with a given spread (sigma) on
468  a grayscale array. The operation is isotropic.
469  The input is a grayscale multi-dimensional array.
470 
471  This function may work in-place, which means that <tt>siter == diter</tt> is allowed.
472  A full-sized internal array is only allocated if working on the destination
473  array directly would cause overflow errors (i.e. if
474  <tt> typeid(typename DestAccessor::value_type) < N * M*M</tt>, where M is the
475  size of the largest dimension of the array.
476 
477  <b> Declarations:</b>
478 
479  pass arguments explicitly:
480  \code
481  namespace vigra {
482  template <class SrcIterator, class SrcShape, class SrcAccessor,
483  class DestIterator, class DestAccessor>
484  void
485  multiGrayscaleDilation(SrcIterator siter, SrcShape const & shape, SrcAccessor src,
486  DestIterator diter, DestAccessor dest, double sigma);
487 
488  }
489  \endcode
490 
491  use argument objects in conjunction with \ref ArgumentObjectFactories :
492  \code
493  namespace vigra {
494  template <class SrcIterator, class SrcShape, class SrcAccessor,
495  class DestIterator, class DestAccessor>
496  void
497  multiGrayscaleDilation(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
498  pair<DestIterator, DestAccessor> const & dest,
499  double sigma);
500 
501  }
502  \endcode
503 
504  <b> Usage:</b>
505 
506  <b>\#include</b> <vigra/multi_morphology.hxx>
507 
508  \code
509  MultiArray<3, unsigned char>::size_type shape(width, height, depth);
510  MultiArray<3, unsigned char> source(shape);
511  MultiArray<3, unsigned char> dest(shape);
512  ...
513 
514  // perform isotropic grayscale erosion
515  multiGrayscaleDilation(srcMultiArrayRange(source), destMultiArray(dest), 3.0);
516  \endcode
517 
518  \see vigra::discErosion()
519 */
520 doxygen_overloaded_function(template <...> void multiGrayscaleDilation)
521 
522 template <class SrcIterator, class SrcShape, class SrcAccessor,
523  class DestIterator, class DestAccessor>
524 void multiGrayscaleDilation( SrcIterator s, SrcShape const & shape, SrcAccessor src,
525  DestIterator d, DestAccessor dest, double sigma)
526 {
527  typedef typename NumericTraits<typename DestAccessor::value_type>::ValueType DestType;
528  typedef typename NumericTraits<typename DestAccessor::value_type>::Promote TmpType;
529  DestType MinValue = NumericTraits<DestType>::min();
530  DestType MaxValue = NumericTraits<DestType>::max();
531  enum { N = 1 + SrcIterator::level };
532 
533  // temporary array to hold the current line to enable in-place operation
534  ArrayVector<TmpType> tmp( shape[0] );
535 
536  typedef MultiArrayNavigator<SrcIterator, N> SNavigator;
537  typedef MultiArrayNavigator<DestIterator, N> DNavigator;
538 
539  int MaxDim = 0;
540  for( int i=0; i<N; i++)
541  if(MaxDim < shape[i]) MaxDim = shape[i];
542 
543  using namespace vigra::functor;
544 
545  ArrayVector<double> sigmas(shape.size(), sigma);
546 
547  // Allocate a new temporary array if the distances squared wouldn't fit
548  if(-N*MaxDim*MaxDim < MinValue || N*MaxDim*MaxDim > MaxValue)
549  {
550  MultiArray<SrcShape::static_size, TmpType> tmpArray(shape);
551 
552  detail::internalSeparableMultiArrayDistTmp( s, shape, src, tmpArray.traverser_begin(),
553  typename AccessorTraits<TmpType>::default_accessor(), sigmas, true );
554 
555  transformMultiArray( tmpArray.traverser_begin(), shape,
556  typename AccessorTraits<TmpType>::default_accessor(), d, dest,
557  ifThenElse( Arg1() > Param(MaxValue), Param(MaxValue),
558  ifThenElse( Arg1() < Param(MinValue), Param(MinValue), Arg1() ) ) );
559  }
560  else
561  {
562  detail::internalSeparableMultiArrayDistTmp( s, shape, src, d, dest, sigmas, true );
563  }
564 
565 }
566 
567 
568 template <class SrcIterator, class SrcShape, class SrcAccessor,
569  class DestIterator, class DestAccessor>
570 inline
572  triple<SrcIterator, SrcShape, SrcAccessor> const & source,
573  pair<DestIterator, DestAccessor> const & dest, double sigma)
574 {
575  multiGrayscaleDilation( source.first, source.second, source.third,
576  dest.first, dest.second, sigma);
577 }
578 
579 
580 //@}
581 
582 } //-- namespace vigra
583 
584 
585 #endif //-- VIGRA_MULTI_MORPHOLOGY_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.9.0 (Tue Oct 22 2013)