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

seededregiongrowing.hxx
1 /************************************************************************/
2 /* */
3 /* Copyright 1998-2010 by Ullrich Koethe, Hans Meine */
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_SEEDEDREGIONGROWING_HXX
37 #define VIGRA_SEEDEDREGIONGROWING_HXX
38 
39 #include <vector>
40 #include <stack>
41 #include <queue>
42 #include "utilities.hxx"
43 #include "stdimage.hxx"
44 #include "stdimagefunctions.hxx"
45 #include "pixelneighborhood.hxx"
46 
47 namespace vigra {
48 
49 namespace detail {
50 
51 template <class COST>
52 class SeedRgPixel
53 {
54 public:
55  Point2D location_, nearest_;
56  COST cost_;
57  int count_;
58  int label_;
59  int dist_;
60 
61  SeedRgPixel()
62  : location_(0,0), nearest_(0,0), cost_(0), count_(0), label_(0)
63  {}
64 
65  SeedRgPixel(Point2D const & location, Point2D const & nearest,
66  COST const & cost, int const & count, int const & label)
67  : location_(location), nearest_(nearest),
68  cost_(cost), count_(count), label_(label)
69  {
70  int dx = location_.x - nearest_.x;
71  int dy = location_.y - nearest_.y;
72  dist_ = dx * dx + dy * dy;
73  }
74 
75  void set(Point2D const & location, Point2D const & nearest,
76  COST const & cost, int const & count, int const & label)
77  {
78  location_ = location;
79  nearest_ = nearest;
80  cost_ = cost;
81  count_ = count;
82  label_ = label;
83 
84  int dx = location_.x - nearest_.x;
85  int dy = location_.y - nearest_.y;
86  dist_ = dx * dx + dy * dy;
87  }
88 
89  struct Compare
90  {
91  // must implement > since priority_queue looks for largest element
92  bool operator()(SeedRgPixel const & l,
93  SeedRgPixel const & r) const
94  {
95  if(r.cost_ == l.cost_)
96  {
97  if(r.dist_ == l.dist_) return r.count_ < l.count_;
98 
99  return r.dist_ < l.dist_;
100  }
101 
102  return r.cost_ < l.cost_;
103  }
104  bool operator()(SeedRgPixel const * l,
105  SeedRgPixel const * r) const
106  {
107  if(r->cost_ == l->cost_)
108  {
109  if(r->dist_ == l->dist_) return r->count_ < l->count_;
110 
111  return r->dist_ < l->dist_;
112  }
113 
114  return r->cost_ < l->cost_;
115  }
116  };
117 
118  struct Allocator
119  {
120  ~Allocator()
121  {
122  while(!freelist_.empty())
123  {
124  delete freelist_.top();
125  freelist_.pop();
126  }
127  }
128 
129  SeedRgPixel *
130  create(Point2D const & location, Point2D const & nearest,
131  COST const & cost, int const & count, int const & label)
132  {
133  if(!freelist_.empty())
134  {
135  SeedRgPixel * res = freelist_.top();
136  freelist_.pop();
137  res->set(location, nearest, cost, count, label);
138  return res;
139  }
140 
141  return new SeedRgPixel(location, nearest, cost, count, label);
142  }
143 
144  void dismiss(SeedRgPixel * p)
145  {
146  freelist_.push(p);
147  }
148 
149  std::stack<SeedRgPixel<COST> *> freelist_;
150  };
151 };
152 
153 struct UnlabelWatersheds
154 {
155  int operator()(int label) const
156  {
157  return label < 0 ? 0 : label;
158  }
159 };
160 
161 } // namespace detail
162 
163 enum SRGType { CompleteGrow = 0, KeepContours = 1, StopAtThreshold = 2, SRGWatershedLabel = -1 };
164 
165 /** \addtogroup SeededRegionGrowing Region Segmentation Algorithms
166  Region growing, watersheds, and voronoi tesselation
167 */
168 //@{
169 
170 /********************************************************/
171 /* */
172 /* seededRegionGrowing */
173 /* */
174 /********************************************************/
175 
176 /** \brief Region Segmentation by means of Seeded Region Growing.
177 
178  This algorithm implements seeded region growing as described in
179 
180  R. Adams, L. Bischof: "<em> Seeded Region Growing</em>", IEEE Trans. on Pattern
181  Analysis and Maschine Intelligence, vol 16, no 6, 1994, and
182 
183  Ullrich K&ouml;the:
184  <em><a href="http://hci.iwr.uni-heidelberg.de/people/ukoethe/papers/index.php#cite_primary_segmentation">Primary Image Segmentation</a></em>,
185  in: G. Sagerer, S.
186  Posch, F. Kummert (eds.): Mustererkennung 1995, Proc. 17. DAGM-Symposium,
187  Springer 1995
188 
189  The seed image is a partly segmented image which contains uniquely
190  labeled regions (the seeds) and unlabeled pixels (the candidates, label 0).
191  Seed regions can be as large as you wish and as small as one pixel. If
192  there are no candidates, the algorithm will simply copy the seed image
193  into the output image. Otherwise it will aggregate the candidates into
194  the existing regions so that a cost function is minimized.
195  Candidates are taken from the neighborhood of the already assigned pixels,
196  where the type of neighborhood is determined by parameter <tt>neighborhood</tt>
197  which can take the values <tt>FourNeighborCode()</tt> (the default)
198  or <tt>EightNeighborCode()</tt>. The algorithm basically works as follows
199  (illustrated for 4-neighborhood, but 8-neighborhood works in the same way):
200 
201  <ol>
202 
203  <li> Find all candidate pixels that are 4-adjacent to a seed region.
204  Calculate the cost for aggregating each candidate into its adajacent region
205  and put the candidates into a priority queue.
206 
207  <li> While( priority queue is not empty and termination criterion is not fulfilled)
208 
209  <ol>
210 
211  <li> Take the candidate with least cost from the queue. If it has not
212  already been merged, merge it with it's adjacent region.
213 
214  <li> Put all candidates that are 4-adjacent to the pixel just processed
215  into the priority queue.
216 
217  </ol>
218 
219  </ol>
220 
221  <tt>SRGType</tt> can take the following values:
222 
223  <DL>
224  <DT><tt>CompleteGrow</tt> <DD> produce a complete tesselation of the volume (default).
225  <DT><tt>KeepContours</tt> <DD> keep a 1-voxel wide unlabeled contour between all regions.
226  <DT><tt>StopAtThreshold</tt> <DD> stop when the boundary indicator values exceed the
227  threshold given by parameter <tt>max_cost</tt>.
228  <DT><tt>KeepContours | StopAtThreshold</tt> <DD> keep 1-voxel wide contour and stop at given <tt>max_cost</tt>.
229  </DL>
230 
231  The cost is determined jointly by the source image and the
232  region statistics functor. The source image contains feature values for each
233  pixel which will be used by the region statistics functor to calculate and
234  update statistics for each region and to calculate the cost for each
235  candidate. The <TT>RegionStatisticsArray</TT> must be compatible to the
236  \ref ArrayOfRegionStatistics functor and contains an <em> array</em> of
237  statistics objects for each region. The indices must correspond to the
238  labels of the seed regions. The statistics for the initial regions must have
239  been calculated prior to calling <TT>seededRegionGrowing()</TT> (for example by
240  means of \ref inspectTwoImagesIf()).
241 
242  For each candidate
243  <TT>x</TT> that is adjacent to region <TT>i</TT>, the algorithm will call
244  <TT>stats[i].cost(as(x))</TT> to get the cost (where <TT>x</TT> is a <TT>SrcImageIterator</TT>
245  and <TT>as</TT> is
246  the SrcAccessor). When a candidate has been merged with a region, the
247  statistics are updated by calling <TT>stats[i].operator()(as(x))</TT>. Since
248  the <TT>RegionStatisticsArray</TT> is passed by reference, this will overwrite
249  the original statistics.
250 
251  If a candidate could be merged into more than one regions with identical
252  cost, the algorithm will favour the nearest region. If <tt>StopAtThreshold</tt> is active,
253  and the cost of the current candidate at any point in the algorithm exceeds the optional
254  <tt>max_cost</tt> value (which defaults to <tt>NumericTraits<double>::max()</tt>),
255  region growing is aborted, and all voxels not yet assigned to a region remain unlabeled.
256 
257  In some cases, the cost only depends on the feature value of the current
258  pixel. Then the update operation will simply be a no-op, and the <TT>cost()</TT>
259  function returns its argument. This behavior is implemented by the
260  \ref SeedRgDirectValueFunctor. With <tt>SRGType == KeepContours</tt>,
261  this is equivalent to the watershed algorithm.
262 
263  <b> Declarations:</b>
264 
265  pass arguments explicitly:
266  \code
267  namespace vigra {
268  template <class SrcImageIterator, class SrcAccessor,
269  class SeedImageIterator, class SeedAccessor,
270  class DestImageIterator, class DestAccessor,
271  class RegionStatisticsArray, class Neighborhood>
272  void
273  seededRegionGrowing(SrcImageIterator srcul, SrcImageIterator srclr, SrcAccessor as,
274  SeedImageIterator seedsul, SeedAccessor aseeds,
275  DestImageIterator destul, DestAccessor ad,
276  RegionStatisticsArray & stats,
277  SRGType srgType = CompleteGrow,
278  Neighborhood neighborhood = FourNeighborCode(),
279  double max_cost = NumericTraits<double>::max());
280  }
281  \endcode
282 
283  use argument objects in conjunction with \ref ArgumentObjectFactories :
284  \code
285  namespace vigra {
286  template <class SrcImageIterator, class SrcAccessor,
287  class SeedImageIterator, class SeedAccessor,
288  class DestImageIterator, class DestAccessor,
289  class RegionStatisticsArray, class Neighborhood>
290  void
291  seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
292  pair<SeedImageIterator, SeedAccessor> seeds,
293  pair<DestImageIterator, DestAccessor> dest,
294  RegionStatisticsArray & stats,
295  SRGType srgType = CompleteGrow,
296  Neighborhood neighborhood = FourNeighborCode(),
297  double max_cost = NumericTraits<double>::max());
298  }
299  \endcode
300 
301  <b> Usage:</b>
302 
303  <b>\#include</b> <<a href="seededregiongrowing_8hxx-source.html">vigra/seededregiongrowing.hxx</a>><br>
304  Namespace: vigra
305 
306  Example: implementation of the voronoi tesselation
307 
308  \code
309  vigra::BImage points(w,h);
310  vigra::FImage dist(x,y);
311 
312  // empty edge image
313  points = 0;
314  dist = 0;
315 
316  int max_region_label = 100;
317 
318  // throw in some random points:
319  for(int i = 1; i <= max_region_label; ++i)
320  points(w * rand() / RAND_MAX , h * rand() / RAND_MAX) = i;
321 
322  // calculate Euclidean distance transform
323  vigra::distanceTransform(srcImageRange(points), destImage(dist), 2);
324 
325  // init statistics functor
326  vigra::ArrayOfRegionStatistics<vigra::SeedRgDirectValueFunctor<float> >
327  stats(max_region_label);
328 
329  // find voronoi region of each point
330  vigra:: seededRegionGrowing(srcImageRange(dist), srcImage(points),
331  destImage(points), stats);
332  \endcode
333 
334  <b> Required Interface:</b>
335 
336  \code
337  SrcImageIterator src_upperleft, src_lowerright;
338  SeedImageIterator seed_upperleft;
339  DestImageIterator dest_upperleft;
340 
341  SrcAccessor src_accessor;
342  SeedAccessor seed_accessor;
343  DestAccessor dest_accessor;
344 
345  RegionStatisticsArray stats;
346 
347  // calculate costs
348  RegionStatisticsArray::value_type::cost_type cost =
349  stats[seed_accessor(seed_upperleft)].cost(src_accessor(src_upperleft));
350 
351  // compare costs
352  cost < cost;
353 
354  // update statistics
355  stats[seed_accessor(seed_upperleft)](src_accessor(src_upperleft));
356 
357  // set result
358  dest_accessor.set(seed_accessor(seed_upperleft), dest_upperleft);
359  \endcode
360 
361  Further requirements are determined by the <TT>RegionStatisticsArray</TT>.
362 */
364 
365 template <class SrcImageIterator, class SrcAccessor,
366  class SeedImageIterator, class SeedAccessor,
367  class DestImageIterator, class DestAccessor,
368  class RegionStatisticsArray, class Neighborhood>
369 void seededRegionGrowing(SrcImageIterator srcul,
370  SrcImageIterator srclr, SrcAccessor as,
371  SeedImageIterator seedsul, SeedAccessor aseeds,
372  DestImageIterator destul, DestAccessor ad,
373  RegionStatisticsArray & stats,
374  SRGType srgType,
375  Neighborhood,
376  double max_cost)
377 {
378  int w = srclr.x - srcul.x;
379  int h = srclr.y - srcul.y;
380  int count = 0;
381 
382  SrcImageIterator isy = srcul, isx = srcul; // iterators for the src image
383 
384  typedef typename RegionStatisticsArray::value_type RegionStatistics;
385  typedef typename RegionStatistics::cost_type CostType;
386  typedef detail::SeedRgPixel<CostType> Pixel;
387 
388  typename Pixel::Allocator allocator;
389 
390  typedef std::priority_queue<Pixel *, std::vector<Pixel *>,
391  typename Pixel::Compare> SeedRgPixelHeap;
392 
393  // copy seed image in an image with border
394  IImage regions(w+2, h+2);
395  IImage::Iterator ir = regions.upperLeft() + Diff2D(1,1);
396  IImage::Iterator iry, irx;
397 
398  initImageBorder(destImageRange(regions), 1, SRGWatershedLabel);
399  copyImage(seedsul, seedsul+Diff2D(w,h), aseeds, ir, regions.accessor());
400 
401  // allocate and init memory for the results
402 
403  SeedRgPixelHeap pheap;
404  int cneighbor;
405 
406  typedef typename Neighborhood::Direction Direction;
407  int directionCount = Neighborhood::DirectionCount;
408 
409  Point2D pos(0,0);
410  for(isy=srcul, iry=ir, pos.y=0; pos.y<h;
411  ++pos.y, ++isy.y, ++iry.y)
412  {
413  for(isx=isy, irx=iry, pos.x=0; pos.x<w;
414  ++pos.x, ++isx.x, ++irx.x)
415  {
416  if(*irx == 0)
417  {
418  // find candidate pixels for growing and fill heap
419  for(int i=0; i<directionCount; i++)
420  {
421  // cneighbor = irx[dist[i]];
422  cneighbor = irx[Neighborhood::diff((Direction)i)];
423  if(cneighbor > 0)
424  {
425  CostType cost = stats[cneighbor].cost(as(isx));
426 
427  Pixel * pixel =
428  allocator.create(pos, pos+Neighborhood::diff((Direction)i), cost, count++, cneighbor);
429  pheap.push(pixel);
430  }
431  }
432  }
433  }
434  }
435 
436  // perform region growing
437  while(pheap.size() != 0)
438  {
439  Pixel * pixel = pheap.top();
440  pheap.pop();
441 
442  Point2D pos = pixel->location_;
443  Point2D nearest = pixel->nearest_;
444  int lab = pixel->label_;
445  CostType cost = pixel->cost_;
446 
447  allocator.dismiss(pixel);
448 
449  if((srgType & StopAtThreshold) != 0 && cost > max_cost)
450  break;
451 
452  irx = ir + pos;
453  isx = srcul + pos;
454 
455  if(*irx) // already labelled region / watershed?
456  continue;
457 
458  if((srgType & KeepContours) != 0)
459  {
460  for(int i=0; i<directionCount; i++)
461  {
462  cneighbor = irx[Neighborhood::diff((Direction)i)];
463  if((cneighbor>0) && (cneighbor != lab))
464  {
465  lab = SRGWatershedLabel;
466  break;
467  }
468  }
469  }
470 
471  *irx = lab;
472 
473  if((srgType & KeepContours) == 0 || lab > 0)
474  {
475  // update statistics
476  stats[*irx](as(isx));
477 
478  // search neighborhood
479  // second pass: find new candidate pixels
480  for(int i=0; i<directionCount; i++)
481  {
482  if(irx[Neighborhood::diff((Direction)i)] == 0)
483  {
484  CostType cost = stats[lab].cost(as(isx, Neighborhood::diff((Direction)i)));
485 
486  Pixel * new_pixel =
487  allocator.create(pos+Neighborhood::diff((Direction)i), nearest, cost, count++, lab);
488  pheap.push(new_pixel);
489  }
490  }
491  }
492  }
493 
494  // free temporary memory
495  while(pheap.size() != 0)
496  {
497  allocator.dismiss(pheap.top());
498  pheap.pop();
499  }
500 
501  // write result
502  transformImage(ir, ir+Point2D(w,h), regions.accessor(), destul, ad,
503  detail::UnlabelWatersheds());
504 }
505 
506 template <class SrcImageIterator, class SrcAccessor,
507  class SeedImageIterator, class SeedAccessor,
508  class DestImageIterator, class DestAccessor,
509  class RegionStatisticsArray, class Neighborhood>
510 inline void
511 seededRegionGrowing(SrcImageIterator srcul,
512  SrcImageIterator srclr, SrcAccessor as,
513  SeedImageIterator seedsul, SeedAccessor aseeds,
514  DestImageIterator destul, DestAccessor ad,
515  RegionStatisticsArray & stats,
516  SRGType srgType,
517  Neighborhood n)
518 {
519  seededRegionGrowing(srcul, srclr, as,
520  seedsul, aseeds,
521  destul, ad,
522  stats, srgType, n, NumericTraits<double>::max());
523 }
524 
525 
526 
527 template <class SrcImageIterator, class SrcAccessor,
528  class SeedImageIterator, class SeedAccessor,
529  class DestImageIterator, class DestAccessor,
530  class RegionStatisticsArray>
531 inline void
532 seededRegionGrowing(SrcImageIterator srcul,
533  SrcImageIterator srclr, SrcAccessor as,
534  SeedImageIterator seedsul, SeedAccessor aseeds,
535  DestImageIterator destul, DestAccessor ad,
536  RegionStatisticsArray & stats,
537  SRGType srgType)
538 {
539  seededRegionGrowing(srcul, srclr, as,
540  seedsul, aseeds,
541  destul, ad,
542  stats, srgType, FourNeighborCode());
543 }
544 
545 template <class SrcImageIterator, class SrcAccessor,
546  class SeedImageIterator, class SeedAccessor,
547  class DestImageIterator, class DestAccessor,
548  class RegionStatisticsArray>
549 inline void
550 seededRegionGrowing(SrcImageIterator srcul,
551  SrcImageIterator srclr, SrcAccessor as,
552  SeedImageIterator seedsul, SeedAccessor aseeds,
553  DestImageIterator destul, DestAccessor ad,
554  RegionStatisticsArray & stats)
555 {
556  seededRegionGrowing(srcul, srclr, as,
557  seedsul, aseeds,
558  destul, ad,
559  stats, CompleteGrow);
560 }
561 
562 template <class SrcImageIterator, class SrcAccessor,
563  class SeedImageIterator, class SeedAccessor,
564  class DestImageIterator, class DestAccessor,
565  class RegionStatisticsArray, class Neighborhood>
566 inline void
567 seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> img1,
568  pair<SeedImageIterator, SeedAccessor> img3,
569  pair<DestImageIterator, DestAccessor> img4,
570  RegionStatisticsArray & stats,
571  SRGType srgType,
572  Neighborhood n,
573  double max_cost)
574 {
575  seededRegionGrowing(img1.first, img1.second, img1.third,
576  img3.first, img3.second,
577  img4.first, img4.second,
578  stats, srgType, n, max_cost);
579 }
580 
581 template <class SrcImageIterator, class SrcAccessor,
582  class SeedImageIterator, class SeedAccessor,
583  class DestImageIterator, class DestAccessor,
584  class RegionStatisticsArray, class Neighborhood>
585 inline void
586 seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> img1,
587  pair<SeedImageIterator, SeedAccessor> img3,
588  pair<DestImageIterator, DestAccessor> img4,
589  RegionStatisticsArray & stats,
590  SRGType srgType,
591  Neighborhood n)
592 {
593  seededRegionGrowing(img1.first, img1.second, img1.third,
594  img3.first, img3.second,
595  img4.first, img4.second,
596  stats, srgType, n, NumericTraits<double>::max());
597 }
598 
599 template <class SrcImageIterator, class SrcAccessor,
600  class SeedImageIterator, class SeedAccessor,
601  class DestImageIterator, class DestAccessor,
602  class RegionStatisticsArray>
603 inline void
604 seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> img1,
605  pair<SeedImageIterator, SeedAccessor> img3,
606  pair<DestImageIterator, DestAccessor> img4,
607  RegionStatisticsArray & stats,
608  SRGType srgType)
609 {
610  seededRegionGrowing(img1.first, img1.second, img1.third,
611  img3.first, img3.second,
612  img4.first, img4.second,
613  stats, srgType, FourNeighborCode());
614 }
615 
616 template <class SrcImageIterator, class SrcAccessor,
617  class SeedImageIterator, class SeedAccessor,
618  class DestImageIterator, class DestAccessor,
619  class RegionStatisticsArray>
620 inline void
621 seededRegionGrowing(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> img1,
622  pair<SeedImageIterator, SeedAccessor> img3,
623  pair<DestImageIterator, DestAccessor> img4,
624  RegionStatisticsArray & stats)
625 {
626  seededRegionGrowing(img1.first, img1.second, img1.third,
627  img3.first, img3.second,
628  img4.first, img4.second,
629  stats, CompleteGrow);
630 }
631 
632 /********************************************************/
633 /* */
634 /* SeedRgDirectValueFunctor */
635 /* */
636 /********************************************************/
637 
638 /** \brief Statistics functor to be used for seeded region growing.
639 
640  This functor can be used if the cost of a candidate during
641  \ref seededRegionGrowing() is equal to the feature value of that
642  candidate and does not depend on properties of the region it is going to
643  be merged with.
644 
645  <b>\#include</b> <<a href="seededregiongrowing_8hxx-source.html">vigra/seededregiongrowing.hxx</a>><br>
646  Namespace: vigra
647 
648 
649  <b> Required Interface:</b>
650 
651  no requirements
652 */
653 template <class Value>
655 {
656  public:
657  /** the functor's argument type
658  */
659  typedef Value argument_type;
660 
661  /** the functor's result type (unused, only necessary for
662  use of SeedRgDirectValueFunctor in \ref vigra::ArrayOfRegionStatistics
663  */
664  typedef Value result_type;
665 
666  /** \deprecated use argument_type
667  */
668  typedef Value value_type;
669 
670  /** the return type of the cost() function
671  */
672  typedef Value cost_type;
673 
674  /** Do nothing (since we need not update region statistics).
675  */
676  void operator()(argument_type const &) const {}
677 
678  /** Return argument (since cost is identical to feature value)
679  */
680  cost_type const & cost(argument_type const & v) const
681  {
682  return v;
683  }
684 };
685 
686 //@}
687 
688 } // namespace vigra
689 
690 #endif // VIGRA_SEEDEDREGIONGROWING_HXX
691 

© 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.7.1 (Thu Jun 14 2012)