Orfeo Toolbox  3.16
itkWatershedSegmentTreeGenerator.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkWatershedSegmentTreeGenerator.txx,v $
5  Language: C++
6  Date: $Date: 2009-04-17 15:57:33 $
7  Version: $Revision: 1.20 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  This software is distributed WITHOUT ANY WARRANTY; without even
13  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  PURPOSE. See the above copyright notices for more information.
15 
16 =========================================================================*/
17 #ifndef __itkWatershedSegmentTreeGenerator_txx
18 #define __itkWatershedSegmentTreeGenerator_txx
19 
20 #include <stack>
22 
23 namespace itk
24 {
25 namespace watershed
26 {
27 
28 template <class TScalarType>
30 ::SegmentTreeGenerator() : m_Merge(false), m_FloodLevel(0.0),
31  m_ConsumeInput(false), m_HighestCalculatedFloodLevel(0.0)
32 {
33  typename SegmentTreeType::Pointer st
34  = static_cast<SegmentTreeType*>(this->MakeOutput(0).GetPointer());
35  this->SetNumberOfRequiredOutputs(1);
37  m_MergedSegmentsTable = OneWayEquivalencyTableType::New();
38 }
39 
40 template <class TScalarType>
43 ::MakeOutput(unsigned int itkNotUsed(idx))
44 {
45  return static_cast<DataObject*>(SegmentTreeType::New().GetPointer());
46 }
47 
48 template <class TScalarType>
50 ::SetFloodLevel(double val)
51 {
52  // Clamp level between 0.0 and 1.0
53  if (val > 1.0) { m_FloodLevel = 1.0; }
54  else if (val < 0.0) { m_FloodLevel = 0.0; }
55  else { m_FloodLevel = val; }
56 
57  // Has this flood level increased over a level that has already been
58  // calculated? If not, then we don't set the modified flag. A decrease in
59  // the flood level does not require re-execution of the filter.
60  if ( m_HighestCalculatedFloodLevel < m_FloodLevel )
61  {
62  this->Modified();
63  }
64 }
65 
66 template <class TScalarType>
69 {
70 
71  //Reset persistant ivars.
72  m_MergedSegmentsTable->Clear();
73  this->GetOutputSegmentTree()->Clear();
74 
75  typename SegmentTableType::Pointer input = this->GetInputSegmentTable();
76  typename SegmentTreeType::Pointer mergeList = SegmentTreeType::New();
77  typename SegmentTableType::Pointer seg = SegmentTableType::New();
78  if (m_ConsumeInput == true) // do not copy input
79  {
80  input->Modified();
81  input->SortEdgeLists();
82 
83  if (m_Merge == true) { this->MergeEquivalencies(); }
84 
85  this->CompileMergeList(input, mergeList);
86  this->ExtractMergeHierarchy(input, mergeList);
87  }
88  else
89  {
90  seg->Copy(*input); // copy the input
91  seg->SortEdgeLists();
92  if (m_Merge == true) { this->MergeEquivalencies(); }
93  this->CompileMergeList(seg, mergeList);
94  this->ExtractMergeHierarchy(seg, mergeList);
95  }
96  this->UpdateProgress(1.0);
97 
98  // Keep track of the highest flood level we calculated
99  if (m_FloodLevel > m_HighestCalculatedFloodLevel)
100  {
101  m_HighestCalculatedFloodLevel = m_FloodLevel;
102  }
103 }
104 
105 template <class TScalarType>
108 {
109  typename SegmentTableType::Pointer segTable = this->GetInputSegmentTable();
110  typename EquivalencyTableType::Pointer eqTable =
111  this->GetInputEquivalencyTable();
112  typename EquivalencyTableType::Iterator it;
113  ScalarType threshold = static_cast<ScalarType>(m_FloodLevel * segTable->GetMaximumDepth());
114 
115  eqTable->Flatten();
116  unsigned long counter =0;
117 
118  segTable->PruneEdgeLists(threshold);
119 
120  for (it = eqTable->Begin(); it != eqTable->End(); ++it)
121  {
122  MergeSegments(segTable, m_MergedSegmentsTable,
123  (*it).first, (*it).second); // Merge first INTO second.
124  // deletes first
125  if ( (counter % 10000) == 0 )
126  {
127  segTable->PruneEdgeLists(threshold);
128  m_MergedSegmentsTable->Flatten();
129  counter = 0;
130  }
131 
132  counter++;
133  }
134 }
135 
136 template <class TScalarType>
139  SegmentTreeTypePointer mergeList)
140 {
141  typename SegmentTreeType::merge_t tempMerge;
142 
143  // Region A will flood Region B (B will merge with A) at a flood level L
144  // when all of the following conditions are true:
145  // 1) Depth of B < L
146  // 2) A is across the lowest edge of B
147  typename SegmentTableType::Iterator segment_ptr;
148  unsigned long labelFROM;
149  unsigned long labelTO;
150  ScalarType threshold = static_cast<ScalarType>(m_FloodLevel * segments->GetMaximumDepth());
151  m_MergedSegmentsTable->Flatten();
152 
153  segments->PruneEdgeLists(threshold);
154 
155  for (segment_ptr = segments->Begin(); segment_ptr != segments->End();
156  ++segment_ptr)
157  {
158  labelFROM = (*segment_ptr).first;
159 
160  // Must take into account any equivalencies that have already been
161  // recorded.
162  labelTO
163  = m_MergedSegmentsTable->RecursiveLookup((*segment_ptr).second.edge_list.front().label);
164  while (labelTO == labelFROM) // Pop off any bogus merges with ourself
165  { // that may have been left in this list.
166  (*segment_ptr).second.edge_list.pop_front();
167  labelTO
168  = m_MergedSegmentsTable->RecursiveLookup((*segment_ptr).second.edge_list.front().label);
169  }
170 
171  // Add this merge to our list if its saliency is below
172  // the threshold.
173  tempMerge.from = labelFROM;
174  tempMerge.to = labelTO;
175  tempMerge.saliency = (*segment_ptr).second.edge_list.front().height
176  - (*segment_ptr).second.min;
177  if (tempMerge.saliency < threshold)
178  {
179  mergeList->PushBack(tempMerge);
180  }
181  }
182 
183  // Heapsort the list
184  typedef typename SegmentTreeType::merge_comp MergeComparison;
185  std::make_heap(mergeList->Begin(), mergeList->End(), MergeComparison() );
186 }
187 
188 template <class TScalarType>
192 {
193  typename SegmentTreeType::Pointer list = this->GetOutputSegmentTree();
194 
195  // Merges segments up to a specified floodlevel according to the information
196  // in the heap of merges. As two segments are merged, calculates a new
197  // possible merges and pushes it onto the heap.
198  ScalarType threshold = static_cast<ScalarType>(m_FloodLevel * segments->GetMaximumDepth());
199 
200  unsigned counter;
201  typedef typename SegmentTreeType::merge_comp MergeComparison;
202  typename SegmentTableType::DataType *toSeg;
203  typename SegmentTreeType::ValueType tempMerge;
204  unsigned long toSegLabel, fromSegLabel;
205 
206  if (heap->Empty()) return;
207  double initHeapSize = static_cast<double>(heap->Size());
208 
209  counter = 0;
210  typename SegmentTreeType::ValueType topMerge = heap->Front();
211 
212  while( (! heap->Empty()) && (topMerge.saliency <= threshold) )
213  {
214  counter++; // Every so often we should eliminate
215  if ((counter == 10000)) // all the recursion in our records
216  { // of which segments have merged.
217  counter = 0;
218  segments->PruneEdgeLists(threshold); // also we want to
219  // keep the edge list size under control
220  }
221  if ((counter % 10000) == 0)
222  {
223  m_MergedSegmentsTable->Flatten();
224  }
225 
226  if ((counter % 1000) == 0)
227  {
228  this->UpdateProgress(1.0 - ((static_cast<double>(heap->Size())) /
229  initHeapSize));
230  }
231 
232  std::pop_heap(heap->Begin(), heap->End(), MergeComparison() );
233  heap->PopBack(); // Popping the heap moves the top element to the end
234  // of the container structure, so we delete that here.
235 
236  // Recursively find the segments we are about to merge
237  // (the labels identified here may have merged already)
238  fromSegLabel = m_MergedSegmentsTable->RecursiveLookup(topMerge.from);
239  toSegLabel = m_MergedSegmentsTable->RecursiveLookup(topMerge.to);
240 
241  // If the two segments do not resolve to the same segment and the
242  // "TO" segment has never been merged, then then merge them.
243  // Otherwise, ignore this particular entry.
244  if ( fromSegLabel == topMerge.from && fromSegLabel != toSegLabel )
245  {
246  toSeg = segments->Lookup( toSegLabel );
247 
248  topMerge.from = fromSegLabel;
249  topMerge.to = toSegLabel;
250  list->PushBack(topMerge); // Record this merge for posterity
251 
252  // Merge the segments
253  Self::MergeSegments(segments, m_MergedSegmentsTable,
254  fromSegLabel, toSegLabel);
255 
256  // Now check for new possible merges in A.
257  // All we have to do is look at the front of the
258  // ordered list.
259 
260  // Recursively look up the label to which we might
261  // be merging to.
262  if (! toSeg->edge_list.empty() )
263  {
264  tempMerge.from = toSegLabel; // The new, composite segment
265  tempMerge.to = m_MergedSegmentsTable->RecursiveLookup(
266  toSeg->edge_list.front().label );
267  while (tempMerge.to == tempMerge.from)
268  { // We don't want to merge to ourself.
269  toSeg->edge_list.pop_front();
270  tempMerge.to = m_MergedSegmentsTable->RecursiveLookup(
271  toSeg->edge_list.front().label );
272  }
273  tempMerge.saliency =
274  (toSeg->edge_list.front().height) - toSeg->min;
275 
276  heap->PushBack(tempMerge);
277  std::push_heap(heap->Begin(), heap->End(), MergeComparison() );
278  }
279  }
280  if( ! heap->Empty() )
281  {
282  topMerge = heap->Front();
283  }
284  }
285 }
286 
287 
288 template <class TScalarType>
292  const unsigned long FROM, const unsigned long TO,
293  ScalarType maxSaliency)
294 {
295  typename SegmentTableType::edge_list_t::iterator edgeTOi, edgeFROMi,
296  edgeTEMPi;
298  seen_table;
299  unsigned long labelTO, labelFROM;
300 
301  // Lookup both entries.
302  typename SegmentTableType::segment_t *from_seg = segments->Lookup(FROM);
303  typename SegmentTableType::segment_t *to_seg = segments->Lookup(TO);
304 
305  if (from_seg == 0 || to_seg == 0)
306  {
307  itkGenericExceptionMacro ( << "PruneMergeSegments:: An unexpected and fatal error has occurred.");
308  }
309 
310  // Compare the minimum values.
311  if ((from_seg->min) < (to_seg->min)) (to_seg->min) = (from_seg->min);
312 
313  // Add all the "FROM" edges to the "TO" edges.
314 
315  // We MUST eliminate redundant edges to prevent the
316  // segment table from growing to unmanageable sizes.
317  // Since the lists are sorted, the lowest height
318  // value will be added first, so any redundant edges
319  // can simply be eliminated.
320 
321  // References in adjacent edge tables are not replaced,
322  // but rather will be resolved later through the one-way
323  // equivalency table.
324 
325  edgeTOi = to_seg->edge_list.begin();
326  edgeFROMi = from_seg->edge_list.begin();
327  while ( edgeTOi != to_seg->edge_list.end() &&
328  edgeFROMi != from_seg->edge_list.end() )
329  {
330  // Recursively resolve the labels we are seeing
331  labelTO = eqT->RecursiveLookup(edgeTOi->label);
332  labelFROM = eqT->RecursiveLookup(edgeFROMi->label);
333 
334  // Ignore any labels already in this list and
335  // any pointers back to ourself.
336  // This step is necessary to keep the edge lists from
337  // growing exponentially in size as segments merge.
338  if ( seen_table.find(labelTO) != seen_table.end() ||
339  labelTO == FROM )
340  {
341  edgeTEMPi = edgeTOi;
342  edgeTEMPi++;
343  to_seg->edge_list.erase(edgeTOi);
344  edgeTOi = edgeTEMPi;
345  continue;
346  }
347  if ( seen_table.find(labelFROM) != seen_table.end() ||
348  labelFROM == TO)
349  {
350  edgeFROMi++;
351  continue;
352  }
353 
354  // Fix any changed labels since we have the chance
355  if ( labelTO != edgeTOi->label ) edgeTOi->label = labelTO;
356  if ( labelFROM != edgeFROMi->label) edgeFROMi->label = labelFROM;
357 
358  // Which edge is next in the list?
359  if ( edgeFROMi->height < edgeTOi->height )
360  {
361  to_seg->edge_list.insert(edgeTOi, *edgeFROMi);
362  seen_table.insert(itk::hash_map<unsigned long, bool, itk::hash<unsigned long> >::value_type(labelFROM, true));
363  edgeFROMi++;
364  }
365  else
366  {
367  seen_table.insert(itk::hash_map<unsigned long, bool, itk::hash<unsigned long> >::value_type(labelTO, true));
368  edgeTOi++;
369  }
370  }
371 
372  // Process tail of the FROM list.
373  while ( edgeFROMi != from_seg->edge_list.end() )
374  {
375  labelFROM = eqT->RecursiveLookup(edgeFROMi->label);
376  if ( seen_table.find(labelFROM) != seen_table.end() ||
377  labelFROM == TO)
378  {
379  edgeFROMi++;
380  }
381  else
382  {
383  if ( labelFROM != edgeFROMi->label) edgeFROMi->label = labelFROM;
384  to_seg->edge_list.push_back(*edgeFROMi);
385  seen_table.insert(itk::hash_map<unsigned long, bool, itk::hash<unsigned long> >::value_type(labelFROM, true));
386  edgeFROMi++;
387  }
388  }
389 
390  // Process tail of the TO list.
391  while ( edgeTOi != to_seg->edge_list.end() )
392  {
393  labelTO = eqT->RecursiveLookup(edgeTOi->label);
394  if ( seen_table.find(labelTO) != seen_table.end() ||
395  labelTO == FROM)
396  {
397  edgeTEMPi = edgeTOi;
398  edgeTEMPi++;
399  to_seg->edge_list.erase(edgeTOi);
400  edgeTOi = edgeTEMPi;
401  }
402  else
403  {
404  if ( labelTO != edgeTOi->label ) edgeTOi->label = labelTO;
405  seen_table.insert(itk::hash_map<unsigned long, bool, itk::hash<unsigned long> >::value_type(labelTO, true));
406  edgeTOi++;
407  }
408  }
409 
410  // Now destroy the segment that was merged.
411  segments->Erase(FROM);
412 
413  // Record this equivalency
414  eqT->Add(FROM, TO);
415 }
416 
417 template <class TScalarType>
421  const unsigned long FROM, const unsigned long TO)
422 {
423  typename SegmentTableType::edge_list_t::iterator edgeTOi, edgeFROMi,
424  edgeTEMPi;
426  seen_table;
427  unsigned long labelTO, labelFROM;
428 
429  // Lookup both entries.
430  typename SegmentTableType::segment_t *from_seg = segments->Lookup(FROM);
431  typename SegmentTableType::segment_t *to_seg = segments->Lookup(TO);
432 
433  if (from_seg == 0 || to_seg == 0)
434  {
435 
436  itkGenericExceptionMacro ( <<
437  "itk::watershed::SegmentTreeGenerator::MergeSegments:: An unexpected and fatal error has occurred. This is probably the result of overthresholding of the input image.");
438  }
439 
440  // Compare the minimum values.
441  if ((from_seg->min) < (to_seg->min)) (to_seg->min) = (from_seg->min);
442 
443  // Add all the "FROM" edges to the "TO" edges.
444 
445  // We MUST eliminate redundant edges to prevent the
446  // segment table from growing to unmanageable sizes.
447  // Since the lists are sorted, the lowest height
448  // value will be added first, so any redundant edges
449  // can simply be eliminated.
450 
451  // References in adjacent edge tables are not replaced,
452  // but rather will be resolved later through the one-way
453  // equivalency table.
454 
455  edgeTOi = to_seg->edge_list.begin();
456  edgeFROMi = from_seg->edge_list.begin();
457  while ( edgeTOi != to_seg->edge_list.end() &&
458  edgeFROMi != from_seg->edge_list.end() )
459  {
460  // Recursively resolve the labels we are seeing
461  labelTO = eqT->RecursiveLookup(edgeTOi->label);
462  labelFROM = eqT->RecursiveLookup(edgeFROMi->label);
463 
464  // Ignore any labels already in this list and
465  // any pointers back to ourself.
466  // This step is necessary to keep the edge lists from
467  // growing exponentially in size as segments merge.
468  if ( seen_table.find(labelTO) != seen_table.end() ||
469  labelTO == FROM )
470  {
471  edgeTEMPi = edgeTOi;
472  edgeTEMPi++;
473  to_seg->edge_list.erase(edgeTOi);
474  edgeTOi = edgeTEMPi;
475  continue;
476  }
477  if ( seen_table.find(labelFROM) != seen_table.end() ||
478  labelFROM == TO)
479  {
480  edgeFROMi++;
481  continue;
482  }
483 
484  // Fix any changed labels since we have the chance
485  if ( labelTO != edgeTOi->label ) edgeTOi->label = labelTO;
486  if ( labelFROM != edgeFROMi->label) edgeFROMi->label = labelFROM;
487 
488  // Which edge is next in the list?
489  if ( edgeFROMi->height < edgeTOi->height )
490  {
491  to_seg->edge_list.insert(edgeTOi, *edgeFROMi);
492  seen_table.insert(itk::hash_map<unsigned long, bool, itk::hash<unsigned long> >::value_type(labelFROM, true));
493  edgeFROMi++;
494  }
495  else
496  {
497  seen_table.insert(itk::hash_map<unsigned long, bool, itk::hash<unsigned long> >::value_type(labelTO, true));
498  edgeTOi++;
499  }
500  }
501 
502  // Process tail of the FROM list.
503  while ( edgeFROMi != from_seg->edge_list.end() )
504  {
505  labelFROM = eqT->RecursiveLookup(edgeFROMi->label);
506  if ( seen_table.find(labelFROM) != seen_table.end() ||
507  labelFROM == TO)
508  {
509  edgeFROMi++;
510  }
511  else
512  {
513  if ( labelFROM != edgeFROMi->label) edgeFROMi->label = labelFROM;
514  to_seg->edge_list.push_back(*edgeFROMi);
515  seen_table.insert(itk::hash_map<unsigned long, bool, itk::hash<unsigned long> >::value_type(labelFROM, true));
516  edgeFROMi++;
517  }
518  }
519 
520  // Process tail of the TO list.
521  while ( edgeTOi != to_seg->edge_list.end() )
522  {
523  labelTO = eqT->RecursiveLookup(edgeTOi->label);
524  if ( seen_table.find(labelTO) != seen_table.end() ||
525  labelTO == FROM)
526  {
527  edgeTEMPi = edgeTOi;
528  edgeTEMPi++;
529  to_seg->edge_list.erase(edgeTOi);
530  edgeTOi = edgeTEMPi;
531  }
532  else
533  {
534  if ( labelTO != edgeTOi->label ) edgeTOi->label = labelTO;
535  seen_table.insert(itk::hash_map<unsigned long, bool, itk::hash<unsigned long> >::value_type(labelTO, true));
536  edgeTOi++;
537  }
538  }
539 
540  // Now destroy the segment that was merged.
541  segments->Erase(FROM);
542 
543  // Record this equivalency
544  eqT->Add(FROM, TO);
545 }
546 
547 template <class TScalarType>
550 {
551 }
552 
553 template <class TScalarType>
556 {
557  Superclass::GenerateInputRequestedRegion();
558 
559  // get pointers to the input and output
560  // typename SegmentTableType::Pointer inputPtr = this->GetInputSegmentTable();
561  // typename SegmentTreeType::Pointer outputPtr = this->GetOutputSegmentTree();
562 
563  // if ( !inputPtr || !outputPtr )
564  // {
565  // return;
566  // }
567 
568 }
569 
570 template<class TScalarType>
571 void
573 ::PrintSelf(std::ostream& os, Indent indent) const
574 {
575  Superclass::PrintSelf(os,indent);
576  os << indent << "FloodLevel: " << m_FloodLevel << std::endl;
577  os << indent << "Merge: " << m_Merge << std::endl;
578  os << indent << "ConsumeInput: " << m_ConsumeInput << std::endl;
579  os << indent << "HighestCalculatedFloodLevel: " <<
580  m_HighestCalculatedFloodLevel << std::endl;
581 }
582 
583 }// end namespace watershed
584 }// end namespace itk
585 
586 #endif

Generated at Sun Feb 3 2013 00:14:59 for Orfeo Toolbox with doxygen 1.8.1.1