vigra - vigra/seededregiongrowing3d.hxx Source File

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

seededregiongrowing3d.hxx |

1 /************************************************************************/
2 /* */
3 /* Copyright 2003-2007 by Kasim Terzic, Christian-Dennis Rahn */
4 /* and Ullrich Koethe */
5 /* */
6 /* This file is part of the VIGRA computer vision library. */
7 /* The VIGRA Website is */
8 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
9 /* Please direct questions, bug reports, and contributions to */
10 /* ullrich.koethe@iwr.uni-heidelberg.de or */
11 /* vigra@informatik.uni-hamburg.de */
12 /* */
13 /* Permission is hereby granted, free of charge, to any person */
14 /* obtaining a copy of this software and associated documentation */
15 /* files (the "Software"), to deal in the Software without */
16 /* restriction, including without limitation the rights to use, */
17 /* copy, modify, merge, publish, distribute, sublicense, and/or */
18 /* sell copies of the Software, and to permit persons to whom the */
19 /* Software is furnished to do so, subject to the following */
20 /* conditions: */
21 /* */
22 /* The above copyright notice and this permission notice shall be */
23 /* included in all copies or substantial portions of the */
24 /* Software. */
25 /* */
26 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
27 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
28 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
29 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
30 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
31 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
32 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
33 /* OTHER DEALINGS IN THE SOFTWARE. */
34 /* */
35 /************************************************************************/
36
37 #ifndef VIGRA_SEEDEDREGIONGROWING_3D_HXX
38 #define VIGRA_SEEDEDREGIONGROWING_3D_HXX
39
40 #include <vector>
41 #include <stack>
42 #include <queue>
43 #include "utilities.hxx"
44 #include "stdimage.hxx"
45 #include "stdimagefunctions.hxx"
46 #include "seededregiongrowing.hxx"
47 #include "multi_shape.hxx"
48 #include "multi_pointoperators.hxx"
49 #include "voxelneighborhood.hxx"
50
51 namespace vigra {
52
53 namespace detail {
54
55 template <class COST, class Diff_type>
56 class SeedRgVoxel
57 {
58 public:
59 Diff_type location_, nearest_;
60 COST cost_;
61 int count_;
62 int label_;
63 int dist_;
64
65 SeedRgVoxel()
66 //: location_(0,0,0), nearest_(0,0,0), cost_(0), count_(0), label_(0)
67 {
68 location_ = Diff_type(0,0,0);
69 nearest_ = Diff_type(0,0,0);
70 cost_ = 0;
71 count_ = 0;
72 label_ = 0;
73 }
74
75 SeedRgVoxel(Diff_type const & location, Diff_type const & nearest,
76 COST const & cost, int const & count, int const & label)
77 : location_(location), nearest_(nearest),
78 cost_(cost), count_(count), label_(label)
79 {
80 int dx = location_[0] - nearest_[0];
81 int dy = location_[1] - nearest_[1];
82 int dz = location_[2] - nearest_[2];
83 dist_ = dx * dx + dy * dy + dz * dz;
84 }
85
86 void set(Diff_type const & location, Diff_type const & nearest,
87 COST const & cost, int const & count, int const & label)
88 {
89 location_ = location;
90 nearest_ = nearest;
91 cost_ = cost;
92 count_ = count;
93 label_ = label;
94
95 int dx = location_[0] - nearest_[0];
96 int dy = location_[1] - nearest_[1];
97 int dz = location_[2] - nearest_[2];
98 dist_ = dx * dx + dy * dy + dz * dz;
99 }
100
101 struct Compare
102 {
103 // must implement > since priority_queue looks for largest element
104 bool operator()(SeedRgVoxel const & l,
105 SeedRgVoxel 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 bool operator()(SeedRgVoxel const * l,
117 SeedRgVoxel const * r) const
118 {
119 if(r->cost_ == l->cost_)
120 {
121 if(r->dist_ == l->dist_) return r->count_ < l->count_;
122
123 return r->dist_ < l->dist_;
124 }
125
126 return r->cost_ < l->cost_;
127 }
128 };
129
130 struct Allocator
131 {
132 ~Allocator()
133 {
134 while(!freelist_.empty())
135 {
136 delete freelist_.top();
137 freelist_.pop();
138 }
139 }
140
141 SeedRgVoxel * create(Diff_type const & location, Diff_type const & nearest,
142 COST const & cost, int const & count, int const & label)
143 {
144 if(!freelist_.empty())
145 {
146 SeedRgVoxel * res = freelist_.top();
147 freelist_.pop();
148 res->set(location, nearest, cost, count, label);
149 return res;
150 }
151
152 return new SeedRgVoxel(location, nearest, cost, count, label);
153 }
154
155 void dismiss(SeedRgVoxel * p)
156 {
157 freelist_.push(p);
158 }
159
160 std::stack<SeedRgVoxel<COST,Diff_type> *> freelist_;
161 };
162 };
163
164 } // namespace detail
165
166 /** \addtogroup SeededRegionGrowing
167 */
168 //@{
169
170 /********************************************************/
171 /* */
172 /* seededRegionGrowing3D */
173 /* */
174 /********************************************************/
175
176 /** \brief Three-dimensional Region Segmentation by means of Seeded Region Growing.
177
178 This algorithm implements seeded region growing as described in
179
180 The seed image is a partly segmented multi-dimensional array which contains uniquely
181 labeled regions (the seeds) and unlabeled voxels (the candidates, label 0).
182 Seed regions can be as large as you wish and as small as one voxel. If
183 there are no candidates, the algorithm will simply copy the seed array
184 into the output array. Otherwise it will aggregate the candidates into
185 the existing regions so that a cost function is minimized.
186 Candidates are taken from the neighborhood of the already assigned pixels,
187 where the type of neighborhood is determined by parameter <tt>neighborhood</tt>
188 which can take the values <tt>NeighborCode3DSix()</tt> (the default)
189 or <tt>NeighborCode3DTwentySix()</tt>. The algorithm basically works as follows
190 (illustrated for 6-neighborhood, but 26-neighborhood works in the same way):
191
192 <ol>
193
194 <li> Find all candidate pixels that are 6-adjacent to a seed region.
195 Calculate the cost for aggregating each candidate into its adjacent region
196 and put the candidates into a priority queue.
197
198 <li> While( priority queue is not empty)
199
200 <ol>
201
202 <li> Take the candidate with least cost from the queue. If it has not
203 already been merged, merge it with it's adjacent region.
204
205 <li> Put all candidates that are 4-adjacent to the pixel just processed
206 into the priority queue.
207
208 </ol>
209
210 </ol>
211
212 <tt>SRGType</tt> can take the following values:
213
214 <DL>
215 <DT><tt>CompleteGrow</tt> <DD> produce a complete tesselation of the volume (default).
216 <DT><tt>KeepContours</tt> <DD> keep a 1-voxel wide unlabeled contour between all regions.
217 <DT><tt>StopAtThreshold</tt> <DD> stop when the boundary indicator values exceed the
218 threshold given by parameter <tt>max_cost</tt>.
219 <DT><tt>KeepContours | StopAtThreshold</tt> <DD> keep 1-voxel wide contour and stop at given <tt>max_cost</tt>.
220 </DL>
221
222 The cost is determined jointly by the source array and the
223 region statistics functor. The source array contains feature values for each
224 pixel which will be used by the region statistics functor to calculate and
225 update statistics for each region and to calculate the cost for each
226 candidate. The <TT>RegionStatisticsArray</TT> must be compatible to the
227 \ref ArrayOfRegionStatistics functor and contains an <em> array</em> of
228 statistics objects for each region. The indices must correspond to the
229 labels of the seed regions. The statistics for the initial regions must have
230 been calculated prior to calling <TT>seededRegionGrowing3D()</TT>
231
232 For each candidate
233 <TT>x</TT> that is adjacent to region <TT>i</TT>, the algorithm will call
234 <TT>stats[i].cost(as(x))</TT> to get the cost (where <TT>x</TT> is a <TT>SrcImageIterator</TT>
235 and <TT>as</TT> is
236 the SrcAccessor). When a candidate has been merged with a region, the
237 statistics are updated by calling <TT>stats[i].operator()(as(x))</TT>. Since
238 the <TT>RegionStatisticsArray</TT> is passed by reference, this will overwrite
239 the original statistics.
240
241 If a candidate could be merged into more than one regions with identical
242 cost, the algorithm will favour the nearest region. If <tt>StopAtThreshold</tt> is active,
243 and the cost of the current candidate at any point in the algorithm exceeds the optional
244 <tt>max_cost</tt> value (which defaults to <tt>NumericTraits<double>::max()</tt>),
245 region growing is aborted, and all voxels not yet assigned to a region remain unlabeled.
246
247 In some cases, the cost only depends on the feature value of the current
248 voxel. Then the update operation will simply be a no-op, and the <TT>cost()</TT>
249 function returns its argument. This behavior is implemented by the
250 \ref SeedRgDirectValueFunctor.
251
252 <b> Declarations:</b>
253
254 pass 3D array views:
255 \code
256 namespace vigra {
257 template <class T1, class S1,
258 class TS, class AS,
259 class T2, class S2,
260 class RegionStatisticsArray, class Neighborhood>
261 void
262 seededRegionGrowing3D(MultiArrayView<3, T1, S1> const & src,
263 MultiArrayView<3, TS, AS> const & seeds,
264 MultiArrayView<3, T2, S2> labels,
265 RegionStatisticsArray & stats,
266 SRGType srgType = CompleteGrow,
267 Neighborhood neighborhood = NeighborCode3DSix(),
268 double max_cost = NumericTraits<double>::max());
269 }
270 \endcode
271
272 \deprecatedAPI{seededRegionGrowing3D}
273 pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
274 \code
275 namespace vigra {
276 template <class SrcImageIterator, class Shape, class SrcAccessor,
277 class SeedImageIterator, class SeedAccessor,
278 class DestImageIterator, class DestAccessor,
279 class RegionStatisticsArray, class Neighborhood>
280 void
281 seededRegionGrowing3D(SrcImageIterator srcul, Shape shape, SrcAccessor as,
282 SeedImageIterator seedsul, SeedAccessor aseeds,
283 DestImageIterator destul, DestAccessor ad,
284 RegionStatisticsArray & stats,
285 SRGType srgType = CompleteGrow,
286 Neighborhood neighborhood = NeighborCode3DSix(),
287 double max_cost = NumericTraits<double>::max());
288 }
289 \endcode
290 use argument objects in conjunction with \ref ArgumentObjectFactories :
291 \code
292 namespace vigra {
293 template <class SrcImageIterator, class Shape, class SrcAccessor,
294 class SeedImageIterator, class SeedAccessor,
295 class DestImageIterator, class DestAccessor,
296 class RegionStatisticsArray, class Neighborhood>
297 void
298 seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> src,
299 pair<SeedImageIterator, SeedAccessor> seeds,
300 pair<DestImageIterator, DestAccessor> dest,
301 RegionStatisticsArray & stats,
302 SRGType srgType = CompleteGrow,
303 Neighborhood neighborhood = NeighborCode3DSix(),
304 double max_cost = NumericTraits<double>::max());
305 }
306 \endcode
307 \deprecatedEnd
308
309 <b> Usage:</b>
310
311 <b>\#include</b> <vigra/seededregiongrowing3d.hxx><br>
312 Namespace: vigra
313
314 See \ref seededRegionGrowing() for an example
315 */
316 doxygen_overloaded_function(template <...> void seededRegionGrowing3D)
317
318 template <class SrcImageIterator, class Diff_type, class SrcAccessor,
319 class SeedImageIterator, class SeedAccessor,
320 class DestImageIterator, class DestAccessor,
321 class RegionStatisticsArray, class Neighborhood>
322 void
323 seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, SrcAccessor as,
324 SeedImageIterator seedsul, SeedAccessor aseeds,
325 DestImageIterator destul, DestAccessor ad,
326 RegionStatisticsArray & stats,
327 SRGType srgType,
328 Neighborhood,
329 double max_cost)
330 {
331 //SrcImageIterator srclr = srcul + shape;
332 //int w = srclr.x - srcul.x;
333 int w = shape[0];
334 //int h = srclr.y - srcul.y;
335 int h = shape[1];
336 //int d = srclr.z - srcul.z;
337 int d = shape[2];
338 int count = 0;
339
340 SrcImageIterator isy = srcul, isx = srcul, isz = srcul; // iterators for the src image
341
342 typedef typename RegionStatisticsArray::value_type RegionStatistics;
343 typedef typename PromoteTraits<typename RegionStatistics::cost_type, double>::Promote CostType;
344 typedef detail::SeedRgVoxel<CostType, Diff_type> Voxel;
345
346 typename Voxel::Allocator allocator;
347
348 typedef std::priority_queue< Voxel *,
349 std::vector<Voxel *>,
350 typename Voxel::Compare > SeedRgVoxelHeap;
351 typedef MultiArray<3, int> IVolume;
352 typedef IVolume::traverser Traverser;
353
354 // copy seed image in an image with border
355 Diff_type regionshape = shape + Diff_type(2,2,2);
356 IVolume regions(regionshape);
357 Traverser ir = regions.traverser_begin();
358 ir = ir + Diff_type(1,1,1);
359
360 //IVolume::Iterator iry, irx, irz;
361 Traverser iry, irx, irz;
362
363 //initImageBorder(destImageRange(regions), 1, SRGWatershedLabel);
364 initMultiArrayBorder(destMultiArrayRange(regions), 1, SRGWatershedLabel);
365
366 copyMultiArray(seedsul, Diff_type(w,h,d), aseeds, ir, AccessorTraits<int>::default_accessor());
367
368 // allocate and init memory for the results
369
370 SeedRgVoxelHeap pheap;
371 int cneighbor;
372
373 typedef typename Neighborhood::Direction Direction;
374 int directionCount = Neighborhood::DirectionCount;
375
376 Diff_type pos(0,0,0);
377
378 for(isz=srcul, irz=ir, pos[2]=0; pos[2]<d;
379 pos[2]++, isz.dim2()++, irz.dim2()++)
380 {
381 //std::cerr << "Z = " << pos[2] << std::endl;
382
383 for(isy=isz, iry=irz, pos[1]=0; pos[1]<h;
384 pos[1]++, isy.dim1()++, iry.dim1()++)
385 {
386 //std::cerr << "Y = " << pos[1] << std::endl;
387
388 for(isx=isy, irx=iry, pos[0]=0; pos[0]<w;
389 pos[0]++, isx.dim0()++, irx.dim0()++)
390 {
391 //std::cerr << "X = " << pos[0] << std::endl;
392
393 if(*irx == 0)
394 {
395 // find candidate pixels for growing and fill heap
396 for(int i=0; i<directionCount; i++)
397 {
398 cneighbor = *(irx + Neighborhood::diff((Direction)i));
399 if(cneighbor > 0)
400 {
401 CostType cost = stats[cneighbor].cost(as(isx));
402
403 Voxel * voxel =
404 allocator.create(pos, pos+Neighborhood::diff((Direction)i), cost, count++, cneighbor);
405 pheap.push(voxel);
406 }
407 }
408 }
409 }
410 }
411 }
412
413 // perform region growing
414 while(pheap.size() != 0)
415 {
416 Voxel * voxel = pheap.top();
417 pheap.pop();
418
419 Diff_type pos = voxel->location_;
420 Diff_type nearest = voxel->nearest_;
421 int lab = voxel->label_;
422 CostType cost = voxel->cost_;
423
424 allocator.dismiss(voxel);
425
426 if((srgType & StopAtThreshold) != 0 && cost > max_cost)
427 break;
428
429 irx = ir + pos;
430 isx = srcul + pos;
431
432 if(*irx) // already labelled region / watershed?
433 continue;
434
435 if((srgType & KeepContours) != 0)
436 {
437 for(int i=0; i<directionCount; i++)
438 {
439 cneighbor = * (irx + Neighborhood::diff((Direction)i));
440 if((cneighbor>0) && (cneighbor != lab))
441 {
442 lab = SRGWatershedLabel;
443 break;
444 }
445 }
446 }
447
448 *irx = lab;
449
450 if((srgType & KeepContours) == 0 || lab > 0)
451 {
452 // update statistics
453 stats[*irx](as(isx));
454
455 // search neighborhood
456 // second pass: find new candidate pixels
457 for(int i=0; i<directionCount; i++)
458 {
459 if(*(irx + Neighborhood::diff((Direction)i)) == 0)
460 {
461 CostType cost = stats[lab].cost(as(isx, Neighborhood::diff((Direction)i)));
462
463 Voxel * new_voxel =
464 allocator.create(pos+Neighborhood::diff((Direction)i), nearest, cost, count++, lab);
465 pheap.push(new_voxel);
466 }
467 }
468 }
469 }
470
471 // free temporary memory
472 while(pheap.size() != 0)
473 {
474 allocator.dismiss(pheap.top());
475 pheap.pop();
476 }
477
478 // write result
479 transformMultiArray(ir, Diff_type(w,h,d), AccessorTraits<int>::default_accessor(),
480 destul, ad, detail::UnlabelWatersheds());
481 }
482
483 template <class SrcImageIterator, class Diff_type, class SrcAccessor,
484 class SeedImageIterator, class SeedAccessor,
485 class DestImageIterator, class DestAccessor,
486 class RegionStatisticsArray, class Neighborhood >
487 inline void
488 seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, SrcAccessor as,
489 SeedImageIterator seedsul, SeedAccessor aseeds,
490 DestImageIterator destul, DestAccessor ad,
491 RegionStatisticsArray & stats, SRGType srgType, Neighborhood n)
492 {
493 seededRegionGrowing3D( srcul, shape, as, seedsul, aseeds,
494 destul, ad, stats, srgType, n, NumericTraits<double>::max());
495 }
496
497 template <class SrcImageIterator, class Diff_type, class SrcAccessor,
498 class SeedImageIterator, class SeedAccessor,
499 class DestImageIterator, class DestAccessor,
500 class RegionStatisticsArray >
501 inline void
502 seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, SrcAccessor as,
503 SeedImageIterator seedsul, SeedAccessor aseeds,
504 DestImageIterator destul, DestAccessor ad,
505 RegionStatisticsArray & stats, SRGType srgType)
506 {
507 seededRegionGrowing3D( srcul, shape, as, seedsul, aseeds,
508 destul, ad, stats, srgType, NeighborCode3DSix());
509 }
510
511 template <class SrcImageIterator, class Diff_type, class SrcAccessor,
512 class SeedImageIterator, class SeedAccessor,
513 class DestImageIterator, class DestAccessor,
514 class RegionStatisticsArray >
515 inline void
516 seededRegionGrowing3D(SrcImageIterator srcul, Diff_type shape, SrcAccessor as,
517 SeedImageIterator seedsul, SeedAccessor aseeds,
518 DestImageIterator destul, DestAccessor ad,
519 RegionStatisticsArray & stats)
520 {
521 seededRegionGrowing3D( srcul, shape, as, seedsul, aseeds, destul, ad,
522 stats, CompleteGrow);
523 }
524
525 template <class SrcImageIterator, class Shape, class SrcAccessor,
526 class SeedImageIterator, class SeedAccessor,
527 class DestImageIterator, class DestAccessor,
528 class RegionStatisticsArray, class Neighborhood>
529 inline void
530 seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> img1,
531 pair<SeedImageIterator, SeedAccessor> img3,
532 pair<DestImageIterator, DestAccessor> img4,
533 RegionStatisticsArray & stats,
534 SRGType srgType, Neighborhood n, double max_cost)
535 {
536 seededRegionGrowing3D(img1.first, img1.second, img1.third,
537 img3.first, img3.second,
538 img4.first, img4.second,
539 stats, srgType, n, max_cost);
540 }
541
542 template <class SrcImageIterator, class Shape, class SrcAccessor,
543 class SeedImageIterator, class SeedAccessor,
544 class DestImageIterator, class DestAccessor,
545 class RegionStatisticsArray, class Neighborhood>
546 inline void
547 seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> img1,
548 pair<SeedImageIterator, SeedAccessor> img3,
549 pair<DestImageIterator, DestAccessor> img4,
550 RegionStatisticsArray & stats,
551 SRGType srgType, Neighborhood n)
552 {
553 seededRegionGrowing3D(img1.first, img1.second, img1.third,
554 img3.first, img3.second,
555 img4.first, img4.second,
556 stats, srgType, n, NumericTraits<double>::max());
557 }
558
559 template <class SrcImageIterator, class Shape, class SrcAccessor,
560 class SeedImageIterator, class SeedAccessor,
561 class DestImageIterator, class DestAccessor,
562 class RegionStatisticsArray>
563 inline void
564 seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> img1,
565 pair<SeedImageIterator, SeedAccessor> img3,
566 pair<DestImageIterator, DestAccessor> img4,
567 RegionStatisticsArray & stats, SRGType srgType)
568 {
569 seededRegionGrowing3D(img1.first, img1.second, img1.third,
570 img3.first, img3.second,
571 img4.first, img4.second,
572 stats, srgType, NeighborCode3DSix());
573 }
574
575 template <class SrcImageIterator, class Shape, class SrcAccessor,
576 class SeedImageIterator, class SeedAccessor,
577 class DestImageIterator, class DestAccessor,
578 class RegionStatisticsArray>
579 inline void
580 seededRegionGrowing3D(triple<SrcImageIterator, Shape, SrcAccessor> img1,
581 pair<SeedImageIterator, SeedAccessor> img3,
582 pair<DestImageIterator, DestAccessor> img4,
583 RegionStatisticsArray & stats)
584 {
585 seededRegionGrowing3D(img1.first, img1.second, img1.third,
586 img3.first, img3.second,
587 img4.first, img4.second,
588 stats);
589 }
590
591 template <class T1, class S1,
592 class TS, class AS,
593 class T2, class S2,
594 class RegionStatisticsArray, class Neighborhood>
595 inline void
596 seededRegionGrowing3D(MultiArrayView<3, T1, S1> const & img1,
597 MultiArrayView<3, TS, AS> const & img3,
598 MultiArrayView<3, T2, S2> img4,
599 RegionStatisticsArray & stats,
600 SRGType srgType, Neighborhood n, double max_cost)
601 {
602 vigra_precondition(img1.shape() == img3.shape(),
603 "seededRegionGrowing3D(): shape mismatch between input and output.");
604 seededRegionGrowing3D(srcMultiArrayRange(img1),
605 srcMultiArray(img3),
606 destMultiArray(img4),
607 stats, srgType, n, max_cost);
608 }
609
610 template <class T1, class S1,
611 class TS, class AS,
612 class T2, class S2,
613 class RegionStatisticsArray, class Neighborhood>
614 inline void
615 seededRegionGrowing3D(MultiArrayView<3, T1, S1> const & img1,
616 MultiArrayView<3, TS, AS> const & img3,
617 MultiArrayView<3, T2, S2> img4,
618 RegionStatisticsArray & stats,
619 SRGType srgType, Neighborhood n)
620 {
621 vigra_precondition(img1.shape() == img3.shape(),
622 "seededRegionGrowing3D(): shape mismatch between input and output.");
623 seededRegionGrowing3D(srcMultiArrayRange(img1),
624 srcMultiArray(img3),
625 destMultiArray(img4),
626 stats, srgType, n, NumericTraits<double>::max());
627 }
628
629 template <class T1, class S1,
630 class TS, class AS,
631 class T2, class S2,
632 class RegionStatisticsArray>
633 inline void
634 seededRegionGrowing3D(MultiArrayView<3, T1, S1> const & img1,
635 MultiArrayView<3, TS, AS> const & img3,
636 MultiArrayView<3, T2, S2> img4,
637 RegionStatisticsArray & stats, SRGType srgType)
638 {
639 vigra_precondition(img1.shape() == img3.shape(),
640 "seededRegionGrowing3D(): shape mismatch between input and output.");
641 seededRegionGrowing3D(srcMultiArrayRange(img1),
642 srcMultiArray(img3),
643 destMultiArray(img4),
644 stats, srgType, NeighborCode3DSix());
645 }
646
647 template <class T1, class S1,
648 class TS, class AS,
649 class T2, class S2,
650 class RegionStatisticsArray>
651 inline void
652 seededRegionGrowing3D(MultiArrayView<3, T1, S1> const & img1,
653 MultiArrayView<3, TS, AS> const & img3,
654 MultiArrayView<3, T2, S2> img4,
655 RegionStatisticsArray & stats)
656 {
657 vigra_precondition(img1.shape() == img3.shape(),
658 "seededRegionGrowing3D(): shape mismatch between input and output.");
659 seededRegionGrowing3D(srcMultiArrayRange(img1),
660 srcMultiArray(img3),
661 destMultiArray(img4),
662 stats);
663 }
664
665 } // namespace vigra
666
667 #endif // VIGRA_SEEDEDREGIONGROWING_HXX
668

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany | html generated using doxygen and Python vigra 1.10.0 (Mon Nov 18 2013)