36 #ifndef VIGRA_WATERSHEDS_HXX
37 #define VIGRA_WATERSHEDS_HXX
40 #include "mathutil.hxx"
41 #include "stdimage.hxx"
42 #include "pixelneighborhood.hxx"
43 #include "localminmax.hxx"
44 #include "labelimage.hxx"
45 #include "seededregiongrowing.hxx"
46 #include "functorexpression.hxx"
47 #include "union_find.hxx"
48 #include "multi_shape.hxx"
52 template <
class SrcIterator,
class SrcAccessor,
53 class DestIterator,
class DestAccessor,
55 unsigned int watershedLabeling(SrcIterator upperlefts,
56 SrcIterator lowerrights, SrcAccessor sa,
57 DestIterator upperleftd, DestAccessor da,
60 typedef typename DestAccessor::value_type LabelType;
62 int w = lowerrights.x - upperlefts.x;
63 int h = lowerrights.y - upperlefts.y;
66 SrcIterator ys(upperlefts);
68 DestIterator yd(upperleftd);
72 UnionFindArray<LabelType> labels;
75 NeighborOffsetCirculator<Neighborhood> ncstart(Neighborhood::CausalFirst);
76 NeighborOffsetCirculator<Neighborhood> ncstartBorder(Neighborhood::North);
77 NeighborOffsetCirculator<Neighborhood> ncend(Neighborhood::CausalLast);
79 NeighborOffsetCirculator<Neighborhood> ncendBorder(Neighborhood::North);
95 da.set(labels.finalizeIndex(labels.nextFreeIndex()), xd);
99 for(x = 1; x != w; ++x, ++xs.x, ++xd.x)
101 if((sa(xs) & Neighborhood::directionBit(Neighborhood::West)) ||
102 (sa(xs, Neighborhood::west()) & Neighborhood::directionBit(Neighborhood::East)))
104 da.set(da(xd, Neighborhood::west()), xd);
108 da.set(labels.finalizeIndex(labels.nextFreeIndex()), xd);
114 for(y = 1; y != h; ++y, ++ys.y, ++yd.y)
119 for(x = 0; x != w; ++x, ++xs.x, ++xd.x)
121 NeighborOffsetCirculator<Neighborhood> nc(x == w-1
124 NeighborOffsetCirculator<Neighborhood> nce(x == 0
127 LabelType currentIndex = labels.nextFreeIndex();
128 for(; nc != nce; ++nc)
130 if((sa(xs) & nc.directionBit()) || (sa(xs, *nc) & nc.oppositeDirectionBit()))
132 currentIndex = labels.makeUnion(da(xd,*nc), currentIndex);
135 da.set(labels.finalizeIndex(currentIndex), xd);
139 unsigned int count = labels.makeContiguous();
144 for(y=0; y != h; ++y, ++yd.y)
147 for(x = 0; x != w; ++x, ++xd.x)
149 da.set(labels.findLabel(da(xd)), xd);
155 template <
class SrcIterator,
class SrcAccessor,
156 class DestIterator,
class DestAccessor,
158 unsigned int watershedLabeling(triple<SrcIterator, SrcIterator, SrcAccessor> src,
159 pair<DestIterator, DestAccessor> dest,
160 Neighborhood neighborhood)
162 return watershedLabeling(src.first, src.second, src.third,
163 dest.first, dest.second, neighborhood);
167 template <
class SrcIterator,
class SrcAccessor,
168 class DestIterator,
class DestAccessor>
169 void prepareWatersheds(SrcIterator upperlefts, SrcIterator lowerrights, SrcAccessor sa,
170 DestIterator upperleftd, DestAccessor da,
173 int w = lowerrights.x - upperlefts.x;
174 int h = lowerrights.y - upperlefts.y;
177 SrcIterator ys(upperlefts);
180 DestIterator yd = upperleftd;
182 for(y = 0; y != h; ++y, ++ys.y, ++yd.y)
185 DestIterator xd = yd;
187 for(x = 0; x != w; ++x, ++xs.x, ++xd.x)
190 typename SrcAccessor::value_type v = sa(xs);
197 NeighborhoodCirculator<SrcIterator, FourNeighborCode> c(xs), cend(c);
202 o = c.directionBit();
209 RestrictedNeighborhoodCirculator<SrcIterator, FourNeighborCode> c(xs, atBorder), cend(c);
214 o = c.directionBit();
224 template <
class SrcIterator,
class SrcAccessor,
225 class DestIterator,
class DestAccessor>
226 void prepareWatersheds(SrcIterator upperlefts, SrcIterator lowerrights, SrcAccessor sa,
227 DestIterator upperleftd, DestAccessor da,
230 int w = lowerrights.x - upperlefts.x;
231 int h = lowerrights.y - upperlefts.y;
234 SrcIterator ys(upperlefts);
237 DestIterator yd = upperleftd;
239 for(y = 0; y != h; ++y, ++ys.y, ++yd.y)
242 DestIterator xd = yd;
244 for(x = 0; x != w; ++x, ++xs.x, ++xd.x)
247 typename SrcAccessor::value_type v = sa(xs);
257 NeighborhoodCirculator<SrcIterator, EightNeighborCode>
259 for(
int i = 0; i < 4; ++i, c += 2)
264 o = c.directionBit();
268 for(
int i = 0; i < 4; ++i, c += 2)
273 o = c.directionBit();
279 RestrictedNeighborhoodCirculator<SrcIterator, EightNeighborCode>
280 c(xs, atBorder), cend(c);
288 o = c.directionBit();
299 o = c.directionBit();
332 enum DetectMinima { LevelSets, Minima, ExtendedMinima, Unspecified };
342 : thresh(NumericTraits<double>::max()),
362 mini = ExtendedMinima;
403 bool thresholdIsValid()
const
405 return thresh < double(NumericTraits<T>::max());
492 template <
class SrcIterator,
class SrcAccessor,
493 class DestIterator,
class DestAccessor,
496 generateWatershedSeeds(SrcIterator upperlefts, SrcIterator lowerrights, SrcAccessor sa,
497 DestIterator upperleftd, DestAccessor da,
499 SeedOptions
const & options = SeedOptions())
501 using namespace functor;
502 typedef typename SrcAccessor::value_type SrcType;
504 vigra_precondition(options.mini != SeedOptions::LevelSets ||
505 options.thresholdIsValid<SrcType>(),
506 "generateWatershedSeeds(): SeedOptions.levelSets() must be specified with threshold.");
508 Diff2D shape = lowerrights - upperlefts;
511 if(options.mini == SeedOptions::LevelSets)
515 ifThenElse(Arg1() <= Param(options.thresh), Param(1), Param(0)));
519 LocalMinmaxOptions lm_options;
520 lm_options.neighborhood(Neighborhood::DirectionCount)
523 .allowPlateaus(options.mini == SeedOptions::ExtendedMinima);
524 if(options.thresholdIsValid<SrcType>())
525 lm_options.threshold(options.thresh);
527 localMinima(srcIterRange(upperlefts, lowerrights, sa), destImage(seeds),
532 Neighborhood::DirectionCount == 8, 0);
535 template <
class SrcIterator,
class SrcAccessor,
536 class DestIterator,
class DestAccessor>
538 generateWatershedSeeds(SrcIterator upperlefts, SrcIterator lowerrights, SrcAccessor sa,
539 DestIterator upperleftd, DestAccessor da,
540 SeedOptions
const & options = SeedOptions())
542 return generateWatershedSeeds(upperlefts, lowerrights, sa, upperleftd, da,
546 template <
class SrcIterator,
class SrcAccessor,
547 class DestIterator,
class DestAccessor,
550 generateWatershedSeeds(triple<SrcIterator, SrcIterator, SrcAccessor> src,
551 pair<DestIterator, DestAccessor> dest,
552 Neighborhood neighborhood,
553 SeedOptions
const & options = SeedOptions())
555 return generateWatershedSeeds(src.first, src.second, src.third,
556 dest.first, dest.second,
557 neighborhood, options);
560 template <
class SrcIterator,
class SrcAccessor,
561 class DestIterator,
class DestAccessor>
563 generateWatershedSeeds(triple<SrcIterator, SrcIterator, SrcAccessor> src,
564 pair<DestIterator, DestAccessor> dest,
565 SeedOptions
const & options = SeedOptions())
567 return generateWatershedSeeds(src.first, src.second, src.third,
568 dest.first, dest.second,
699 template <
class SrcIterator,
class SrcAccessor,
700 class DestIterator,
class DestAccessor,
704 DestIterator upperleftd, DestAccessor da,
705 Neighborhood neighborhood)
707 SImage orientationImage(lowerrights - upperlefts);
709 prepareWatersheds(upperlefts, lowerrights, sa,
710 orientationImage.upperLeft(), orientationImage.accessor(), neighborhood);
711 return watershedLabeling(orientationImage.upperLeft(), orientationImage.lowerRight(), orientationImage.accessor(),
712 upperleftd, da, neighborhood);
715 template <
class SrcIterator,
class SrcAccessor,
716 class DestIterator,
class DestAccessor>
719 DestIterator upperleftd, DestAccessor da)
724 template <
class SrcIterator,
class SrcAccessor,
725 class DestIterator,
class DestAccessor,
729 pair<DestIterator, DestAccessor> dest, Neighborhood neighborhood)
732 dest.first, dest.second, neighborhood);
735 template <
class SrcIterator,
class SrcAccessor,
736 class DestIterator,
class DestAccessor>
739 pair<DestIterator, DestAccessor> dest)
742 dest.first, dest.second);
745 template <
class T1,
class S1,
750 MultiArrayView<2, T2, S2> dest, Neighborhood neighborhood)
753 destImage(dest), neighborhood);
756 template <
class T1,
class S1,
760 MultiArrayView<2, T2, S2> dest)
762 vigra_precondition(src.shape() == dest.shape(),
763 "watershedsUnionFind(): shape mismatch between input and output.");
777 enum Method { RegionGrowing, UnionFind };
779 double max_cost, bias;
782 unsigned int biased_label, bucket_count;
796 terminate(CompleteGrow),
797 method(RegionGrowing),
812 terminate =
SRGType(CompleteGrow | (terminate & StopAtThreshold));
824 terminate =
SRGType(KeepContours | (terminate & StopAtThreshold));
846 terminate =
SRGType(terminate | StopAtThreshold);
847 max_cost = threshold;
864 this->bucket_count = bucket_count;
865 method = RegionGrowing;
896 biased_label = label;
911 this->method = method;
924 method = RegionGrowing;
944 template <
class CostType,
class LabelType>
945 class WatershedStatistics
949 typedef SeedRgDirectValueFunctor<CostType> value_type;
950 typedef value_type & reference;
951 typedef value_type
const & const_reference;
953 typedef CostType first_argument_type;
954 typedef LabelType second_argument_type;
955 typedef LabelType argument_type;
957 WatershedStatistics()
960 void resize(
unsigned int)
968 template <
class T1,
class T2>
969 void operator()(first_argument_type
const &, second_argument_type
const &)
974 LabelType maxRegionLabel()
const
975 {
return size() - 1; }
979 LabelType size()
const
980 {
return NumericTraits<LabelType>::max(); }
984 const_reference operator[](argument_type)
const
989 reference operator[](argument_type)
995 template <
class Value>
996 class SeedRgBiasedValueFunctor
1003 typedef Value argument_type;
1008 typedef Value result_type;
1012 typedef Value cost_type;
1014 SeedRgBiasedValueFunctor(
double b = 1.0)
1020 void operator()(argument_type
const &)
const {}
1024 cost_type cost(argument_type
const & v)
const
1026 return cost_type(bias*v);
1030 template <
class CostType,
class LabelType>
1031 class BiasedWatershedStatistics
1035 typedef SeedRgBiasedValueFunctor<CostType> value_type;
1036 typedef value_type & reference;
1037 typedef value_type
const & const_reference;
1039 typedef CostType first_argument_type;
1040 typedef LabelType second_argument_type;
1041 typedef LabelType argument_type;
1043 BiasedWatershedStatistics(LabelType biasedLabel,
double bias)
1044 : biased_label(biasedLabel),
1048 void resize(
unsigned int)
1056 template <
class T1,
class T2>
1057 void operator()(first_argument_type
const &, second_argument_type
const &)
1062 LabelType maxRegionLabel()
const
1063 {
return size() - 1; }
1067 LabelType size()
const
1068 {
return NumericTraits<LabelType>::max(); }
1072 const_reference operator[](argument_type label)
const
1074 return (label == biased_label)
1081 reference operator[](argument_type label)
1083 return (label == biased_label)
1088 LabelType biased_label;
1089 value_type stats, biased_stats;
1353 template <
class SrcIterator,
class SrcAccessor,
1354 class DestIterator,
class DestAccessor,
1358 DestIterator upperleftd, DestAccessor da,
1359 Neighborhood neighborhood,
1360 WatershedOptions
const & options = WatershedOptions())
1362 typedef typename SrcAccessor::value_type ValueType;
1363 typedef typename DestAccessor::value_type LabelType;
1365 unsigned int max_region_label = 0;
1367 if(options.seed_options.mini != SeedOptions::Unspecified)
1371 generateWatershedSeeds(srcIterRange(upperlefts, lowerrights, sa),
1372 destIter(upperleftd, da),
1373 neighborhood, options.seed_options);
1376 if(options.biased_label != 0)
1379 detail::BiasedWatershedStatistics<ValueType, LabelType>
1380 regionstats(options.biased_label, options.bias);
1383 if(options.bucket_count == 0)
1387 srcIter(upperleftd, da),
1388 destIter(upperleftd, da),
1389 regionstats, options.terminate, neighborhood, options.max_cost);
1394 fastSeededRegionGrowing(srcIterRange(upperlefts, lowerrights, sa),
1395 destIter(upperleftd, da),
1396 regionstats, options.terminate,
1397 neighborhood, options.max_cost, options.bucket_count);
1403 detail::WatershedStatistics<ValueType, LabelType> regionstats;
1406 if(options.bucket_count == 0)
1410 srcIter(upperleftd, da),
1411 destIter(upperleftd, da),
1412 regionstats, options.terminate, neighborhood, options.max_cost);
1417 fastSeededRegionGrowing(srcIterRange(upperlefts, lowerrights, sa),
1418 destIter(upperleftd, da),
1419 regionstats, options.terminate,
1420 neighborhood, options.max_cost, options.bucket_count);
1424 return max_region_label;
1427 template <
class SrcIterator,
class SrcAccessor,
1428 class DestIterator,
class DestAccessor>
1431 DestIterator upperleftd, DestAccessor da,
1432 WatershedOptions
const & options = WatershedOptions())
1438 template <
class SrcIterator,
class SrcAccessor,
1439 class DestIterator,
class DestAccessor,
1443 pair<DestIterator, DestAccessor> dest,
1444 Neighborhood neighborhood,
1445 WatershedOptions
const & options = WatershedOptions())
1448 dest.first, dest.second,
1449 neighborhood, options);
1452 template <
class SrcIterator,
class SrcAccessor,
1453 class DestIterator,
class DestAccessor>
1456 pair<DestIterator, DestAccessor> dest,
1457 WatershedOptions
const & options = WatershedOptions())
1460 dest.first, dest.second,
1464 template <
class T1,
class S1,
1469 MultiArrayView<2, T2, S2> dest,
1470 Neighborhood neighborhood,
1471 WatershedOptions
const & options = WatershedOptions())
1473 vigra_precondition(src.shape() == dest.shape(),
1474 "watershedsRegionGrowing(): shape mismatch between input and output.");
1477 neighborhood, options);
1480 template <
class T1,
class S1,
1484 MultiArrayView<2, T2, S2> dest,
1485 WatershedOptions
const & options = WatershedOptions())
1487 vigra_precondition(src.shape() == dest.shape(),
1488 "watershedsRegionGrowing(): shape mismatch between input and output.");
1498 #endif // VIGRA_WATERSHEDS_HXX
SeedOptions & threshold(double threshold)
Definition: watersheds.hxx:395
WatershedOptions & completeGrow()
Perform complete grow.
Definition: watersheds.hxx:810
SRGType
Definition: seededregiongrowing.hxx:176
Definition: pixelneighborhood.hxx:437
SeedOptions & minima()
Definition: watersheds.hxx:350
unsigned int watershedsUnionFind(...)
Region segmentation by means of the union-find watershed algorithm.
WatershedOptions()
Create options object with default settings.
Definition: watersheds.hxx:793
WatershedOptions & regionGrowing()
Use region-growing watershed.
Definition: watersheds.hxx:922
WatershedOptions & unionFind()
Use union-find watershed.
Definition: watersheds.hxx:935
SeedOptions & levelSets(double threshold)
Definition: watersheds.hxx:382
void localMinima(...)
Find local minima in an image or multi-dimensional array.
AtImageBorder
Encode whether a point is near the image border.
Definition: pixelneighborhood.hxx:68
AtImageBorder isAtImageBorder(int x, int y, int width, int height)
Find out whether a point is at the image border.
Definition: pixelneighborhood.hxx:111
WatershedOptions & useMethod(Method method)
Specify the algorithm to be used.
Definition: watersheds.hxx:909
WatershedOptions & seedOptions(SeedOptions const &s)
Specify seed options.
Definition: watersheds.hxx:878
unsigned int labelImageWithBackground(...)
Find the connected components of a segmented image, excluding the background from labeling...
BasicImage< UInt8 > BImage
Definition: stdimage.hxx:62
WatershedOptions & turboAlgorithm(unsigned int bucket_count=256)
Use a simpler, but faster region growing algorithm.
Definition: watersheds.hxx:862
WatershedOptions & keepContours()
Keep one-pixel wide contour between regions.
Definition: watersheds.hxx:822
BasicImage< Int16 > SImage
Definition: stdimage.hxx:89
Options object for watershed algorithms.
Definition: watersheds.hxx:774
SeedOptions()
Construct default options object.
Definition: watersheds.hxx:341
WatershedOptions & srgType(SRGType type)
Set SRGType explicitly.
Definition: watersheds.hxx:832
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
void seededRegionGrowing(...)
Region Segmentation by means of Seeded Region Growing.
WatershedOptions & biasLabel(unsigned int label, double factor)
Bias the cost of the specified region by the given factor.
Definition: watersheds.hxx:894
WatershedOptions & stopAtThreshold(double threshold)
Stop region growing when the boundaryness exceeds the threshold.
Definition: watersheds.hxx:844
SeedOptions & levelSets()
Definition: watersheds.hxx:371
FourNeighborhood::NeighborCode FourNeighborCode
Definition: pixelneighborhood.hxx:379
Options object for generateWatershedSeeds().
Definition: watersheds.hxx:329
unsigned int watershedsRegionGrowing(...)
Region segmentation by means of a flooding-based watershed algorithm.
Definition: pixelneighborhood.hxx:70
EightNeighborhood::NeighborCode EightNeighborCode
Definition: pixelneighborhood.hxx:687
SeedOptions & extendedMinima()
Definition: watersheds.hxx:360