ITK 6.0.0
Insight Toolkit
 
Loading...
Searching...
No Matches
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
27namespace itk
28{
43template <typename TImage>
44class ITK_TEMPLATE_EXPORT ShapeUniqueLabelMapFilter : public InPlaceLabelMapFilter<TImage>
45{
46public:
47 ITK_DISALLOW_COPY_AND_MOVE(ShapeUniqueLabelMapFilter);
48
54
56 using ImageType = TImage;
57 using ImagePointer = typename ImageType::Pointer;
58 using ImageConstPointer = typename ImageType::ConstPointer;
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 /*itkConceptMacro(InputEqualityComparableCheck,
76 (Concept::EqualityComparable<InputImagePixelType>));
77 itkConceptMacro(IntConvertibleToInputCheck,
78 (Concept::Convertible<int, InputImagePixelType>));
79 itkConceptMacro(InputOStreamWritableCheck,
80 (Concept::OStreamWritable<InputImagePixelType>));*/
81
88 itkGetConstMacro(ReverseOrdering, bool);
89 itkSetMacro(ReverseOrdering, bool);
90 itkBooleanMacro(ReverseOrdering);
97 itkGetConstMacro(Attribute, AttributeType);
98 itkSetMacro(Attribute, AttributeType);
99 void
100 SetAttribute(const std::string & s)
101 {
102 this->SetAttribute(LabelObjectType::GetAttributeFromName(s));
103 }
104
105protected:
107 ~ShapeUniqueLabelMapFilter() override = default;
108
109 void
110 GenerateData() override;
111
112 template <typename TAttributeAccessor>
113 void
114 TemplatedGenerateData(const TAttributeAccessor & accessor)
115 {
116 // Allocate the output
117 this->AllocateOutputs();
118
119 // the priority queue to store all the lines of all the objects sorted
120 using PriorityQueueType =
121 typename std::priority_queue<LineOfLabelObject, std::vector<LineOfLabelObject>, LineOfLabelObjectComparator>;
122 PriorityQueueType priorityQueue;
123
124 const ProgressReporter progress(this, 0, 1);
125 // TODO: really report the progress
126
127 for (typename ImageType::Iterator it(this->GetLabelMap()); !it.IsAtEnd(); ++it)
128 {
129 LabelObjectType * labelObject = it.GetLabelObject();
130
131 // may reduce the number of lines to proceed
132 labelObject->Optimize();
133
134 typename LabelObjectType::ConstLineIterator lit(labelObject);
135 while (!lit.IsAtEnd())
136 {
137 priorityQueue.push(LineOfLabelObject(lit.GetLine(), labelObject));
138 ++lit;
139 }
140
141 // clear the lines to read them later
142 labelObject->Clear();
143
144 // go to the next label
145 // progress.CompletedPixel();
146 }
147
148 if (priorityQueue.empty())
149 {
150 // nothing to do
151 return;
152 }
153
154 using LinesType = typename std::deque<LineOfLabelObject>;
155 LinesType lines;
156
157 lines.push_back(priorityQueue.top());
158 LineOfLabelObject prev = lines.back();
159 IndexType prevIdx = prev.line.GetIndex();
160 priorityQueue.pop();
161
162 while (!priorityQueue.empty())
163 {
164 LineOfLabelObject l = priorityQueue.top();
165 IndexType idx = l.line.GetIndex();
166 priorityQueue.pop();
167
168 bool newMainLine = false;
169 // don't check dim 0!
170 for (unsigned int i = 1; i < ImageDimension; ++i)
171 {
172 if (idx[i] != prevIdx[i])
173 {
174 newMainLine = true;
175 }
176 }
177
178 assert(newMainLine || (idx[0] >= prevIdx[0]));
179
180 if (newMainLine)
181 {
182 // just push the line
183 lines.push_back(l);
184 }
185 else
186 {
187 OffsetValueType prevLength = prev.line.GetLength();
188 const OffsetValueType length = l.line.GetLength();
189
190 if (prevIdx[0] + prevLength > idx[0])
191 {
192 // the lines are overlapping. We need to choose which line to keep.
193 // the label, the only "attribute" to be guaranteed to be unique, is
194 // used to choose
195 // which line to keep. This is necessary to avoid the case where a
196 // part of a label is over
197 // a second label, and below in another part of the image.
198
199 const typename TAttributeAccessor::AttributeValueType prevAttr = accessor(prev.labelObject);
200 const typename TAttributeAccessor::AttributeValueType attr = accessor(l.labelObject);
201 // this may be changed to a single boolean expression, but may become
202 // quite difficult to read
203 bool keepCurrent = false;
204 if (Math::ExactlyEquals(attr, prevAttr))
205 {
206 if (l.labelObject->GetLabel() > prev.labelObject->GetLabel())
207 {
208 keepCurrent = !m_ReverseOrdering;
209 }
210 else
211 {
212 keepCurrent = m_ReverseOrdering;
213 }
214 }
215 else
216 {
217 if (attr > prevAttr)
218 {
219 keepCurrent = !m_ReverseOrdering;
220 }
221 else
222 {
223 keepCurrent = m_ReverseOrdering;
224 }
225 }
226
227 if (keepCurrent)
228 {
229 // keep the current one. We must truncate the previous one to remove
230 // the
231 // overlap, and take care of the end of the previous line if it
232 // extends
233 // after the current one.
234 if (prevIdx[0] + prevLength > idx[0] + length)
235 {
236 // the previous line is longer than the current one. Lets take its
237 // tail and
238 // add it to the priority queue
239 IndexType newIdx = idx;
240 newIdx[0] = idx[0] + length;
241 const OffsetValueType newLength = prevIdx[0] + prevLength - newIdx[0];
242 priorityQueue.push(LineOfLabelObject(LineType(newIdx, newLength), prev.labelObject));
243 }
244 // truncate the previous line to let some place for the current one
245 prevLength = idx[0] - prevIdx[0];
246 if (prevLength != 0)
247 {
248 assert(prevIdx[0] <= idx[0]);
249 lines.back().line.SetLength(idx[0] - prevIdx[0]);
250 }
251 else
252 {
253 // length is 0 - no need to keep that line
254 lines.pop_back();
255 }
256 // and push the current one
257 lines.push_back(l);
258 }
259 else
260 {
261 // keep the previous one. If the previous line fully overlap the
262 // current one,
263 // the current one is fully discarded.
264 if (prevIdx[0] + prevLength >= idx[0] + length)
265 {
266 // discarding the current line - just do nothing
267 }
268 else
269 {
270 IndexType newIdx = idx;
271 newIdx[0] = prevIdx[0] + prevLength;
272 const OffsetValueType newLength = idx[0] + length - newIdx[0];
273 if (newLength > 0)
274 {
275 l.line.SetIndex(newIdx);
276 l.line.SetLength(newLength);
277 // The front of this line is trimmed, it may occur after a line in the queue
278 // so the queue is used for the proper ordering.
279 priorityQueue.push(l);
280 }
281 }
282 }
283 }
284 else
285 {
286 // no overlap - things are just fine already
287 lines.push_back(l);
288 }
289 }
290
291 // store the current line as the previous one, and go to the next one.
292 prev = lines.back();
293 prevIdx = prev.line.GetIndex();
294 }
295
296 // put the lines in their object
297 for (size_t i = 0; i < lines.size(); ++i)
298 {
299 LineOfLabelObject & l = lines[i];
300 l.labelObject->AddLine(l.line);
301 }
302
303 // remove objects without lines
304 typename ImageType::Iterator it(this->GetLabelMap());
305 while (!it.IsAtEnd())
306 {
307 const typename LabelObjectType::LabelType label = it.GetLabel();
308 LabelObjectType * labelObject = it.GetLabelObject();
309
310 if (labelObject->Empty())
311 {
312 // must increment the iterator before removing the object to avoid
313 // invalidating the iterator
314 ++it;
315 this->GetLabelMap()->RemoveLabel(label);
316 }
317 else
318 {
319 ++it;
320 }
321 }
322 }
323
324 void
325 PrintSelf(std::ostream & os, Indent indent) const override;
326
328
329private:
332 {
333 using LineType = typename LabelObjectType::LineType;
335 {
336 this->line = _line;
337 this->labelObject = _lo;
338 }
339
342 };
343
345 {
346 public:
347 bool
349 {
350 for (int i = ImageDimension - 1; i >= 0; i--)
351 {
352 if (lla.line.GetIndex()[i] > llb.line.GetIndex()[i])
353 {
354 return true;
355 }
356 if (lla.line.GetIndex()[i] < llb.line.GetIndex()[i])
357 {
358 return false;
359 }
360 }
361 return false;
362 }
363 };
364}; // end of class
365} // end namespace itk
366
367#ifndef ITK_MANUAL_INSTANTIATION
368# include "itkShapeUniqueLabelMapFilter.hxx"
369#endif
370
371#endif
Control indentation during Print() invocation.
Definition itkIndent.h:50
Implements progress tracking for a filter.
bool operator()(const LineOfLabelObject &lla, const LineOfLabelObject &llb)
typename ImageType::IndexType IndexType
virtual void SetAttribute(AttributeType _arg)
typename ImageType::PixelType PixelType
void TemplatedGenerateData(const TAttributeAccessor &accessor)
void PrintSelf(std::ostream &os, Indent indent) const override
typename LabelObjectType::AttributeType AttributeType
typename ImageType::ConstPointer ImageConstPointer
typename LabelObjectType::LineType LineType
typename ImageType::LabelObjectType LabelObjectType
InPlaceLabelMapFilter< TImage > Superclass
~ShapeUniqueLabelMapFilter() override=default
static constexpr unsigned int ImageDimension
Implements transparent reference counting.
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:719
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
long OffsetValueType
Definition itkIntTypes.h:97
LineOfLabelObject(const LineType _line, LabelObjectType *_lo)