Orfeo Toolbox  3.16
itkShapeUniqueLabelMapFilter.h
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkShapeUniqueLabelMapFilter.h,v $
5  Language: C++
6  Date: $Date: 2009-08-11 14:24:44 $
7  Version: $Revision: 1.6 $
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 __itkShapeUniqueLabelMapFilter_h
18 #define __itkShapeUniqueLabelMapFilter_h
19 
22 #include <queue>
23 
24 namespace itk {
36 template<class TImage>
38  public InPlaceLabelMapFilter<TImage>
39 {
40 public:
46 
48  typedef TImage ImageType;
49  typedef typename ImageType::Pointer ImagePointer;
50  typedef typename ImageType::ConstPointer ImageConstPointer;
51  typedef typename ImageType::PixelType PixelType;
52  typedef typename ImageType::IndexType IndexType;
53  typedef typename ImageType::LabelObjectType LabelObjectType;
54  typedef typename LabelObjectType::LineType LineType;
55 
56  typedef typename LabelObjectType::AttributeType AttributeType;
57 
59  itkStaticConstMacro(ImageDimension, unsigned int,
60  TImage::ImageDimension);
61 
63  itkNewMacro(Self);
64 
66  itkTypeMacro(ShapeUniqueLabelMapFilter,
68 
69 #ifdef ITK_USE_CONCEPT_CHECKING
70 
71 /* itkConceptMacro(InputEqualityComparableCheck,
72  (Concept::EqualityComparable<InputImagePixelType>));
73  itkConceptMacro(IntConvertibleToInputCheck,
74  (Concept::Convertible<int, InputImagePixelType>));
75  itkConceptMacro(InputOStreamWritableCheck,
76  (Concept::OStreamWritable<InputImagePixelType>));*/
78 #endif
79 
86  itkGetConstMacro( ReverseOrdering, bool );
87  itkSetMacro( ReverseOrdering, bool );
88  itkBooleanMacro( ReverseOrdering );
89 
94  itkGetConstMacro( Attribute, AttributeType );
95  itkSetMacro( Attribute, AttributeType );
96  void SetAttribute( const std::string & s )
97  {
98  this->SetAttribute( LabelObjectType::GetAttributeFromName( s ) );
99  }
100 
101 
102 protected:
105 
106  void GenerateData();
107 
108  template <class TAttributeAccessor>
109  void TemplatedGenerateData( const TAttributeAccessor & accessor )
110  {
111  // Allocate the output
112  this->AllocateOutputs();
113 
114  // the priority queue to store all the lines of all the objects sorted
115  typedef typename std::priority_queue< LineOfLabelObject, std::vector<LineOfLabelObject>, LineOfLabelObjectComparator > PriorityQueueType;
116  PriorityQueueType pq;
117 
118  ProgressReporter progress( this, 0, 1 );
119  // TODO: really report the progress
120 
121  typedef typename ImageType::LabelObjectContainerType LabelObjectsType;
122 
123  const LabelObjectsType & labelObjects = this->GetLabelMap()->GetLabelObjectContainer();
124  for( typename LabelObjectsType::const_iterator it2 = labelObjects.begin();
125  it2 != labelObjects.end();
126  it2++ )
127  {
128  LabelObjectType * lo = it2->second;
129 
130  // may reduce the number of lines to proceed
131  lo->Optimize();
132 
133  typename LabelObjectType::LineContainerType::const_iterator lit;
134  typename LabelObjectType::LineContainerType & lineContainer = lo->GetLineContainer();
135 
136  for( lit = lineContainer.begin(); lit != lineContainer.end(); lit++ )
137  {
138  pq.push( LineOfLabelObject( *lit, lo ) );
139  }
140 
141  // clear the lines to readd them later
142  lineContainer.clear();
143 
144  // go to the next label
145  // progress.CompletedPixel();
146  }
147 
148  if( pq.empty() )
149  {
150  // nothing to do
151  return;
152  }
153 
154  typedef typename std::deque<LineOfLabelObject> LinesType;
155  LinesType lines;
156 
157  lines.push_back( pq.top() );
158  LineOfLabelObject prev = lines.back();
159  IndexType prevIdx = prev.line.GetIndex();
160  pq.pop();
161 
162  while( !pq.empty() )
163  {
164  LineOfLabelObject l = pq.top();
165  IndexType idx = l.line.GetIndex();
166  pq.pop();
167 
168  bool newMainLine = false;
169  // don't check dim 0!
170  for( int i=1; i<ImageDimension; i++ )
171  {
172  if( idx[i] != prevIdx[i] )
173  {
174  newMainLine = true;
175  }
176  }
177 
178  if( newMainLine )
179  {
180  // just push the line
181  lines.push_back( l );
182  }
183  else
184  {
185  unsigned long prevLength = prev.line.GetLength();
186  unsigned long length = l.line.GetLength();
187 
188  if( prevIdx[0] + (long)prevLength >= idx[0] )
189  {
190  // the lines are overlapping. We need to choose which line to keep.
191  // the label, the only "attribute" to be guarenteed to be unique, is used to choose
192  // which line to keep. This is necessary to avoid the case where a part of a label is over
193  // a second label, and below in another part of the image.
194  bool keepCurrent;
195  typename TAttributeAccessor::AttributeValueType prevAttr = accessor( prev.labelObject );
196  typename TAttributeAccessor::AttributeValueType attr = accessor( l.labelObject );
197  // this may be changed to a single boolean expression, but may become quite difficult to read
198  if( attr == prevAttr )
199  {
200  if( l.labelObject->GetLabel() > prev.labelObject->GetLabel() )
201  {
202  keepCurrent = !m_ReverseOrdering;
203  }
204  else
205  {
206  keepCurrent = m_ReverseOrdering;
207  }
208  }
209  else
210  {
211  if( attr > prevAttr )
212  {
213  keepCurrent = !m_ReverseOrdering;
214  }
215  else
216  {
217  keepCurrent = m_ReverseOrdering;
218  }
219  }
220 
221  if( keepCurrent )
222  {
223  // keep the current one. We must truncate the previous one to remove the
224  // overlap, and take care of the end of the previous line if it extends
225  // after the current one.
226  if( prevIdx[0] + prevLength > idx[0] + length )
227  {
228  // the previous line is longer than the current one. Lets take its tail and
229  // add it to the priority queue
230  IndexType newIdx = idx;
231  newIdx[0] = idx[0] + length;
232  unsigned long newLength = prevIdx[0] + prevLength - newIdx[0];
233  pq.push( LineOfLabelObject( LineType( newIdx, newLength ), prev.labelObject ) );
234  }
235  // truncate the previous line to let some place for the current one
236  prevLength = idx[0] - prevIdx[0];
237  if( prevLength != 0 )
238  {
239  lines.back().line.SetLength( idx[0] - prevIdx[0] );
240  }
241  else
242  {
243  // length is 0 - no need to keep that line
244  lines.pop_back();
245  }
246  // and push the current one
247  lines.push_back( l );
248  }
249  else
250  {
251  // keep the previous one. If the previous line fully overlap the current one,
252  // the current one is fully discarded.
253  if( prevIdx[0] + prevLength > idx[0] + length )
254  {
255  // discarding the current line - just do nothing
256  }
257  else
258  {
259  IndexType newIdx = idx;
260  newIdx[0] = prevIdx[0] + prevLength;
261  unsigned long newLength = idx[0] + length - newIdx[0];
262  l.line.SetIndex( newIdx );
263  l.line.SetLength( newLength );
264  lines.push_back( l );
265  }
266 
267  }
268  }
269  else
270  {
271  // no overlap - things are just fine already
272  lines.push_back( l );
273  }
274  }
275 
276  // store the current line as the previous one, and go to the next one.
277  prev = lines.back();
278  prevIdx = prev.line.GetIndex();
279  }
280 
281  // put the lines in their object
282  for( unsigned int i=0; i<lines.size(); i++ )
283  {
284  LineOfLabelObject & l = lines[i];
285  l.labelObject->AddLine( l.line );
286  }
287 
288  // remove objects without lines
289  typename LabelObjectsType::const_iterator it = labelObjects.begin();
290  while( it != labelObjects.end() )
291  {
292  typename LabelObjectType::LabelType label = it->first;
293  LabelObjectType * labelObject = it->second;
294 
295  if( labelObject->Empty() )
296  {
297  // must increment the iterator before removing the object to avoid invalidating the iterator
298  it++;
299  this->GetLabelMap()->RemoveLabel( label );
300  }
301  else
302  {
303  it++;
304  }
305 
306  }
307  }
308 
309  void PrintSelf(std::ostream& os, Indent indent) const;
310 
312 
313 private:
314  ShapeUniqueLabelMapFilter(const Self&); //purposely not implemented
315  void operator=(const Self&); //purposely not implemented
316 
319  {
320  typedef typename LabelObjectType::LineType LineType;
322  {
323  this->line = _line;
324  this->labelObject = _lo;
325  }
328  };
329 
331  {
332  public:
333  bool operator()( const LineOfLabelObject & lla, const LineOfLabelObject & llb )
334  {
335  for( int i=ImageDimension-1; i>=0; i-- )
336  {
337  if( lla.line.GetIndex()[i] > llb.line.GetIndex()[i] )
338  {
339  return true;
340  }
341  else if( lla.line.GetIndex()[i] < llb.line.GetIndex()[i] )
342  {
343  return false;
344  }
345  }
346  return false;
347  }
348  };
349 
350 }; // end of class
351 
352 } // end namespace itk
353 
354 #ifndef ITK_MANUAL_INSTANTIATION
356 #endif
357 
358 #endif

Generated at Sun Feb 3 2013 00:06:44 for Orfeo Toolbox with doxygen 1.8.1.1