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

labelvolume.hxx VIGRA

1 /************************************************************************/
2 /* */
3 /* Copyright 2006-2007 by F. Heinrich, B. Seppke, 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 #ifndef VIGRA_LABELVOLUME_HXX
37 #define VIGRA_LABELVOLUME_HXX
38 
39 
40 #include "voxelneighborhood.hxx"
41 #include "multi_array.hxx"
42 #include "union_find.hxx"
43 
44 namespace vigra{
45 
46 /** \addtogroup Labeling Connected Components Labeling
47  The 3-dimensional connected components algorithms may use either 6 or 26 connectivity.
48  By means of a functor the merge criterion can be defined arbitrarily.
49 */
50 //@{
51 
52 /********************************************************/
53 /* */
54 /* labelVolume */
55 /* */
56 /********************************************************/
57 
58 /** \brief Find the connected components of a segmented volume.
59 
60  Connected components are defined as regions with uniform voxel
61  values. Thus, <TT>T1</TT> either must be equality comparable,
62  or an EqualityFunctor must be provided explicitly that realizes
63  the desired equivalence predicate. The destination's value type
64  <tt>T2</tt> should be large enough to hold the labels
65  without overflow. Region numbers will be a consecutive sequence
66  starting with one and ending with the region number returned by
67  the function (inclusive).
68 
69  Return: the number of regions found (= largest region label)
70 
71  See \ref labelMultiArray() for a dimension-independent implementation of
72  connected components labelling.
73 
74  <b> Declarations:</b>
75 
76  pass 3D array views:
77  \code
78  namespace vigra {
79  template <class T1, class S1,
80  class T2, class S2,
81  class Neighborhood3D,
82  class EqualityFunctor = std::equal_to<T1> >
83  unsigned int
84  labelVolume(MultiArrayView<3, T1, S1> const & source,
85  MultiArrayView<3, T2, S2> dest,
86  Neighborhood3D neighborhood3D,
87  EqualityFunctor equal = EqualityFunctor());
88 
89  }
90  \endcode
91 
92  \deprecatedAPI{labelVolume}
93  pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
94  \code
95  namespace vigra {
96 
97  template <class SrcIterator, class SrcAccessor,class SrcShape,
98  class DestIterator, class DestAccessor,
99  class Neighborhood3D>
100  unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
101  DestIterator d_Iter, DestAccessor da,
102  Neighborhood3D neighborhood3D);
103 
104  template <class SrcIterator, class SrcAccessor,class SrcShape,
105  class DestIterator, class DestAccessor,
106  class Neighborhood3D, class EqualityFunctor>
107  unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
108  DestIterator d_Iter, DestAccessor da,
109  Neighborhood3D neighborhood3D, EqualityFunctor equal);
110 
111  }
112  \endcode
113  use argument objects in conjunction with \ref ArgumentObjectFactories :
114  \code
115  namespace vigra {
116 
117  template <class SrcIterator, class SrcAccessor,class SrcShape,
118  class DestIterator, class DestAccessor,
119  class Neighborhood3D>
120  unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src,
121  pair<DestIterator, DestAccessor> dest,
122  Neighborhood3D neighborhood3D);
123 
124  template <class SrcIterator, class SrcAccessor,class SrcShape,
125  class DestIterator, class DestAccessor,
126  class Neighborhood3D, class EqualityFunctor>
127  unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src,
128  pair<DestIterator, DestAccessor> dest,
129  Neighborhood3D neighborhood3D, EqualityFunctor equal);
130 
131  }
132  \endcode
133  use with 3D-Six-Neighborhood:
134  \code
135  namespace vigra {
136 
137  template <class SrcIterator, class SrcAccessor,class SrcShape,
138  class DestIterator, class DestAccessor>
139  unsigned int labelVolumeSix(triple<SrcIterator, SrcShape, SrcAccessor> src,
140  pair<DestIterator, DestAccessor> dest);
141 
142  }
143  \endcode
144  \deprecatedEnd
145 
146  <b> Usage:</b>
147 
148  <b>\#include</b> <vigra/labelvolume.hxx><br>
149  Namespace: vigra
150 
151  \code
152  typedef MultiArray<3,int> IntVolume;
153  IntVolume src(Shape3(w,h,d));
154  IntVolume dest(Shape3(w,h,d));
155 
156  // find 6-connected regions
157  int max_region_label = labelVolumeSix(src, dest);
158 
159  // find 26-connected regions
160  int max_region_label = labelVolume(src, dest, NeighborCode3DTwentySix());
161  \endcode
162 
163  \deprecatedUsage{labelVolume}
164  \code
165  typedef vigra::MultiArray<3,int> IntVolume;
166  IntVolume src(IntVolume::difference_type(w,h,d));
167  IntVolume dest(IntVolume::difference_type(w,h,d));
168 
169  // find 6-connected regions
170  int max_region_label = vigra::labelVolumeSix(srcMultiArrayRange(src), destMultiArray(dest));
171 
172  // find 26-connected regions
173  int max_region_label = vigra::labelVolume(srcMultiArrayRange(src), destMultiArray(dest), NeighborCode3DTwentySix());
174  \endcode
175  <b> Required Interface:</b>
176  \code
177  SrcIterator src_begin;
178  SrcShape shape;
179  DestIterator dest_begin;
180 
181  SrcAccessor src_accessor;
182  DestAccessor dest_accessor;
183 
184  SrcAccessor::value_type u = src_accessor(src_begin);
185 
186  u == u // first form
187 
188  EqualityFunctor equal; // second form
189  equal(u, u) // second form
190 
191  int i;
192  dest_accessor.set(i, dest_begin);
193  \endcode
194  \deprecatedEnd
195 */
196 doxygen_overloaded_function(template <...> unsigned int labelVolume)
197 
198 
199 template <class SrcIterator, class SrcAccessor,class SrcShape,
200  class DestIterator, class DestAccessor,
201  class Neighborhood3D, class EqualityFunctor>
202 unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
203  DestIterator d_Iter, DestAccessor da,
204  Neighborhood3D, EqualityFunctor equal)
205 {
206  typedef typename DestAccessor::value_type LabelType;
207 
208  //basically needed for iteration and border-checks
209  int w = srcShape[0], h = srcShape[1], d = srcShape[2];
210  int x,y,z;
211 
212  // temporary image to store region labels
213  UnionFindArray<LabelType> label;
214 
215  //Declare traversers for all three dims at target
216  SrcIterator zs = s_Iter;
217  DestIterator zd = d_Iter;
218 
219  // initialize the neighborhood traversers
220  NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast);
221  ++nce;
222  // pass 1: scan image from upper left front to lower right back
223  // to find connected components
224 
225  // Each component will be represented by a tree of pixels. Each
226  // pixel contains the scan order address of its parent in the
227  // tree. In order for pass 2 to work correctly, the parent must
228  // always have a smaller scan order address than the child.
229  // Therefore, we can merge trees only at their roots, because the
230  // root of the combined tree must have the smallest scan order
231  // address among all the tree's pixels/ nodes. The root of each
232  // tree is distinguished by pointing to itself (it contains its
233  // own scan order address). This condition is enforced whenever a
234  // new region is found or two regions are merged
235  for(z = 0; z != d; ++z, ++zs.dim2(), ++zd.dim2())
236  {
237  SrcIterator ys(zs);
238  DestIterator yd(zd);
239 
240  for(y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1())
241  {
242  SrcIterator xs(ys);
243  DestIterator xd(yd);
244 
245  for(x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0())
246  {
247  LabelType currentIndex = label.nextFreeIndex();
248 
249  //check whether there is a special border treatment to be used or not
250  AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h,d);
251 
252  //We are not at the border!
253  if(atBorder == NotAtBorder)
254  {
255  NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::CausalFirst);
256 
257  do
258  {
259  // if colors are equal
260  if(equal(sa(xs), sa(xs, *nc)))
261  {
262  currentIndex = label.makeUnion(da(xd,*nc), currentIndex);
263  }
264  ++nc;
265  }
266  while(nc!=nce);
267  }
268  else //we are at a border - handle this!!
269  {
270  NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::nearBorderDirectionsCausal(atBorder,0));
271  int j=0;
272  while(nc.direction() != Neighborhood3D::Error)
273  {
274  int dummy = x+(*nc)[0]; // prevents an apparently incorrect optimization in gcc 4.8
275  if (dummy<0)
276  {
277  std::cerr << "internal error " << dummy << std::endl;
278  }
279  // colors equal???
280  if(equal(sa(xs), sa(xs, *nc)))
281  {
282  currentIndex = label.makeUnion(da(xd,*nc), currentIndex);
283  }
284  nc.turnTo(Neighborhood3D::nearBorderDirectionsCausal(atBorder,++j));
285  }
286  }
287  da.set(label.finalizeIndex(currentIndex), xd);
288  }
289  }
290  }
291 
292  LabelType count = label.makeContiguous();
293 
294  // pass 2: assign one label to each region (tree)
295  // so that labels form a consecutive sequence 1, 2, ...
296  zd = d_Iter;
297  for(z=0; z != d; ++z, ++zd.dim2())
298  {
299  DestIterator yd(zd);
300 
301  for(y=0; y != h; ++y, ++yd.dim1())
302  {
303  DestIterator xd(yd);
304 
305  for(x = 0; x != w; ++x, ++xd.dim0())
306  {
307  da.set(label.findLabel(da(xd)), xd);
308  }
309  }
310  }
311  return count;
312 }
313 
314 template <class SrcIterator, class SrcAccessor,class SrcShape,
315  class DestIterator, class DestAccessor,
316  class Neighborhood3D>
317 unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
318  DestIterator d_Iter, DestAccessor da,
319  Neighborhood3D neighborhood3D)
320 {
321  return labelVolume(s_Iter, srcShape, sa, d_Iter, da, neighborhood3D, std::equal_to<typename SrcAccessor::value_type>());
322 }
323 
324 template <class SrcIterator, class SrcShape, class SrcAccessor,
325  class DestIterator, class DestAccessor,
326  class Neighborhood3D>
327 unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src,
328  pair<DestIterator, DestAccessor> dest,
329  Neighborhood3D neighborhood3D)
330 {
331  return labelVolume(src.first, src.second, src.third, dest.first, dest.second, neighborhood3D, std::equal_to<typename SrcAccessor::value_type>());
332 }
333 
334 template <class SrcIterator, class SrcShape, class SrcAccessor,
335  class DestIterator, class DestAccessor,
336  class Neighborhood3D, class EqualityFunctor>
337 unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src,
338  pair<DestIterator, DestAccessor> dest,
339  Neighborhood3D neighborhood3D, EqualityFunctor equal)
340 {
341  return labelVolume(src.first, src.second, src.third, dest.first, dest.second, neighborhood3D, equal);
342 }
343 
344 template <class T1, class S1,
345  class T2, class S2,
346  class Neighborhood3D, class EqualityFunctor>
347 inline unsigned int
348 labelVolume(MultiArrayView<3, T1, S1> const & source,
349  MultiArrayView<3, T2, S2> dest,
350  Neighborhood3D neighborhood3D,
351  EqualityFunctor equal)
352 {
353  vigra_precondition(source.shape() == dest.shape(),
354  "labelVolume(): shape mismatch between input and output.");
355  return labelVolume(srcMultiArrayRange(source), destMultiArray(dest), neighborhood3D, equal);
356 }
357 
358 template <class T1, class S1,
359  class T2, class S2,
360  class Neighborhood3D>
361 inline unsigned int
362 labelVolume(MultiArrayView<3, T1, S1> const & source,
363  MultiArrayView<3, T2, S2> dest,
364  Neighborhood3D neighborhood3D)
365 {
366  vigra_precondition(source.shape() == dest.shape(),
367  "labelVolume(): shape mismatch between input and output.");
368  return labelVolume(srcMultiArrayRange(source), destMultiArray(dest), neighborhood3D, std::equal_to<T1>());
369 }
370 
371 /********************************************************/
372 /* */
373 /* labelVolumeSix */
374 /* */
375 /********************************************************/
376 
377 /** \brief Find the connected components of a segmented volume
378  using the 6-neighborhood.
379 
380  See \ref labelVolume() for detailed documentation.
381 
382 */
383 template <class SrcIterator, class SrcAccessor,class SrcShape,
384  class DestIterator, class DestAccessor>
385 unsigned int labelVolumeSix(triple<SrcIterator, SrcShape, SrcAccessor> src,
386  pair<DestIterator, DestAccessor> dest)
387 {
388  return labelVolume(src.first, src.second, src.third, dest.first, dest.second, NeighborCode3DSix(), std::equal_to<typename SrcAccessor::value_type>());
389 }
390 
391 template <class T1, class S1,
392  class T2, class S2>
393 unsigned int labelVolumeSix(MultiArrayView<3, T1, S1> const & source,
394  MultiArrayView<3, T2, S2> dest)
395 {
396  return labelVolume(srcMultiArrayRange(source), destMultiArray(dest),
397  NeighborCode3DSix(), std::equal_to<T1>());
398 }
399 
400 /********************************************************/
401 /* */
402 /* labelVolumeWithBackground */
403 /* */
404 /********************************************************/
405 
406 /** \brief Find the connected components of a segmented volume,
407  excluding the background from labeling.
408 
409  This function works like \ref labelVolume(), but considers all background voxels
410  (i.e. voxels having the given '<TT>background_value</TT>') as a single region that
411  is ignored when determining connected components and remains untouched in the
412  destination array. Usually, you will zero-initialize the output array, so that
413  the background gets label 0 (remember that actual region labels start at one).
414 
415  Return: the number of regions found (= largest region label)
416 
417  See \ref labelMultiArrayWithBackground() for a dimension-independent implementation
418  if this algorithm.
419 
420  <b> Declarations:</b>
421 
422  pass 3D array views:
423  \code
424  namespace vigra {
425  template <class T1, class S1,
426  class T2, class S2,
427  class Neighborhood3D,
428  class ValueType,
429  class EqualityFunctor = std::equalt_to<T1> >
430  unsigned int
431  labelVolumeWithBackground(MultiArrayView<3, T1, S1> const & source,
432  MultiArrayView<3, T2, S2> dest,
433  Neighborhood3D neighborhood3D,
434  ValueType backgroundValue,
435  EqualityFunctor equal = EqualityFunctor());
436  }
437  \endcode
438 
439  \deprecatedAPI{labelVolumeWithBackground}
440  pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
441  \code
442  namespace vigra {
443 
444  template <class SrcIterator, class SrcAccessor,class SrcShape,
445  class DestIterator, class DestAccessor,
446  class Neighborhood3D, class ValueType>
447  unsigned int labelVolumeWithBackground( SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
448  DestIterator d_Iter, DestAccessor da,
449  Neighborhood3D neighborhood3D, ValueType background_value);
450 
451  template <class SrcIterator, class SrcAccessor,class SrcShape,
452  class DestIterator, class DestAccessor,
453  class Neighborhood3D, class ValueType, class EqualityFunctor>
454  unsigned int labelVolumeWithBackground( SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
455  DestIterator d_Iter, DestAccessor da,
456  Neighborhood3D neighborhood3D, ValueType background_value,
457  EqualityFunctor equal);
458 
459  }
460  \endcode
461  use argument objects in conjunction with \ref ArgumentObjectFactories :
462  \code
463  namespace vigra {
464 
465  template <class SrcIterator, class SrcAccessor,class SrcShape,
466  class DestIterator, class DestAccessor,
467  class Neighborhood3D, class ValueType>
468  unsigned int labelVolumeWithBackground( triple<SrcIterator, SrcShape, SrcAccessor> src,
469  pair<DestIterator, DestAccessor> dest,
470  Neighborhood3D neighborhood3D, ValueType background_value);
471 
472  template <class SrcIterator, class SrcAccessor,class SrcShape,
473  class DestIterator, class DestAccessor,
474  class Neighborhood3D, class ValueType, class EqualityFunctor>
475  unsigned int labelVolumeWithBackground( triple<SrcIterator, SrcShape, SrcAccessor> src,
476  pair<DestIterator, DestAccessor> dest,
477  Neighborhood3D neighborhood3D, ValueType background_value,
478  EqualityFunctor equal);
479 
480  }
481  \endcode
482  \deprecatedEnd
483 
484  <b> Usage:</b>
485 
486  <b>\#include</b> <vigra/labelvolume.hxx><br>
487  Namespace: vigra
488 
489  \code
490  typedef vigra::MultiArray<3,int> IntVolume;
491 
492  IntVolume src(Shape3(w,h,d));
493  IntVolume dest(Shape3(w,h,d));
494 
495  // find 6-connected regions
496  int max_region_label = labelVolumeWithBackground(src, dest, NeighborCode3DSix(), 0);
497  \endcode
498 
499  \deprecatedUsage{labelVolumeWithBackground}
500  \code
501  typedef vigra::MultiArray<3,int> IntVolume;
502  IntVolume src(IntVolume::difference_type(w,h,d));
503  IntVolume dest(IntVolume::difference_type(w,h,d));
504 
505  // find 6-connected regions
506  int max_region_label = vigra::labelVolumeWithBackground(
507  srcMultiArrayRange(src), destMultiArray(dest), NeighborCode3DSix(), 0);
508  \endcode
509  <b> Required Interface:</b>
510  \code
511  SrcIterator src_begin;
512  SrcShape shape;
513  DestIterator dest_begin;
514 
515  SrcAccessor src_accessor;
516  DestAccessor dest_accessor;
517 
518  SrcAccessor::value_type u = src_accessor(src_begin);
519 
520  u == u // first form
521 
522  EqualityFunctor equal; // second form
523  equal(u, u) // second form
524 
525  int i;
526  dest_accessor.set(i, dest_begin);
527  \endcode
528  \deprecatedEnd
529 */
530 doxygen_overloaded_function(template <...> unsigned int labelVolumeWithBackground)
531 
532 template <class SrcIterator, class SrcAccessor,class SrcShape,
533  class DestIterator, class DestAccessor,
534  class Neighborhood3D,
535  class ValueType, class EqualityFunctor>
536 unsigned int labelVolumeWithBackground(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
537  DestIterator d_Iter, DestAccessor da,
538  Neighborhood3D,
539  ValueType backgroundValue, EqualityFunctor equal)
540 {
541  typedef typename DestAccessor::value_type LabelType;
542 
543  //basically needed for iteration and border-checks
544  int w = srcShape[0], h = srcShape[1], d = srcShape[2];
545  int x,y,z;
546 
547  // temporary image to store region labels
548  UnionFindArray<LabelType> label;
549 
550  //Declare traversers for all three dims at target
551  SrcIterator zs = s_Iter;
552  DestIterator zd = d_Iter;
553 
554  // initialize the neighborhood traversers
555  NeighborOffsetCirculator<Neighborhood3D> nce(Neighborhood3D::CausalLast);
556  ++nce;
557  // pass 1: scan image from upper left front to lower right back
558  // to find connected components
559 
560  // Each component will be represented by a tree of pixels. Each
561  // pixel contains the scan order address of its parent in the
562  // tree. In order for pass 2 to work correctly, the parent must
563  // always have a smaller scan order address than the child.
564  // Therefore, we can merge trees only at their roots, because the
565  // root of the combined tree must have the smallest scan order
566  // address among all the tree's pixels/ nodes. The root of each
567  // tree is distinguished by pointing to itself (it contains its
568  // own scan order address). This condition is enforced whenever a
569  // new region is found or two regions are merged
570  for(z = 0; z != d; ++z, ++zs.dim2(), ++zd.dim2())
571  {
572  SrcIterator ys(zs);
573  DestIterator yd(zd);
574 
575  for(y = 0; y != h; ++y, ++ys.dim1(), ++yd.dim1())
576  {
577  SrcIterator xs(ys);
578  DestIterator xd(yd);
579 
580  for(x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0())
581  {
582  if(equal(sa(xs), backgroundValue))
583  {
584  //da.set(label.getIndex(0), xd);
585  da.set(0, xd);
586  continue;
587  }
588 
589  LabelType currentIndex = label.nextFreeIndex();
590 
591  //check whether there is a special border treatment to be used or not
592  AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h,d);
593 
594  //We are not at the border!
595  if(atBorder == NotAtBorder)
596  {
597  NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::CausalFirst);
598 
599  do
600  {
601  // if colors are equal
602  if(equal(sa(xs), sa(xs, *nc)))
603  {
604  currentIndex = label.makeUnion(da(xd,*nc), currentIndex);
605  }
606  ++nc;
607  }
608  while(nc!=nce);
609  }
610  else //we are at a border - handle this!!
611  {
612  NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::nearBorderDirectionsCausal(atBorder,0));
613  int j=0;
614  while(nc.direction() != Neighborhood3D::Error)
615  {
616  int dummy = x+(*nc)[0]; // prevents an apparently incorrect optimization in gcc 4.8
617  if (dummy<0)
618  {
619  std::cerr << "internal error " << dummy << std::endl;
620  }
621  // colors equal???
622  if(equal(sa(xs), sa(xs, *nc)))
623  {
624  currentIndex = label.makeUnion(da(xd,*nc), currentIndex);
625  }
626  nc.turnTo(Neighborhood3D::nearBorderDirectionsCausal(atBorder,++j));
627  }
628  }
629  da.set(label.finalizeIndex(currentIndex), xd);
630  }
631  }
632  }
633 
634  LabelType count = label.makeContiguous();
635 
636  // pass 2: assign one label to each region (tree)
637  // so that labels form a consecutive sequence 1, 2, ...
638  zd = d_Iter;
639  for(z=0; z != d; ++z, ++zd.dim2())
640  {
641  DestIterator yd(zd);
642 
643  for(y=0; y != h; ++y, ++yd.dim1())
644  {
645  DestIterator xd(yd);
646 
647  for(x = 0; x != w; ++x, ++xd.dim0())
648  {
649  da.set(label.findLabel(da(xd)), xd);
650  }
651  }
652  }
653  return count;
654 }
655 
656 template <class SrcIterator, class SrcAccessor,class SrcShape,
657  class DestIterator, class DestAccessor,
658  class Neighborhood3D,
659  class ValueType>
660 inline unsigned int
661 labelVolumeWithBackground(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
662  DestIterator d_Iter, DestAccessor da,
663  Neighborhood3D neighborhood3D, ValueType backgroundValue)
664 {
665  return labelVolumeWithBackground(s_Iter, srcShape, sa, d_Iter, da, neighborhood3D, backgroundValue, std::equal_to<typename SrcAccessor::value_type>());
666 }
667 
668 template <class SrcIterator, class SrcShape, class SrcAccessor,
669  class DestIterator, class DestAccessor,
670  class Neighborhood3D,
671  class ValueType,
672  class EqualityFunctor>
673 inline unsigned int
674 labelVolumeWithBackground(triple<SrcIterator, SrcShape, SrcAccessor> src,
675  pair<DestIterator, DestAccessor> dest,
676  Neighborhood3D neighborhood3D, ValueType backgroundValue, EqualityFunctor equal)
677 {
678  return labelVolumeWithBackground(src.first, src.second, src.third, dest.first, dest.second, neighborhood3D, backgroundValue, equal);
679 }
680 
681 template <class SrcIterator, class SrcShape, class SrcAccessor,
682  class DestIterator, class DestAccessor,
683  class Neighborhood3D,
684  class ValueType>
685 inline unsigned int
686 labelVolumeWithBackground(triple<SrcIterator, SrcShape, SrcAccessor> src,
687  pair<DestIterator, DestAccessor> dest,
688  Neighborhood3D neighborhood3D, ValueType backgroundValue)
689 {
690  return labelVolumeWithBackground(src.first, src.second, src.third, dest.first, dest.second,
691  neighborhood3D, backgroundValue, std::equal_to<typename SrcAccessor::value_type>());
692 }
693 
694 template <class T1, class S1,
695  class T2, class S2,
696  class Neighborhood3D,
697  class ValueType,
698  class EqualityFunctor>
699 inline unsigned int
700 labelVolumeWithBackground(MultiArrayView<3, T1, S1> const & source,
701  MultiArrayView<3, T2, S2> dest,
702  Neighborhood3D neighborhood3D,
703  ValueType backgroundValue,
704  EqualityFunctor equal)
705 {
706  vigra_precondition(source.shape() == dest.shape(),
707  "labelVolumeWithBackground(): shape mismatch between input and output.");
708  return labelVolumeWithBackground(srcMultiArrayRange(source), destMultiArray(dest),
709  neighborhood3D, backgroundValue, equal);
710 }
711 
712 template <class T1, class S1,
713  class T2, class S2,
714  class Neighborhood3D,
715  class ValueType>
716 inline unsigned int
717 labelVolumeWithBackground(MultiArrayView<3, T1, S1> const & source,
718  MultiArrayView<3, T2, S2> dest,
719  Neighborhood3D neighborhood3D,
720  ValueType backgroundValue)
721 {
722  vigra_precondition(source.shape() == dest.shape(),
723  "labelVolumeWithBackground(): shape mismatch between input and output.");
724  return labelVolumeWithBackground(srcMultiArrayRange(source), destMultiArray(dest),
725  neighborhood3D, backgroundValue,
726  std::equal_to<T1>());
727 }
728 
729 //@}
730 
731 } //end of namespace vigra
732 
733 #endif //VIGRA_LABELVOLUME_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 (Thu Jan 8 2015)