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

labelimage.hxx
1/************************************************************************/
2/* */
3/* Copyright 1998-2002 by Ullrich Koethe */
4/* */
5/* This file is part of the VIGRA computer vision library. */
6/* The VIGRA Website is */
7/* http://hci.iwr.uni-heidelberg.de/vigra/ */
8/* Please direct questions, bug reports, and contributions to */
9/* ullrich.koethe@iwr.uni-heidelberg.de or */
10/* vigra@informatik.uni-hamburg.de */
11/* */
12/* Permission is hereby granted, free of charge, to any person */
13/* obtaining a copy of this software and associated documentation */
14/* files (the "Software"), to deal in the Software without */
15/* restriction, including without limitation the rights to use, */
16/* copy, modify, merge, publish, distribute, sublicense, and/or */
17/* sell copies of the Software, and to permit persons to whom the */
18/* Software is furnished to do so, subject to the following */
19/* conditions: */
20/* */
21/* The above copyright notice and this permission notice shall be */
22/* included in all copies or substantial portions of the */
23/* Software. */
24/* */
25/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32/* OTHER DEALINGS IN THE SOFTWARE. */
33/* */
34/************************************************************************/
35
36
37#ifndef VIGRA_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
48namespace 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*/
185doxygen_overloaded_function(template <...> unsigned int labelImage)
186
187template <class SrcIterator, class SrcAccessor,
188 class DestIterator, class DestAccessor,
189 class EqualityFunctor>
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
213
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;
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
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
285template <class SrcIterator, class SrcAccessor,
286 class DestIterator, class DestAccessor>
287inline
288unsigned 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
298template <class SrcIterator, class SrcAccessor,
299 class DestIterator, class DestAccessor,
300 class EqualityFunctor>
301inline unsigned int
302labelImage(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
310template <class SrcIterator, class SrcAccessor,
311 class DestIterator, class DestAccessor>
312inline unsigned int
313labelImage(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
322template <class T1, class S1,
323 class T2, class S2,
324 class EqualityFunctor>
325inline unsigned int
326labelImage(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
336template <class T1, class S1,
337 class T2, class S2>
338inline unsigned int
339labelImage(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*/
486doxygen_overloaded_function(template <...> unsigned int labelImageWithBackground)
487
488template <class SrcIterator, class SrcAccessor,
489 class DestIterator, class DestAccessor,
490 class ValueType, class EqualityFunctor>
491unsigned int labelImageWithBackground(
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
514
515 // temporary image to store region labels
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
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 {
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
600
601 int count = 0;
602 i = 0;
603 for(y=0; y != h; ++y, ++yd.y)
604 {
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
625template <class SrcIterator, class SrcAccessor,
626 class DestIterator, class DestAccessor,
627 class ValueType>
628inline
629unsigned 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
642template <class SrcIterator, class SrcAccessor,
643 class DestIterator, class DestAccessor,
644 class ValueType, class EqualityFunctor>
645inline unsigned int
646labelImageWithBackground(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
656template <class SrcIterator, class SrcAccessor,
657 class DestIterator, class DestAccessor,
658 class ValueType>
659inline unsigned int
660labelImageWithBackground(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
671template <class T1, class S1,
672 class T2, class S2,
673 class ValueType, class EqualityFunctor>
674inline unsigned int
675labelImageWithBackground(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
687template <class T1, class S1,
688 class T2, class S2,
689 class ValueType>
690inline unsigned int
691labelImageWithBackground(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
711enum 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*/
863doxygen_overloaded_function(template <...> void regionImageToCrackEdgeImage)
864
865template <class SrcIterator, class SrcAccessor,
866 class DestIterator, class DestAccessor, class DestValue>
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
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
975template <class SrcIterator, class SrcAccessor,
976 class DestIterator, class DestAccessor, class DestValue>
977inline void
978regionImageToCrackEdgeImage(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
988template <class T1, class S1,
989 class T2, class S2, class DestValue>
990inline void
991regionImageToCrackEdgeImage(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*/
1125doxygen_overloaded_function(template <...> void regionImageToEdgeImage)
1126
1127template <class SrcIterator, class SrcAccessor,
1128 class DestIterator, class DestAccessor, class DestValue>
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
1182template <class SrcIterator, class SrcAccessor,
1183 class DestIterator, class DestAccessor, class DestValue>
1184inline void
1185regionImageToEdgeImage(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
1194template <class T1, class S1,
1195 class T2, class S2, class DestValue>
1196inline void
1197regionImageToEdgeImage(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
Two dimensional difference vector.
Definition diff2d.hxx:186
Class for a single RGB value.
Definition rgbvalue.hxx:128
iterator begin()
Definition tinyvector.hxx:861
detail::SelectBiggestIntegerType< detail::SignedIntTypes >::type IntBiggest
the biggest signed integer type of the system
Definition sized_int.hxx:188
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.
void regionImageToCrackEdgeImage(...)
Transform a labeled image into a crack edge (interpixel edge) image.
unsigned int labelImage(...)
Find the connected components of a segmented image.

© 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