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

labelimage.hxx VIGRA

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_LABELIMAGE_HXX
38 #define VIGRA_LABELIMAGE_HXX
39 
40 #include <vector>
41 #include <functional>
42 #include "utilities.hxx"
43 #include "stdimage.hxx"
44 #include "union_find.hxx"
45 #include "sized_int.hxx"
46 #include "multi_shape.hxx"
47 
48 namespace vigra {
49 
50 /** \addtogroup Labeling Connected Components Labeling
51  The 2-dimensional connected components algorithms may use either 4 or 8 connectivity.
52  By means of a functor the merge criterion can be defined arbitrarily.
53 */
54 //@{
55 
56 /********************************************************/
57 /* */
58 /* labelImage */
59 /* */
60 /********************************************************/
61 
62 /** \brief Find the connected components of a segmented image.
63 
64  Deprecated. Use \ref labelMultiArray() instead.
65 
66  Connected components are defined as regions with uniform pixel
67  values. Thus, <TT>T1</TT> either must be
68  equality comparable, or a suitable EqualityFunctor must be
69  provided that realizes the desired predicate. The
70  destination's value type <tt>T2</tt> should be large enough to hold the labels
71  without overflow. Region numbers will be a consecutive sequence
72  starting with one and ending with the region number returned by
73  the function (inclusive). The parameter '<TT>eight_neighbors</TT>'
74  determines whether the regions should be 4-connected (false) or
75  8-connected (true).
76 
77  Return: the number of regions found (= largest region label)
78 
79  See \ref labelMultiArray() for a dimension-independent implementation of
80  connected components labelling.
81 
82  <b> Declarations:</b>
83 
84  pass 2D array views:
85  \code
86  namespace vigra {
87  template <class T1, class S1,
88  class T2, class S2,
89  class EqualityFunctor = std::equal_to<T1> >
90  unsigned int
91  labelImage(MultiArrayView<2, T1, S1> const & src,
92  MultiArrayView<2, T2, S2> dest,
93  bool eight_neighbors, EqualityFunctor equal = EqualityFunctor());
94  }
95  \endcode
96 
97  \deprecatedAPI{labelImage}
98  pass \ref ImageIterators and \ref DataAccessors :
99  \code
100  namespace vigra {
101  template <class SrcIterator, class SrcAccessor,
102  class DestIterator, class DestAccessor>
103  unsigned int labelImage(SrcIterator upperlefts,
104  SrcIterator lowerrights, SrcAccessor sa,
105  DestIterator upperleftd, DestAccessor da,
106  bool eight_neighbors);
107 
108  template <class SrcIterator, class SrcAccessor,
109  class DestIterator, class DestAccessor,
110  class EqualityFunctor>
111  unsigned int labelImage(SrcIterator upperlefts,
112  SrcIterator lowerrights, SrcAccessor sa,
113  DestIterator upperleftd, DestAccessor da,
114  bool eight_neighbors, EqualityFunctor equal);
115  }
116  \endcode
117  use argument objects in conjunction with \ref ArgumentObjectFactories :
118  \code
119  namespace vigra {
120  template <class SrcIterator, class SrcAccessor,
121  class DestIterator, class DestAccessor>
122  unsigned int labelImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
123  pair<DestIterator, DestAccessor> dest,
124  bool eight_neighbors);
125 
126  template <class SrcIterator, class SrcAccessor,
127  class DestIterator, class DestAccessor,
128  class EqualityFunctor>
129  unsigned int labelImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
130  pair<DestIterator, DestAccessor> dest,
131  bool eight_neighbors, EqualityFunctor equal)
132  }
133  \endcode
134  \deprecatedEnd
135 
136  <b> Usage:</b>
137 
138  <b>\#include</b> <vigra/labelimage.hxx><br>
139  Namespace: vigra
140 
141  \code
142  MultiArray<2, unsigned char> src(w,h);
143  MultiArray<2, unsigned int> labels(w,h);
144 
145  // threshold at 128
146  transformImage(src, src, Threshold<int, int>(128, 256, 0, 255));
147 
148  // find 4-connected regions
149  labelImage(src, labels, false);
150  \endcode
151 
152  \deprecatedUsage{labelImage}
153  \code
154  vigra::BImage src(w,h);
155  vigra::IImage labels(w,h);
156 
157  // threshold at 128
158  vigra::transformImage(srcImageRange(src), destImage(src),
159  vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType>(
160  128, 256, 0, 255));
161 
162  // find 4-connected regions
163  vigra::labelImage(srcImageRange(src), destImage(labels), false);
164  \endcode
165  <b> Required Interface:</b>
166  \code
167  SrcImageIterator src_upperleft, src_lowerright;
168  DestImageIterator dest_upperleft;
169 
170  SrcAccessor src_accessor;
171  DestAccessor dest_accessor;
172 
173  SrcAccessor::value_type u = src_accessor(src_upperleft);
174 
175  u == u // first form
176 
177  EqualityFunctor equal; // second form
178  equal(u, u) // second form
179 
180  int i;
181  dest_accessor.set(i, dest_upperleft);
182  \endcode
183  \deprecatedEnd
184 */
185 doxygen_overloaded_function(template <...> unsigned int labelImage)
186 
187 template <class SrcIterator, class SrcAccessor,
188  class DestIterator, class DestAccessor,
189  class EqualityFunctor>
190 unsigned int labelImage(SrcIterator upperlefts,
191  SrcIterator lowerrights, SrcAccessor sa,
192  DestIterator upperleftd, DestAccessor da,
193  bool eight_neighbors, EqualityFunctor equal)
194 {
195  typedef typename DestAccessor::value_type LabelType;
196 
197  int w = lowerrights.x - upperlefts.x;
198  int h = lowerrights.y - upperlefts.y;
199  int x,y,i;
200 
201  const Diff2D neighbor[] = {
202  Diff2D(-1,0), // left
203  Diff2D(-1,-1), // topleft
204  Diff2D(0,-1), // top
205  Diff2D(1,-1) // topright
206  };
207 
208  const int left = 0, /* unused: topleft = 1, */ top = 2, topright = 3;
209  int step = eight_neighbors ? 1 : 2;
210 
211  SrcIterator ys = upperlefts;
212  DestIterator yd = upperleftd;
213 
214  UnionFindArray<LabelType> label;
215 
216  // pass 1: scan image from upper left to lower right
217  // to find connected components
218 
219  // Each component will be represented by a tree of pixels. Each
220  // pixel contains the scan order address of its parent in the
221  // tree. In order for pass 2 to work correctly, the parent must
222  // always have a smaller scan order address than the child.
223  // Therefore, we can merge trees only at their roots, because the
224  // root of the combined tree must have the smallest scan order
225  // address among all the tree's pixels/ nodes. The root of each
226  // tree is distinguished by pointing to itself (it contains its
227  // own scan order address). This condition is enforced whenever a
228  // new region is found or two regions are merged
229 
230 
231  for(y = 0; y != h; ++y, ++ys.y, ++yd.y)
232  {
233  SrcIterator xs = ys;
234  DestIterator xd = yd;
235 
236  int endNeighbor = (y == 0) ? left : (eight_neighbors ? topright : top);
237 
238  for(x = 0; x != w; ++x, ++xs.x, ++xd.x)
239  {
240  int beginNeighbor = (x == 0) ? top : left;
241  if(x == w-1 && endNeighbor == topright) endNeighbor = top;
242 
243  for(i=beginNeighbor; i<=endNeighbor; i+=step)
244  {
245  if(equal(sa(xs), sa(xs, neighbor[i])))
246  {
247  LabelType neighborIndex = label.findIndex(da(xd,neighbor[i]));
248 
249  for(int j=i+2; j<=endNeighbor; j+=step)
250  {
251  if(equal(sa(xs), sa(xs, neighbor[j])))
252  {
253  neighborIndex = label.makeUnion(da(xd, neighbor[j]), neighborIndex);
254  break;
255  }
256  }
257  da.set(neighborIndex, xd);
258  break;
259  }
260 
261  }
262  if(i > endNeighbor)
263  {
264  da.set(label.makeNewIndex(), xd);
265  }
266  }
267  }
268 
269  // pass 2: assign one label to each region (tree)
270  // so that labels form a consecutive sequence 1, 2, ...
271  unsigned int count = label.makeContiguous();
272 
273  yd = upperleftd;
274  for(y=0; y != h; ++y, ++yd.y)
275  {
276  typename DestIterator::row_iterator xd = yd.rowIterator();
277  for(x = 0; x != w; ++x, ++xd)
278  {
279  da.set(label.findLabel(da(xd)), xd);
280  }
281  }
282  return count;
283 }
284 
285 template <class SrcIterator, class SrcAccessor,
286  class DestIterator, class DestAccessor>
287 inline
288 unsigned int labelImage(SrcIterator upperlefts,
289  SrcIterator lowerrights, SrcAccessor sa,
290  DestIterator upperleftd, DestAccessor da,
291  bool eight_neighbors)
292 {
293  return labelImage(upperlefts, lowerrights, sa,
294  upperleftd, da, eight_neighbors,
295  std::equal_to<typename SrcAccessor::value_type>());
296 }
297 
298 template <class SrcIterator, class SrcAccessor,
299  class DestIterator, class DestAccessor,
300  class EqualityFunctor>
301 inline unsigned int
302 labelImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
303  pair<DestIterator, DestAccessor> dest,
304  bool eight_neighbors, EqualityFunctor equal)
305 {
306  return labelImage(src.first, src.second, src.third,
307  dest.first, dest.second, eight_neighbors, equal);
308 }
309 
310 template <class SrcIterator, class SrcAccessor,
311  class DestIterator, class DestAccessor>
312 inline unsigned int
313 labelImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
314  pair<DestIterator, DestAccessor> dest,
315  bool eight_neighbors)
316 {
317  return labelImage(src.first, src.second, src.third,
318  dest.first, dest.second, eight_neighbors,
319  std::equal_to<typename SrcAccessor::value_type>());
320 }
321 
322 template <class T1, class S1,
323  class T2, class S2,
324  class EqualityFunctor>
325 inline unsigned int
326 labelImage(MultiArrayView<2, T1, S1> const & src,
327  MultiArrayView<2, T2, S2> dest,
328  bool eight_neighbors, EqualityFunctor equal)
329 {
330  vigra_precondition(src.shape() == dest.shape(),
331  "labelImage(): shape mismatch between input and output.");
332  return labelImage(srcImageRange(src),
333  destImage(dest), eight_neighbors, equal);
334 }
335 
336 template <class T1, class S1,
337  class T2, class S2>
338 inline unsigned int
339 labelImage(MultiArrayView<2, T1, S1> const & src,
340  MultiArrayView<2, T2, S2> dest,
341  bool eight_neighbors)
342 {
343  return labelImage(srcImageRange(src),
344  destImage(dest), eight_neighbors,
345  std::equal_to<T1>());
346 }
347 
348 /********************************************************/
349 /* */
350 /* labelImageWithBackground */
351 /* */
352 /********************************************************/
353 
354 /** \brief Find the connected components of a segmented image,
355  excluding the background from labeling.
356 
357  Deprecated. Use \ref labelMultiArray() instead.
358 
359  This function works like \ref labelImage(), but considers all background pixels
360  (i.e. pixels having the given '<TT>background_value</TT>') as a single region that
361  is ignored when determining connected components and remains untouched in the
362  destination image. Usually, you will zero-initialize the output image, so that
363  the background gets label 0 (remember that actual region labels start at one).
364 
365  Return: the number of non-background regions found (= largest region label)
366 
367  See \ref labelMultiArrayWithBackground() for a dimension-independent implementation
368  if this algorithm.
369 
370  <b> Declarations:</b>
371 
372  pass 2D array views:
373  \code
374  namespace vigra {
375  template <class T1, class S1,
376  class T2, class S2,
377  class ValueType,
378  class EqualityFunctor = std::equal_to<T1> >
379  unsigned int
380  labelImageWithBackground(MultiArrayView<2, T1, S1> const & src,
381  MultiArrayView<2, T2, S2> dest,
382  bool eight_neighbors,
383  ValueType background_value,
384  EqualityFunctor equal = EqualityFunctor());
385  }
386  \endcode
387 
388  \deprecatedAPI{labelImageWithBackground}
389  pass \ref ImageIterators and \ref DataAccessors :
390  \code
391  namespace vigra {
392  template <class SrcIterator, class SrcAccessor,
393  class DestIterator, class DestAccessor,
394  class ValueType>
395  int labelImageWithBackground(SrcIterator upperlefts,
396  SrcIterator lowerrights, SrcAccessor sa,
397  DestIterator upperleftd, DestAccessor da,
398  bool eight_neighbors,
399  ValueType background_value );
400 
401  template <class SrcIterator, class SrcAccessor,
402  class DestIterator, class DestAccessor,
403  class ValueType, class EqualityFunctor>
404  int labelImageWithBackground(SrcIterator upperlefts,
405  SrcIterator lowerrights, SrcAccessor sa,
406  DestIterator upperleftd, DestAccessor da,
407  bool eight_neighbors,
408  ValueType background_value, EqualityFunctor equal);
409  }
410  \endcode
411  use argument objects in conjunction with \ref ArgumentObjectFactories :
412  \code
413  namespace vigra {
414  template <class SrcIterator, class SrcAccessor,
415  class DestIterator, class DestAccessor,
416  class ValueType>
417  int labelImageWithBackground(triple<SrcIterator, SrcIterator, SrcAccessor> src,
418  pair<DestIterator, DestAccessor> dest,
419  bool eight_neighbors,
420  ValueType background_value);
421 
422  template <class SrcIterator, class SrcAccessor,
423  class DestIterator, class DestAccessor,
424  class ValueType, class EqualityFunctor>
425  int labelImageWithBackground(triple<SrcIterator, SrcIterator, SrcAccessor> src,
426  pair<DestIterator, DestAccessor> dest,
427  bool eight_neighbors,
428  ValueType background_value, EqualityFunctor equal);
429  }
430  \endcode
431  \deprecatedEnd
432 
433  <b> Usage:</b>
434 
435  <b>\#include</b> <vigra/labelimage.hxx><br>
436  Namespace: vigra
437 
438  \code
439  MultiArray<2, unsigned char> src(w,h);
440  MultiArray<2, unsigned int> labels(w,h);
441 
442  // threshold at 128
443  transformImage(src, src, Threshold<int, int>(128, 256, 0, 255));
444 
445  // find 4-connected regions of foreground (= white pixels) only
446  labelImageWithBackground(src, labels, false, 0);
447  \endcode
448 
449  \deprecatedUsage{labelImageWithBackground}
450  \code
451  vigra::BImage src(w,h);
452  vigra::IImage labels(w,h);
453 
454  // threshold at 128
455  vigra::transformImage(srcImageRange(src), destImage(src),
456  vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType>(
457  128, 256, 0, 255));
458 
459  // find 4-connected regions of foreground (= white pixels) only
460  vigra::labelImageWithBackground(srcImageRange(src), destImage(labels),
461  false, 0);
462  \endcode
463  <b> Required Interface:</b>
464  \code
465  SrcImageIterator src_upperleft, src_lowerright;
466  DestImageIterator dest_upperleft;
467 
468  SrcAccessor src_accessor;
469  DestAccessor dest_accessor;
470 
471  SrcAccessor::value_type u = src_accessor(src_upperleft);
472  ValueType background_value;
473 
474  u == u // first form
475  u == background_value // first form
476 
477  EqualityFunctor equal; // second form
478  equal(u, u) // second form
479  equal(u, background_value) // second form
480 
481  int i;
482  dest_accessor.set(i, dest_upperleft);
483  \endcode
484  \deprecatedEnd
485 */
486 doxygen_overloaded_function(template <...> unsigned int labelImageWithBackground)
487 
488 template <class SrcIterator, class SrcAccessor,
489  class DestIterator, class DestAccessor,
490  class ValueType, class EqualityFunctor>
491 unsigned int labelImageWithBackground(
492  SrcIterator upperlefts,
493  SrcIterator lowerrights, SrcAccessor sa,
494  DestIterator upperleftd, DestAccessor da,
495  bool eight_neighbors,
496  ValueType background_value, EqualityFunctor equal)
497 {
498  int w = lowerrights.x - upperlefts.x;
499  int h = lowerrights.y - upperlefts.y;
500  int x,y,i;
501 
502  const Diff2D neighbor[] = {
503  Diff2D(-1,0), // left
504  Diff2D(-1,-1), // topleft
505  Diff2D(0,-1), // top
506  Diff2D(1,-1) // topright
507  };
508 
509  const int left = 0, /* unused: topleft = 1,*/ top = 2, topright = 3;
510  int step = eight_neighbors ? 1 : 2;
511 
512  SrcIterator ys(upperlefts);
513  SrcIterator xs(ys);
514 
515  // temporary image to store region labels
516  typedef BasicImage<IntBiggest> TmpImage;
517  TmpImage labelimage(w, h);
518  TmpImage::ScanOrderIterator label = labelimage.begin();
519  TmpImage::Iterator yt = labelimage.upperLeft();
520  TmpImage::Iterator xt(yt);
521 
522  // pass 1: scan image from upper left to lower right
523  // find connected components
524 
525  for(y = 0; y != h; ++y, ++ys.y, ++yt.y)
526  {
527  xs = ys;
528  xt = yt;
529 
530  int endNeighbor = (y == 0) ? left : (eight_neighbors ? topright : top);
531 
532  for(x = 0; x != w; ++x, ++xs.x, ++xt.x)
533  {
534  if(equal(sa(xs), background_value))
535  {
536  *xt = -1;
537  }
538  else
539  {
540  int beginNeighbor = (x == 0) ? top : left;
541  if(x == w-1 && endNeighbor == topright) endNeighbor = top;
542 
543  for(i=beginNeighbor; i<=endNeighbor; i+=step)
544  {
545  if(equal(sa(xs), sa(xs, neighbor[i])))
546  {
547  IntBiggest neighborIndex = xt[neighbor[i]];
548 
549  for(int j=i+2; j<=endNeighbor; j+=step)
550  {
551  if(equal(sa(xs), sa(xs, neighbor[j])))
552  {
553  IntBiggest neighborLabel1 = xt[neighbor[j]];
554 
555  if(neighborIndex != neighborLabel1)
556  {
557  // find roots of the region trees
558  while(neighborIndex != label[neighborIndex])
559  {
560  neighborIndex = label[neighborIndex];
561  }
562  while(neighborLabel1 != label[neighborLabel1])
563  {
564  neighborLabel1 = label[neighborLabel1];
565  }
566 
567  // merge the trees
568  if(neighborLabel1 < neighborIndex)
569  {
570  label[neighborIndex] = neighborLabel1;
571  neighborIndex = neighborLabel1;
572  }
573  else if(neighborIndex < neighborLabel1)
574  {
575  label[neighborLabel1] = neighborIndex;
576  }
577  }
578  break;
579  }
580  }
581  *xt = neighborIndex;
582  break;
583  }
584 
585  }
586  if(i > endNeighbor)
587  {
588  // new region
589  // The initial label of a new region equals the
590  // scan order address of it's first pixel.
591  // This is essential for correct operation of the algorithm.
592  *xt = x + y*w;
593  }
594  }
595  }
596  }
597 
598  // pass 2: assign contiguous labels to the regions
599  DestIterator yd(upperleftd);
600 
601  int count = 0;
602  i = 0;
603  for(y=0; y != h; ++y, ++yd.y)
604  {
605  DestIterator xd(yd);
606  for(x = 0; x != w; ++x, ++xd.x, ++i)
607  {
608  if(label[i] == -1) continue;
609 
610  if(label[i] == i)
611  {
612  label[i] = count++;
613  }
614  else
615  {
616  label[i] = label[label[i]];
617  }
618  da.set(label[i]+1, xd);
619  }
620  }
621 
622  return count;
623 }
624 
625 template <class SrcIterator, class SrcAccessor,
626  class DestIterator, class DestAccessor,
627  class ValueType>
628 inline
629 unsigned int labelImageWithBackground(
630  SrcIterator upperlefts,
631  SrcIterator lowerrights, SrcAccessor sa,
632  DestIterator upperleftd, DestAccessor da,
633  bool eight_neighbors,
634  ValueType background_value)
635 {
636  return labelImageWithBackground(upperlefts, lowerrights, sa,
637  upperleftd, da,
638  eight_neighbors, background_value,
639  std::equal_to<typename SrcAccessor::value_type>());
640 }
641 
642 template <class SrcIterator, class SrcAccessor,
643  class DestIterator, class DestAccessor,
644  class ValueType, class EqualityFunctor>
645 inline unsigned int
646 labelImageWithBackground(triple<SrcIterator, SrcIterator, SrcAccessor> src,
647  pair<DestIterator, DestAccessor> dest,
648  bool eight_neighbors,
649  ValueType background_value, EqualityFunctor equal)
650 {
651  return labelImageWithBackground(src.first, src.second, src.third,
652  dest.first, dest.second,
653  eight_neighbors, background_value, equal);
654 }
655 
656 template <class SrcIterator, class SrcAccessor,
657  class DestIterator, class DestAccessor,
658  class ValueType>
659 inline unsigned int
660 labelImageWithBackground(triple<SrcIterator, SrcIterator, SrcAccessor> src,
661  pair<DestIterator, DestAccessor> dest,
662  bool eight_neighbors,
663  ValueType background_value)
664 {
665  return labelImageWithBackground(src.first, src.second, src.third,
666  dest.first, dest.second,
667  eight_neighbors, background_value,
668  std::equal_to<typename SrcAccessor::value_type>());
669 }
670 
671 template <class T1, class S1,
672  class T2, class S2,
673  class ValueType, class EqualityFunctor>
674 inline unsigned int
675 labelImageWithBackground(MultiArrayView<2, T1, S1> const & src,
676  MultiArrayView<2, T2, S2> dest,
677  bool eight_neighbors,
678  ValueType background_value, EqualityFunctor equal)
679 {
680  vigra_precondition(src.shape() == dest.shape(),
681  "labelImageWithBackground(): shape mismatch between input and output.");
682  return labelImageWithBackground(srcImageRange(src),
683  destImage(dest),
684  eight_neighbors, background_value, equal);
685 }
686 
687 template <class T1, class S1,
688  class T2, class S2,
689  class ValueType>
690 inline unsigned int
691 labelImageWithBackground(MultiArrayView<2, T1, S1> const & src,
692  MultiArrayView<2, T2, S2> dest,
693  bool eight_neighbors,
694  ValueType background_value)
695 {
696  vigra_precondition(src.shape() == dest.shape(),
697  "labelImageWithBackground(): shape mismatch between input and output.");
698  return labelImageWithBackground(srcImageRange(src),
699  destImage(dest),
700  eight_neighbors, background_value,
701  std::equal_to<T1>());
702 }
703 
704 /********************************************************/
705 /* */
706 /* regionImageToCrackEdgeImage */
707 /* */
708 /********************************************************/
709 
710 
711 enum EdgeImageLabelPolicy { CopyRegionLabels, EdgeOverlayOnly };
712 
713 
714 /** \brief Transform a labeled image into a crack edge (interpixel edge) image.
715 
716  <b> Declarations:</b>
717 
718  pass 2D array views:
719  \code
720  namespace vigra {
721  template <class T1, class S1,
722  class T2, class S2, class DestValue>
723  void
724  regionImageToCrackEdgeImage(MultiArrayView<2, T1, S1> const & src,
725  MultiArrayView<2, T2, S2> dest,
726  DestValue edge_marker,
727  EdgeImageLabelPolicy labelPolicy = CopyRegionLabels);
728  }
729  \endcode
730 
731  \deprecatedAPI{regionImageToCrackEdgeImage}
732  pass \ref ImageIterators and \ref DataAccessors :
733  \code
734  namespace vigra {
735  template <class SrcIterator, class SrcAccessor,
736  class DestIterator, class DestAccessor, class DestValue>
737  void regionImageToCrackEdgeImage(
738  SrcIterator sul, SrcIterator slr, SrcAccessor sa,
739  DestIterator dul, DestAccessor da,
740  DestValue edge_marker,
741  EdgeImageLabelPolicy labelPolicy = CopyRegionLabels)
742  }
743  \endcode
744  use argument objects in conjunction with \ref ArgumentObjectFactories :
745  \code
746  namespace vigra {
747  template <class SrcIterator, class SrcAccessor,
748  class DestIterator, class DestAccessor, class DestValue>
749  void regionImageToCrackEdgeImage(
750  triple<SrcIterator, SrcIterator, SrcAccessor> src,
751  pair<DestIterator, DestAccessor> dest,
752  DestValue edge_marker,
753  EdgeImageLabelPolicy labelPolicy = CopyRegionLabels)
754  }
755  \endcode
756  \deprecatedEnd
757 
758  The destination image must be twice the size of the input image (precisely,
759  <TT>(2*w-1)</TT> by <TT>(2*h-1)</TT> pixels) to have space for the so called
760  "crack edges" or "interpixel edges" which are logically situated between pixels
761  (at half-integer coordinates of the input image) and correspond to the odd-valued
762  coordinates in the result image (see \ref CrackEdgeImage for more details).
763 
764  When <tt>labelPolicy == CopyRegionLabels</tt> (the default), this algorithm
765  transfers the labels of a labeled image to the output image (repeating them
766  as appropriate to account for the output image size) and inserts border pixels
767  when the label changes. For example, if <TT>a</TT> and <TT>c</TT> are the
768  original labels, and <TT>0</TT> is the value of <TT>edge_marker</TT>, the
769  transformation looks like this:
770 
771  \code
772  original image copy labels and insert edges
773 
774  a 0 c c c
775  a c c a 0 0 0 c
776  a a c => a a a 0 c
777  a a a a a a 0 0
778  a a a a a
779  \endcode
780 
781  When <tt>labelPolicy == EdgeOverlayOnly</tt>, the region pixels of the output
782  image remain untouched, and only the edge marker is inserted. This is especially
783  useful for visualization, when the output is the interpolated original image:
784  \code
785  original image destination image overlay edges only
786 
787  d d d d d d 0 d d d
788  a c c d d d d d d 0 0 0 d
789  a a c + d d d d d => d d d 0 d
790  a a a d d d d d d d d 0 0
791  d d d d d d d d d d
792  \endcode
793 
794  The algorithm assumes that the original labeled image contains
795  no background. Therefore, it is suitable as a post-processing
796  operation of \ref labelImage() or \ref seededRegionGrowing().
797 
798  The source value type (<TT>SrcAccessor::value-type</TT>) must be
799  equality-comparable.
800 
801  <b> Usage:</b>
802 
803  <b>\#include</b> <vigra/labelimage.hxx><br>
804  Namespace: vigra
805 
806  \code
807  MultiArray<2, unsigned char> src(w,h);
808  MultiArray<2, unsigned int> labels(w,h),
809  cellgrid(2*w-1, 2*h-1);
810 
811  // threshold at 128
812  transformImage(src, src, Threshold<int, int>(128, 256, 0, 255));
813 
814  // find 4-connected regions
815  labelImage(src, labels, false);
816 
817  // create cell grid image, mark edges with 0
818  regionImageToCrackEdgeImage(labels, cellgrid, 0);
819  \endcode
820 
821  \deprecatedUsage{regionImageToCrackEdgeImage}
822  \code
823  vigra::BImage src(w,h);
824  vigra::IImage labels(w,h);
825  vigra::IImage cellgrid(2*w-1, 2*h-1);
826 
827  // threshold at 128
828  vigra::transformImage(srcImageRange(src), destImage(src),
829  vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType>(
830  128, 256, 0, 255));
831 
832  // find 4-connected regions
833  vigra::labelImage(srcImageRange(src), destImage(labels), false);
834 
835  // create cell grid image, mark edges with 0
836  vigra::regionImageToCrackEdgeImage(srcImageRange(labels), destImage(cellgrid), 0);
837  \endcode
838  <b> Required Interface:</b>
839  \code
840  ImageIterator src_upperleft, src_lowerright;
841  ImageIterator dest_upperleft;
842 
843  SrcAccessor src_accessor;
844  DestAccessor dest_accessor;
845 
846  SrcAccessor::value_type u = src_accessor(src_upperleft);
847 
848  u != u
849 
850  DestValue edge_marker;
851  dest_accessor.set(edge_marker, dest_upperleft);
852  \endcode
853  \deprecatedEnd
854 
855  <b> Preconditions:</b>
856 
857  The destination image must have twice the size of the source:
858  \code
859  w_dest = 2 * w_src - 1
860  h_dest = 2 * h_src - 1
861  \endcode
862 */
864 
865 template <class SrcIterator, class SrcAccessor,
866  class DestIterator, class DestAccessor, class DestValue>
868  SrcIterator sul, SrcIterator slr, SrcAccessor sa,
869  DestIterator dul, DestAccessor da,
870  DestValue edge_marker,
871  EdgeImageLabelPolicy labelPolicy = CopyRegionLabels)
872 {
873  int w = slr.x - sul.x;
874  int h = slr.y - sul.y;
875  int x,y;
876 
877  const Diff2D right(1,0);
878  const Diff2D left(-1,0);
879  const Diff2D bottomright(1,1);
880  const Diff2D bottom(0,1);
881  const Diff2D top(0,-1);
882 
883  SrcIterator iy = sul;
884  DestIterator dy = dul;
885 
886  for(y=0; y<h-1; ++y, ++iy.y, dy.y+=2)
887  {
888  SrcIterator ix = iy;
889  DestIterator dx = dy;
890 
891  for(x=0; x<w-1; ++x, ++ix.x, dx.x+=2)
892  {
893  if(labelPolicy == CopyRegionLabels)
894  {
895  da.set(sa(ix), dx);
896  da.set(sa(ix), dx, bottomright);
897  }
898 
899  if(sa(ix, right) != sa(ix))
900  {
901  da.set(edge_marker, dx, right);
902  }
903  else if(labelPolicy == CopyRegionLabels)
904  {
905  da.set(sa(ix), dx, right);
906  }
907  if(sa(ix, bottom) != sa(ix))
908  {
909  da.set(edge_marker, dx, bottom);
910  }
911  else if(labelPolicy == CopyRegionLabels)
912  {
913  da.set(sa(ix), dx, bottom);
914  }
915 
916  }
917 
918  if(labelPolicy == CopyRegionLabels)
919  {
920  da.set(sa(ix), dx);
921  }
922  if(sa(ix, bottom) != sa(ix))
923  {
924  da.set(edge_marker, dx, bottom);
925  }
926  else if(labelPolicy == CopyRegionLabels)
927  {
928  da.set(sa(ix), dx, bottom);
929  }
930  }
931 
932  SrcIterator ix = iy;
933  DestIterator dx = dy;
934 
935  for(x=0; x<w-1; ++x, ++ix.x, dx.x+=2)
936  {
937  if(labelPolicy == CopyRegionLabels)
938  {
939  da.set(sa(ix), dx);
940  }
941  if(sa(ix, right) != sa(ix))
942  {
943  da.set(edge_marker, dx, right);
944  }
945  else if(labelPolicy == CopyRegionLabels)
946  {
947  da.set(sa(ix), dx, right);
948  }
949  }
950  if(labelPolicy == CopyRegionLabels)
951  {
952  da.set(sa(ix), dx);
953  }
954  dy = dul + Diff2D(1,1);
955 
956  const Diff2D dist[] = {right, top, left, bottom };
957  // find missing 0-cells
958  for(y=0; y<h-1; ++y, dy.y+=2)
959  {
960  DestIterator dx = dy;
961 
962  for(x=0; x<w-1; ++x, dx.x+=2)
963  {
964  int i;
965  for(i=0; i<4; ++i)
966  {
967  if(da(dx, dist[i]) == edge_marker) break;
968  }
969 
970  if(i < 4) da.set(edge_marker, dx);
971  }
972  }
973 }
974 
975 template <class SrcIterator, class SrcAccessor,
976  class DestIterator, class DestAccessor, class DestValue>
977 inline void
978 regionImageToCrackEdgeImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
979  pair<DestIterator, DestAccessor> dest,
980  DestValue edge_marker,
981  EdgeImageLabelPolicy labelPolicy = CopyRegionLabels)
982 {
983  regionImageToCrackEdgeImage(src.first, src.second, src.third,
984  dest.first, dest.second,
985  edge_marker, labelPolicy);
986 }
987 
988 template <class T1, class S1,
989  class T2, class S2, class DestValue>
990 inline void
991 regionImageToCrackEdgeImage(MultiArrayView<2, T1, S1> const & src,
992  MultiArrayView<2, T2, S2> dest,
993  DestValue edge_marker,
994  EdgeImageLabelPolicy labelPolicy = CopyRegionLabels)
995 {
996  vigra_precondition(2*src.shape()-Shape2(1) == dest.shape(),
997  "regionImageToCrackEdgeImage(): shape mismatch between input and output.");
998  regionImageToCrackEdgeImage(srcImageRange(src),
999  destImage(dest),
1000  edge_marker,
1001  labelPolicy);
1002 }
1003 
1004 /********************************************************/
1005 /* */
1006 /* regionImageToEdgeImage */
1007 /* */
1008 /********************************************************/
1009 
1010 /** \brief Transform a labeled image into an edge image.
1011 
1012  <b> Declarations:</b>
1013 
1014  pass 2D array views:
1015  \code
1016  namespace vigra {
1017  template <class T1, class S1,
1018  class T2, class S2, class DestValue>
1019  void
1020  regionImageToEdgeImage(MultiArrayView<2, T1, S1> const & src,
1021  MultiArrayView<2, T2, S2> dest,
1022  DestValue edge_marker);
1023  }
1024  \endcode
1025 
1026  \deprecatedAPI{regionImageToEdgeImage}
1027  pass \ref ImageIterators and \ref DataAccessors :
1028  \code
1029  namespace vigra {
1030  template <class SrcIterator, class SrcAccessor,
1031  class DestIterator, class DestAccessor, class DestValue>
1032  void regionImageToEdgeImage(
1033  SrcIterator sul, SrcIterator slr, SrcAccessor sa,
1034  DestIterator dul, DestAccessor da,
1035  DestValue edge_marker)
1036  }
1037  \endcode
1038  use argument objects in conjunction with \ref ArgumentObjectFactories :
1039  \code
1040  namespace vigra {
1041  template <class SrcIterator, class SrcAccessor,
1042  class DestIterator, class DestAccessor, class DestValue>
1043  void regionImageToEdgeImage(
1044  triple<SrcIterator, SrcIterator, SrcAccessor> src,
1045  pair<DestIterator, DestAccessor> dest,
1046  DestValue edge_marker)
1047  }
1048  \endcode
1049  \deprecatedEnd
1050 
1051  This algorithm marks all pixels with the given <TT>edge_marker</TT>
1052  which belong to a different region (label) than their right or lower
1053  neighbors:
1054 
1055  \code
1056  original image edges
1057  (assuming edge_marker == 1)
1058 
1059  a c c 1 1 *
1060  a a c => * 1 1
1061  a a a * * *
1062  \endcode
1063 
1064  The non-edge pixels of the destination image will not be touched.
1065  The source value type <TT>T1</TT> must be
1066  equality-comparable.
1067 
1068  <b> Usage:</b>
1069 
1070  <b>\#include</b> <vigra/labelimage.hxx><br>
1071  Namespace: vigra
1072 
1073  \code
1074  MultiArray<2, unsigned char> src(w,h),
1075  edges(w,h);
1076  MultiArray<2, unsigned int> labels(w,h);
1077 
1078  edges = 255; // init background (non-edge) to 255
1079 
1080  // threshold at 128
1081  transformImage(src, src, Threshold<int, int>(128, 256, 0, 255));
1082 
1083  // find 4-connected regions
1084  labelImage(src, labels, false);
1085 
1086  // create edge image, mark edges with 0
1087  regionImageToEdgeImage(labels, edges, 0);
1088  \endcode
1089 
1090  \deprecatedUsage{regionImageToEdgeImage}
1091  \code
1092  vigra::BImage src(w,h);
1093  vigra::IImage labels(w,h);
1094  vigra::IImage edges(w, h);
1095  edges = 255; // init background (non-edge) to 255
1096 
1097  // threshold at 128
1098  vigra::transformImage(srcImageRange(src), destImage(src),
1099  vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType>(
1100  128, 256, 0, 255));
1101 
1102  // find 4-connected regions
1103  vigra::labelImage(srcImageRange(src), destImage(labels), false);
1104 
1105  // create edge image, mark edges with 0
1106  vigra::regionImageToEdgeImage(srcImageRange(labels), destImage(edges), 0);
1107  \endcode
1108  <b> Required Interface:</b>
1109  \code
1110  ImageIterator src_upperleft, src_lowerright;
1111  ImageIterator dest_upperleft;
1112 
1113  SrcAccessor src_accessor;
1114  DestAccessor dest_accessor;
1115 
1116  SrcAccessor::value_type u = src_accessor(src_upperleft);
1117 
1118  u != u
1119 
1120  DestValue edge_marker;
1121  dest_accessor.set(edge_marker, dest_upperleft);
1122  \endcode
1123  \deprecatedEnd
1124 */
1126 
1127 template <class SrcIterator, class SrcAccessor,
1128  class DestIterator, class DestAccessor, class DestValue>
1130  SrcIterator sul, SrcIterator slr, SrcAccessor sa,
1131  DestIterator dul, DestAccessor da,
1132  DestValue edge_marker)
1133 {
1134  int w = slr.x - sul.x;
1135  int h = slr.y - sul.y;
1136  int x,y;
1137 
1138  const Diff2D right(1,0);
1139  const Diff2D left(-1,0);
1140  const Diff2D bottomright(1,1);
1141  const Diff2D bottom(0,1);
1142  const Diff2D top(0,-1);
1143 
1144  SrcIterator iy = sul;
1145  DestIterator dy = dul;
1146 
1147  for(y=0; y<h-1; ++y, ++iy.y, ++dy.y)
1148  {
1149  SrcIterator ix = iy;
1150  DestIterator dx = dy;
1151 
1152  for(x=0; x<w-1; ++x, ++ix.x, ++dx.x)
1153  {
1154  if(sa(ix, right) != sa(ix))
1155  {
1156  da.set(edge_marker, dx);
1157  }
1158  if(sa(ix, bottom) != sa(ix))
1159  {
1160  da.set(edge_marker, dx);
1161  }
1162  }
1163 
1164  if(sa(ix, bottom) != sa(ix))
1165  {
1166  da.set(edge_marker, dx);
1167  }
1168  }
1169 
1170  SrcIterator ix = iy;
1171  DestIterator dx = dy;
1172 
1173  for(x=0; x<w-1; ++x, ++ix.x, ++dx.x)
1174  {
1175  if(sa(ix, right) != sa(ix))
1176  {
1177  da.set(edge_marker, dx);
1178  }
1179  }
1180 }
1181 
1182 template <class SrcIterator, class SrcAccessor,
1183  class DestIterator, class DestAccessor, class DestValue>
1184 inline void
1185 regionImageToEdgeImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1186  pair<DestIterator, DestAccessor> dest,
1187  DestValue edge_marker)
1188 {
1189  regionImageToEdgeImage(src.first, src.second, src.third,
1190  dest.first, dest.second,
1191  edge_marker);
1192 }
1193 
1194 template <class T1, class S1,
1195  class T2, class S2, class DestValue>
1196 inline void
1197 regionImageToEdgeImage(MultiArrayView<2, T1, S1> const & src,
1198  MultiArrayView<2, T2, S2> dest,
1199  DestValue edge_marker)
1200 {
1201  vigra_precondition(src.shape() == dest.shape(),
1202  "regionImageToEdgeImage(): shape mismatch between input and output.");
1203  regionImageToEdgeImage(srcImageRange(src),
1204  destImage(dest),
1205  edge_marker);
1206 }
1207 
1208 //@}
1209 
1210 } // namespace vigra
1211 
1212 #endif // VIGRA_LABELIMAGE_HXX
unsigned int labelImage(...)
Find the connected components of a segmented image.
unsigned int labelImageWithBackground(...)
Find the connected components of a segmented image, excluding the background from labeling...
void regionImageToEdgeImage(...)
Transform a labeled image into an edge image.
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
void regionImageToCrackEdgeImage(...)
Transform a labeled image into a crack edge (interpixel edge) image.
detail::SelectBiggestIntegerType< detail::SignedIntTypes >::type IntBiggest
the biggest signed integer type of the system
Definition: sized_int.hxx:188

© 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.1 (Fri May 19 2017)