ITK  6.0.0
Insight Toolkit
itkShapeUniqueLabelMapFilter.h
Go to the documentation of this file.
1 /*=========================================================================
2  *
3  * Copyright NumFOCUS
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * https://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkShapeUniqueLabelMapFilter_h
19 #define itkShapeUniqueLabelMapFilter_h
20 
23 #include "itkProgressReporter.h"
24 #include <queue>
25 #include "itkMath.h"
26 
27 namespace itk
28 {
43 template <typename TImage>
44 class ITK_TEMPLATE_EXPORT ShapeUniqueLabelMapFilter : public InPlaceLabelMapFilter<TImage>
45 {
46 public:
47  ITK_DISALLOW_COPY_AND_MOVE(ShapeUniqueLabelMapFilter);
48 
54 
56  using ImageType = TImage;
57  using ImagePointer = typename ImageType::Pointer;
59  using PixelType = typename ImageType::PixelType;
60  using IndexType = typename ImageType::IndexType;
61  using LabelObjectType = typename ImageType::LabelObjectType;
62  using LineType = typename LabelObjectType::LineType;
63 
64  using AttributeType = typename LabelObjectType::AttributeType;
65 
67  static constexpr unsigned int ImageDimension = TImage::ImageDimension;
68 
70  itkNewMacro(Self);
71 
73  itkOverrideGetNameOfClassMacro(ShapeUniqueLabelMapFilter);
74 
75 #ifdef ITK_USE_CONCEPT_CHECKING
76  // Begin concept checking
77 /* itkConceptMacro(InputEqualityComparableCheck,
78  (Concept::EqualityComparable<InputImagePixelType>));
79  itkConceptMacro(IntConvertibleToInputCheck,
80  (Concept::Convertible<int, InputImagePixelType>));
81  itkConceptMacro(InputOStreamWritableCheck,
82  (Concept::OStreamWritable<InputImagePixelType>));*/
83 // End concept checking
84 #endif
85 
91  itkGetConstMacro(ReverseOrdering, bool);
92  itkSetMacro(ReverseOrdering, bool);
93  itkBooleanMacro(ReverseOrdering);
100  itkGetConstMacro(Attribute, AttributeType);
101  itkSetMacro(Attribute, AttributeType);
102  void
103  SetAttribute(const std::string & s)
104  {
105  this->SetAttribute(LabelObjectType::GetAttributeFromName(s));
106  }
109 protected:
111  ~ShapeUniqueLabelMapFilter() override = default;
112 
113  void
114  GenerateData() override;
115 
116  template <typename TAttributeAccessor>
117  void
118  TemplatedGenerateData(const TAttributeAccessor & accessor)
119  {
120  // Allocate the output
121  this->AllocateOutputs();
122 
123  // the priority queue to store all the lines of all the objects sorted
124  using PriorityQueueType =
125  typename std::priority_queue<LineOfLabelObject, std::vector<LineOfLabelObject>, LineOfLabelObjectComparator>;
126  PriorityQueueType priorityQueue;
127 
128  const ProgressReporter progress(this, 0, 1);
129  // TODO: really report the progress
130 
131  for (typename ImageType::Iterator it(this->GetLabelMap()); !it.IsAtEnd(); ++it)
132  {
133  LabelObjectType * labelObject = it.GetLabelObject();
134 
135  // may reduce the number of lines to proceed
136  labelObject->Optimize();
137 
138  typename LabelObjectType::ConstLineIterator lit(labelObject);
139  while (!lit.IsAtEnd())
140  {
141  priorityQueue.push(LineOfLabelObject(lit.GetLine(), labelObject));
142  ++lit;
143  }
144 
145  // clear the lines to read them later
146  labelObject->Clear();
147 
148  // go to the next label
149  // progress.CompletedPixel();
150  }
151 
152  if (priorityQueue.empty())
153  {
154  // nothing to do
155  return;
156  }
157 
158  using LinesType = typename std::deque<LineOfLabelObject>;
159  LinesType lines;
160 
161  lines.push_back(priorityQueue.top());
162  LineOfLabelObject prev = lines.back();
163  IndexType prevIdx = prev.line.GetIndex();
164  priorityQueue.pop();
165 
166  while (!priorityQueue.empty())
167  {
168  LineOfLabelObject l = priorityQueue.top();
169  IndexType idx = l.line.GetIndex();
170  priorityQueue.pop();
171 
172  bool newMainLine = false;
173  // don't check dim 0!
174  for (unsigned int i = 1; i < ImageDimension; ++i)
175  {
176  if (idx[i] != prevIdx[i])
177  {
178  newMainLine = true;
179  }
180  }
181 
182  assert(newMainLine || (idx[0] >= prevIdx[0]));
183 
184  if (newMainLine)
185  {
186  // just push the line
187  lines.push_back(l);
188  }
189  else
190  {
191  OffsetValueType prevLength = prev.line.GetLength();
192  const OffsetValueType length = l.line.GetLength();
193 
194  if (prevIdx[0] + prevLength > idx[0])
195  {
196  // the lines are overlapping. We need to choose which line to keep.
197  // the label, the only "attribute" to be guaranteed to be unique, is
198  // used to choose
199  // which line to keep. This is necessary to avoid the case where a
200  // part of a label is over
201  // a second label, and below in another part of the image.
202  bool keepCurrent;
203  const typename TAttributeAccessor::AttributeValueType prevAttr = accessor(prev.labelObject);
204  const typename TAttributeAccessor::AttributeValueType attr = accessor(l.labelObject);
205  // this may be changed to a single boolean expression, but may become
206  // quite difficult to read
207  if (Math::ExactlyEquals(attr, prevAttr))
208  {
209  if (l.labelObject->GetLabel() > prev.labelObject->GetLabel())
210  {
211  keepCurrent = !m_ReverseOrdering;
212  }
213  else
214  {
215  keepCurrent = m_ReverseOrdering;
216  }
217  }
218  else
219  {
220  if (attr > prevAttr)
221  {
222  keepCurrent = !m_ReverseOrdering;
223  }
224  else
225  {
226  keepCurrent = m_ReverseOrdering;
227  }
228  }
229 
230  if (keepCurrent)
231  {
232  // keep the current one. We must truncate the previous one to remove
233  // the
234  // overlap, and take care of the end of the previous line if it
235  // extends
236  // after the current one.
237  if (prevIdx[0] + prevLength > idx[0] + length)
238  {
239  // the previous line is longer than the current one. Lets take its
240  // tail and
241  // add it to the priority queue
242  IndexType newIdx = idx;
243  newIdx[0] = idx[0] + length;
244  const OffsetValueType newLength = prevIdx[0] + prevLength - newIdx[0];
245  priorityQueue.push(LineOfLabelObject(LineType(newIdx, newLength), prev.labelObject));
246  }
247  // truncate the previous line to let some place for the current one
248  prevLength = idx[0] - prevIdx[0];
249  if (prevLength != 0)
250  {
251  assert(prevIdx[0] <= idx[0]);
252  lines.back().line.SetLength(idx[0] - prevIdx[0]);
253  }
254  else
255  {
256  // length is 0 - no need to keep that line
257  lines.pop_back();
258  }
259  // and push the current one
260  lines.push_back(l);
261  }
262  else
263  {
264  // keep the previous one. If the previous line fully overlap the
265  // current one,
266  // the current one is fully discarded.
267  if (prevIdx[0] + prevLength >= idx[0] + length)
268  {
269  // discarding the current line - just do nothing
270  }
271  else
272  {
273  IndexType newIdx = idx;
274  newIdx[0] = prevIdx[0] + prevLength;
275  const OffsetValueType newLength = idx[0] + length - newIdx[0];
276  if (newLength > 0)
277  {
278  l.line.SetIndex(newIdx);
279  l.line.SetLength(newLength);
280  // The front of this line is trimmed, it may occur after a line in the queue
281  // so the queue is used for the proper ordering.
282  priorityQueue.push(l);
283  }
284  }
285  }
286  }
287  else
288  {
289  // no overlap - things are just fine already
290  lines.push_back(l);
291  }
292  }
293 
294  // store the current line as the previous one, and go to the next one.
295  prev = lines.back();
296  prevIdx = prev.line.GetIndex();
297  }
298 
299  // put the lines in their object
300  for (size_t i = 0; i < lines.size(); ++i)
301  {
302  LineOfLabelObject & l = lines[i];
303  l.labelObject->AddLine(l.line);
304  }
305 
306  // remove objects without lines
307  typename ImageType::Iterator it(this->GetLabelMap());
308  while (!it.IsAtEnd())
309  {
310  const typename LabelObjectType::LabelType label = it.GetLabel();
311  LabelObjectType * labelObject = it.GetLabelObject();
312 
313  if (labelObject->Empty())
314  {
315  // must increment the iterator before removing the object to avoid
316  // invalidating the iterator
317  ++it;
318  this->GetLabelMap()->RemoveLabel(label);
319  }
320  else
321  {
322  ++it;
323  }
324  }
325  }
326 
327  void
328  PrintSelf(std::ostream & os, Indent indent) const override;
329 
330  AttributeType m_Attribute{};
331 
332 private:
333  bool m_ReverseOrdering{};
335  {
336  using LineType = typename LabelObjectType::LineType;
338  {
339  this->line = _line;
340  this->labelObject = _lo;
341  }
342 
345  };
346 
348  {
349  public:
350  bool
352  {
353  for (int i = ImageDimension - 1; i >= 0; i--)
354  {
355  if (lla.line.GetIndex()[i] > llb.line.GetIndex()[i])
356  {
357  return true;
358  }
359  else if (lla.line.GetIndex()[i] < llb.line.GetIndex()[i])
360  {
361  return false;
362  }
363  }
364  return false;
365  }
366  };
367 }; // end of class
368 } // end namespace itk
369 
370 #ifndef ITK_MANUAL_INSTANTIATION
371 # include "itkShapeUniqueLabelMapFilter.hxx"
372 #endif
373 
374 #endif
Pointer
SmartPointer< Self > Pointer
Definition: itkAddImageFilter.h:93
itk::ShapeUniqueLabelMapFilter::SetAttribute
void SetAttribute(const std::string &s)
Definition: itkShapeUniqueLabelMapFilter.h:103
ConstPointer
SmartPointer< const Self > ConstPointer
Definition: itkAddImageFilter.h:94
itk::ShapeUniqueLabelMapFilter::LineOfLabelObject::line
LineType line
Definition: itkShapeUniqueLabelMapFilter.h:343
itk::ShapeUniqueLabelMapFilter::LabelObjectType
typename ImageType::LabelObjectType LabelObjectType
Definition: itkShapeUniqueLabelMapFilter.h:61
itk::ShapeUniqueLabelMapFilter::LineOfLabelObjectComparator::operator()
bool operator()(const LineOfLabelObject &lla, const LineOfLabelObject &llb)
Definition: itkShapeUniqueLabelMapFilter.h:351
itk::InPlaceLabelMapFilter
Base class for filters that takes an image as input and overwrites that image as the output.
Definition: itkInPlaceLabelMapFilter.h:83
itk::ShapeUniqueLabelMapFilter::LineOfLabelObjectComparator
Definition: itkShapeUniqueLabelMapFilter.h:347
itk::Math::ExactlyEquals
bool ExactlyEquals(const TInput1 &x1, const TInput2 &x2)
Return the result of an exact comparison between two scalar values of potentially different types.
Definition: itkMath.h:722
itkProgressReporter.h
itk::ShapeUniqueLabelMapFilter::LineOfLabelObject::labelObject
LabelObjectType * labelObject
Definition: itkShapeUniqueLabelMapFilter.h:344
itk::SmartPointer< Self >
itk::Indent
Control indentation during Print() invocation.
Definition: itkIndent.h:49
itk::ShapeUniqueLabelMapFilter::AttributeType
typename LabelObjectType::AttributeType AttributeType
Definition: itkShapeUniqueLabelMapFilter.h:64
itk::ShapeUniqueLabelMapFilter
Remove some pixels in the label object according to the value of their shape attribute to ensure that...
Definition: itkShapeUniqueLabelMapFilter.h:44
itkShapeLabelObjectAccessors.h
itk::GTest::TypedefsAndConstructors::Dimension2::IndexType
ImageBaseType::IndexType IndexType
Definition: itkGTestTypedefsAndConstructors.h:50
itk::ShapeUniqueLabelMapFilter::IndexType
typename ImageType::IndexType IndexType
Definition: itkShapeUniqueLabelMapFilter.h:60
itk::LightObject
Light weight base class for most itk classes.
Definition: itkLightObject.h:55
itk::ShapeUniqueLabelMapFilter::LineType
typename LabelObjectType::LineType LineType
Definition: itkShapeUniqueLabelMapFilter.h:62
itk::ShapeUniqueLabelMapFilter::LineOfLabelObject::LineOfLabelObject
LineOfLabelObject(const LineType _line, LabelObjectType *_lo)
Definition: itkShapeUniqueLabelMapFilter.h:337
itk::ShapeUniqueLabelMapFilter::PixelType
typename ImageType::PixelType PixelType
Definition: itkShapeUniqueLabelMapFilter.h:59
itkInPlaceLabelMapFilter.h
itk::ShapeUniqueLabelMapFilter::ImageConstPointer
typename ImageType::ConstPointer ImageConstPointer
Definition: itkShapeUniqueLabelMapFilter.h:58
itk::OffsetValueType
long OffsetValueType
Definition: itkIntTypes.h:97
itk::ShapeUniqueLabelMapFilter::ImageType
TImage ImageType
Definition: itkShapeUniqueLabelMapFilter.h:56
itk
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
Definition: itkAnatomicalOrientation.h:29
itk::ShapeUniqueLabelMapFilter::TemplatedGenerateData
void TemplatedGenerateData(const TAttributeAccessor &accessor)
Definition: itkShapeUniqueLabelMapFilter.h:118
itk::ProgressReporter
Implements progress tracking for a filter.
Definition: itkProgressReporter.h:60
itk::ShapeUniqueLabelMapFilter::LineOfLabelObject
Definition: itkShapeUniqueLabelMapFilter.h:334
itk::ShapeUniqueLabelMapFilter::ImagePointer
typename ImageType::Pointer ImagePointer
Definition: itkShapeUniqueLabelMapFilter.h:57
itkMath.h
itk::ShapeUniqueLabelMapFilter::LineOfLabelObject::LineType
typename LabelObjectType::LineType LineType
Definition: itkShapeUniqueLabelMapFilter.h:336