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
87 itkGetConstMacro(ReverseOrdering, bool);
88 itkSetMacro(ReverseOrdering, bool);
89 itkBooleanMacro(ReverseOrdering);
91
96 itkGetConstMacro(Attribute, AttributeType);
97 itkSetMacro(Attribute, AttributeType);
98 void
99 SetAttribute(const std::string & s)
100 {
101 this->SetAttribute(LabelObjectType::GetAttributeFromName(s));
102 }
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 bool keepCurrent;
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 if (Math::ExactlyEquals(attr, prevAttr))
204 {
205 if (l.labelObject->GetLabel() > prev.labelObject->GetLabel())
206 {
207 keepCurrent = !m_ReverseOrdering;
208 }
209 else
210 {
211 keepCurrent = m_ReverseOrdering;
212 }
213 }
214 else
215 {
216 if (attr > prevAttr)
217 {
218 keepCurrent = !m_ReverseOrdering;
219 }
220 else
221 {
222 keepCurrent = m_ReverseOrdering;
223 }
224 }
225
226 if (keepCurrent)
227 {
228 // keep the current one. We must truncate the previous one to remove
229 // the
230 // overlap, and take care of the end of the previous line if it
231 // extends
232 // after the current one.
233 if (prevIdx[0] + prevLength > idx[0] + length)
234 {
235 // the previous line is longer than the current one. Lets take its
236 // tail and
237 // add it to the priority queue
238 IndexType newIdx = idx;
239 newIdx[0] = idx[0] + length;
240 const OffsetValueType newLength = prevIdx[0] + prevLength - newIdx[0];
241 priorityQueue.push(LineOfLabelObject(LineType(newIdx, newLength), prev.labelObject));
242 }
243 // truncate the previous line to let some place for the current one
244 prevLength = idx[0] - prevIdx[0];
245 if (prevLength != 0)
246 {
247 assert(prevIdx[0] <= idx[0]);
248 lines.back().line.SetLength(idx[0] - prevIdx[0]);
249 }
250 else
251 {
252 // length is 0 - no need to keep that line
253 lines.pop_back();
254 }
255 // and push the current one
256 lines.push_back(l);
257 }
258 else
259 {
260 // keep the previous one. If the previous line fully overlap the
261 // current one,
262 // the current one is fully discarded.
263 if (prevIdx[0] + prevLength >= idx[0] + length)
264 {
265 // discarding the current line - just do nothing
266 }
267 else
268 {
269 IndexType newIdx = idx;
270 newIdx[0] = prevIdx[0] + prevLength;
271 const OffsetValueType newLength = idx[0] + length - newIdx[0];
272 if (newLength > 0)
273 {
274 l.line.SetIndex(newIdx);
275 l.line.SetLength(newLength);
276 // The front of this line is trimmed, it may occur after a line in the queue
277 // so the queue is used for the proper ordering.
278 priorityQueue.push(l);
279 }
280 }
281 }
282 }
283 else
284 {
285 // no overlap - things are just fine already
286 lines.push_back(l);
287 }
288 }
289
290 // store the current line as the previous one, and go to the next one.
291 prev = lines.back();
292 prevIdx = prev.line.GetIndex();
293 }
294
295 // put the lines in their object
296 for (size_t i = 0; i < lines.size(); ++i)
297 {
298 LineOfLabelObject & l = lines[i];
299 l.labelObject->AddLine(l.line);
300 }
301
302 // remove objects without lines
303 typename ImageType::Iterator it(this->GetLabelMap());
304 while (!it.IsAtEnd())
305 {
306 const typename LabelObjectType::LabelType label = it.GetLabel();
307 LabelObjectType * labelObject = it.GetLabelObject();
308
309 if (labelObject->Empty())
310 {
311 // must increment the iterator before removing the object to avoid
312 // invalidating the iterator
313 ++it;
314 this->GetLabelMap()->RemoveLabel(label);
315 }
316 else
317 {
318 ++it;
319 }
320 }
321 }
322
323 void
324 PrintSelf(std::ostream & os, Indent indent) const override;
325
327
328private:
331 {
332 using LineType = typename LabelObjectType::LineType;
334 {
335 this->line = _line;
336 this->labelObject = _lo;
337 }
338
341 };
342
344 {
345 public:
346 bool
348 {
349 for (int i = ImageDimension - 1; i >= 0; i--)
350 {
351 if (lla.line.GetIndex()[i] > llb.line.GetIndex()[i])
352 {
353 return true;
354 }
355 if (lla.line.GetIndex()[i] < llb.line.GetIndex()[i])
356 {
357 return false;
358 }
359 }
360 return false;
361 }
362 };
363}; // end of class
364} // end namespace itk
365
366#ifndef ITK_MANUAL_INSTANTIATION
367# include "itkShapeUniqueLabelMapFilter.hxx"
368#endif
369
370#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:720
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
long OffsetValueType
Definition itkIntTypes.h:97
LineOfLabelObject(const LineType _line, LabelObjectType *_lo)