1 /*=========================================================================
2 *
3 * Copyright Insight Software Consortium
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 * http://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 /*=========================================================================
19 *
20 * Portions of this file are subject to the VTK Toolkit Version 3 copyright.
21 *
22 * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
23 *
24 * For complete copyright, license and disclaimer of warranty information
25 * please refer to the NOTICE file at the top of the ITK source tree.
26 *
27 *=========================================================================*/
28 #ifndef itkLabelMap_hxx
29 #define itkLabelMap_hxx
30
31 #include "itkLabelMap.h"
32 #include "itkProcessObject.h"
33
34 #include <algorithm>
35
36 namespace itk
37 {
38
39 template< typename TLabelObject >
40 LabelMap< TLabelObject >
LabelMap()41 ::LabelMap()
42 {
43 m_BackgroundValue = NumericTraits< LabelType >::ZeroValue();
44 this->Initialize();
45 }
46
47
48 template< typename TLabelObject >
49 void
50 LabelMap< TLabelObject >
PrintSelf(std::ostream & os,Indent indent) const51 ::PrintSelf(std::ostream & os, Indent indent) const
52 {
53 Superclass::PrintSelf(os, indent);
54
55 os << indent << "BackgroundValue: "
56 << static_cast< typename NumericTraits< LabelType >::PrintType >( m_BackgroundValue ) << std::endl;
57 os << indent << "LabelObjectContainer: " << &m_LabelObjectContainer << std::endl;
58 }
59
60
61 template< typename TLabelObject >
62 void
63 LabelMap< TLabelObject >
Initialize()64 ::Initialize()
65 {
66 this->ClearLabels();
67 }
68
69
70 template< typename TLabelObject >
71 void
72 LabelMap< TLabelObject >
Allocate(bool)73 ::Allocate(bool)
74 {
75 this->Initialize();
76 }
77
78
79 template< typename TLabelObject >
80 void
81 LabelMap< TLabelObject >
Graft(const Self * imgData)82 ::Graft(const Self *imgData)
83 {
84 if(imgData == nullptr)
85 {
86 return; // nothing to do
87 }
88 // call the superclass' implementation
89 Superclass::Graft(imgData);
90
91 // Now copy anything remaining that is needed
92 if( &m_LabelObjectContainer != &(imgData->m_LabelObjectContainer) )
93 {
94 m_LabelObjectContainer.clear();
95 LabelObjectContainerType newLabelObjectContainer( imgData->m_LabelObjectContainer );
96 std::swap( m_LabelObjectContainer, newLabelObjectContainer );
97 }
98 m_BackgroundValue = imgData->m_BackgroundValue;
99 }
100
101 template< typename TLabelObject >
102 void
103 LabelMap< TLabelObject >
Graft(const DataObject * data)104 ::Graft(const DataObject *data)
105 {
106 if(data == nullptr)
107 {
108 return; // nothing to do
109 }
110
111 // Attempt to cast data to an Image
112 const auto * imgData = dynamic_cast< const Self * >( data );
113
114 if ( imgData == nullptr )
115 {
116 // pointer could not be cast back down
117 itkExceptionMacro( << "itk::LabelMap::Graft() cannot cast "
118 << typeid( data ).name() << " to "
119 << typeid( const Self * ).name() );
120 }
121 this->Graft(imgData);
122 }
123
124
125 template< typename TLabelObject >
126 typename LabelMap< TLabelObject >::LabelObjectType *
127 LabelMap< TLabelObject >
GetLabelObject(const LabelType & label)128 ::GetLabelObject(const LabelType & label)
129 {
130 if ( m_BackgroundValue == label )
131 {
132 itkExceptionMacro(<< "Label "
133 << static_cast< typename NumericTraits< LabelType >::PrintType >( label )
134 << " is the background label.");
135 }
136 auto it = m_LabelObjectContainer.find( label );
137 if ( it == m_LabelObjectContainer.end() )
138 {
139 itkExceptionMacro(<< "No label object with label "
140 << static_cast< typename NumericTraits< LabelType >::PrintType >( label )
141 << ".");
142 }
143
144 return it->second;
145 }
146
147
148 template< typename TLabelObject >
149 const typename LabelMap< TLabelObject >::LabelObjectType *
150 LabelMap< TLabelObject >
GetLabelObject(const LabelType & label) const151 ::GetLabelObject(const LabelType & label) const
152 {
153 if ( m_BackgroundValue == label )
154 {
155 itkExceptionMacro(<< "Label "
156 << static_cast< typename NumericTraits< LabelType >::PrintType >( label )
157 << " is the background label.");
158 }
159 auto it = m_LabelObjectContainer.find( label );
160 if ( it == m_LabelObjectContainer.end() )
161 {
162 itkExceptionMacro(<< "No label object with label "
163 << static_cast< typename NumericTraits< LabelType >::PrintType >( label )
164 << ".");
165 }
166
167 return it->second;
168 }
169
170
171 template< typename TLabelObject >
172 bool
173 LabelMap< TLabelObject >
HasLabel(const LabelType label) const174 ::HasLabel(const LabelType label) const
175 {
176 return m_LabelObjectContainer.find(label) != m_LabelObjectContainer.end();
177 }
178
179
180 template< typename TLabelObject >
181 const typename LabelMap< TLabelObject >::LabelType &
182 LabelMap< TLabelObject >
GetPixel(const IndexType & idx) const183 ::GetPixel(const IndexType & idx) const
184 {
185 auto end = m_LabelObjectContainer.end();
186
187 for ( auto it = m_LabelObjectContainer.begin();
188 it != end;
189 ++it )
190 {
191 if ( it->second->HasIndex(idx) )
192 {
193 return it->second->GetLabel();
194 }
195 }
196 return m_BackgroundValue;
197 }
198
199
200 template< typename TLabelObject >
201 typename LabelMap< TLabelObject >::LabelObjectType *
202 LabelMap< TLabelObject >
GetNthLabelObject(const SizeValueType & pos)203 ::GetNthLabelObject(const SizeValueType & pos)
204 {
205 SizeValueType i = 0;
206
207 for ( auto it = m_LabelObjectContainer.begin();
208 it != m_LabelObjectContainer.end();
209 it++ )
210 {
211 if ( i == pos )
212 {
213 return it->second;
214 }
215 i++;
216 }
217 itkExceptionMacro(<< "Can't access to label object at position "
218 << pos
219 << ". The label map has only "
220 << this->GetNumberOfLabelObjects()
221 << " label objects registered.");
222 }
223
224
225 template< typename TLabelObject >
226 const typename LabelMap< TLabelObject >::LabelObjectType *
227 LabelMap< TLabelObject >
GetNthLabelObject(const SizeValueType & pos) const228 ::GetNthLabelObject(const SizeValueType & pos) const
229 {
230 SizeValueType i = 0;
231
232 for ( LabelObjectContainerConstIterator it = m_LabelObjectContainer.begin();
233 it != m_LabelObjectContainer.end();
234 it++ )
235 {
236 if ( i == pos )
237 {
238 return it->second;
239 }
240 i++;
241 }
242 itkExceptionMacro(<< "Can't access to label object at position "
243 << pos
244 << ". The label map has only "
245 << this->GetNumberOfLabelObjects()
246 << " label objects registered.");
247 }
248
249
250 template< typename TLabelObject >
251 void
252 LabelMap< TLabelObject >
SetPixel(const IndexType & idx,const LabelType & iLabel)253 ::SetPixel(const IndexType & idx, const LabelType & iLabel )
254 {
255 bool newLabel = true; // or can be initialized by ( iLabel == m_BackgroundValue )
256
257 auto it = m_LabelObjectContainer.begin();
258
259 while( it != m_LabelObjectContainer.end() )
260 {
261 // increment the iterator before removing the pixel because
262 // RemovePixel() can remove the object and thus invalidate the
263 // iterator
264 if( it->first != iLabel )
265 {
266 auto tempIt = it;
267 ++it;
268 bool emitModifiedEvent = ( iLabel == m_BackgroundValue );
269 this->RemovePixel( tempIt, idx, emitModifiedEvent );
270 }
271 else
272 {
273 newLabel = false;
274 this->AddPixel( it, idx, iLabel );
275 ++it;
276 }
277 }
278 if( newLabel )
279 {
280 this->AddPixel( m_LabelObjectContainer.end(), idx, iLabel );
281 }
282 }
283
284
285 template< typename TLabelObject >
286 void
287 LabelMap< TLabelObject >
AddPixel(const IndexType & idx,const LabelType & label)288 ::AddPixel(const IndexType & idx, const LabelType & label)
289 {
290 if ( label == m_BackgroundValue )
291 {
292 // just do nothing
293 return;
294 }
295
296 LabelObjectContainerIterator it = m_LabelObjectContainer.find(label);
297
298 this->AddPixel( it, idx, label );
299 }
300
301
302 template< typename TLabelObject >
303 void
304 LabelMap< TLabelObject >
AddPixel(const LabelObjectContainerIterator & it,const IndexType & idx,const LabelType & label)305 ::AddPixel(const LabelObjectContainerIterator & it,
306 const IndexType & idx,
307 const LabelType & label )
308 {
309 if ( label == m_BackgroundValue )
310 {
311 // just do nothing
312 return;
313 }
314
315 if ( it != m_LabelObjectContainer.end() )
316 {
317 // the label already exist - add the pixel to it
318 ( *it ).second->AddIndex(idx);
319 this->Modified();
320 }
321 else
322 {
323 // the label does not exist yet - create a new one
324 LabelObjectPointerType labelObject = LabelObjectType::New();
325 labelObject->SetLabel(label);
326 labelObject->AddIndex(idx);
327 // Modified() is called in AddLabelObject()
328 this->AddLabelObject(labelObject);
329 }
330 }
331
332
333 template< typename TLabelObject >
334 void
335 LabelMap< TLabelObject >
RemovePixel(const LabelObjectContainerIterator & it,const IndexType & idx,bool iEmitModifiedEvent)336 ::RemovePixel(const LabelObjectContainerIterator & it,
337 const IndexType & idx,
338 bool iEmitModifiedEvent )
339 {
340 if ( it != m_LabelObjectContainer.end() )
341 {
342 // the label already exist - add the pixel to it
343 if( it->second->RemoveIndex(idx) )
344 {
345 if( it->second->Empty() )
346 {
347 this->RemoveLabelObject(it->second);
348 }
349 if( iEmitModifiedEvent )
350 {
351 this->Modified();
352 }
353 }
354 }
355 }
356
357
358 template< typename TLabelObject >
359 void
360 LabelMap< TLabelObject >
RemovePixel(const IndexType & idx,const LabelType & label)361 ::RemovePixel(const IndexType & idx, const LabelType & label)
362 {
363 if ( label == m_BackgroundValue )
364 {
365 // just do nothing
366 return;
367 }
368
369 LabelObjectContainerIterator it = m_LabelObjectContainer.find(label);
370
371 bool emitModifiedEvent = true;
372 RemovePixel( it, idx, emitModifiedEvent );
373 }
374
375
376 template< typename TLabelObject >
377 void
378 LabelMap< TLabelObject >
SetLine(const IndexType & idx,const LengthType & length,const LabelType & label)379 ::SetLine(const IndexType & idx, const LengthType & length, const LabelType & label)
380 {
381 if ( label == m_BackgroundValue )
382 {
383 // just do nothing
384 return;
385 }
386
387 auto it = m_LabelObjectContainer.find(label);
388
389 if ( it != m_LabelObjectContainer.end() )
390 {
391 // the label already exist - add the pixel to it
392 ( *it ).second->AddLine(idx, length);
393 this->Modified();
394 }
395 else
396 {
397 // the label does not exist yet - create a new one
398 LabelObjectPointerType labelObject = LabelObjectType::New();
399 labelObject->SetLabel(label);
400 labelObject->AddLine(idx, length);
401 // Modified() is called in AddLabelObject()
402 this->AddLabelObject(labelObject);
403 }
404 }
405
406
407 template< typename TLabelObject >
408 typename LabelMap< TLabelObject >::LabelObjectType *
409 LabelMap< TLabelObject >
GetLabelObject(const IndexType & idx) const410 ::GetLabelObject(const IndexType & idx) const
411 {
412 for ( auto it = m_LabelObjectContainer.begin();
413 it != m_LabelObjectContainer.end();
414 it++ )
415 {
416 if ( it->second->HasIndex(idx) )
417 {
418 return it->second.GetPointer();
419 }
420 }
421 itkExceptionMacro(<< "No label object at index " << idx << ".");
422 // return nullptr;
423 }
424
425
426 template< typename TLabelObject >
427 void
428 LabelMap< TLabelObject >
AddLabelObject(LabelObjectType * labelObject)429 ::AddLabelObject(LabelObjectType *labelObject)
430 {
431 itkAssertOrThrowMacro( ( labelObject != nullptr ), "Input LabelObject can't be Null" );
432
433 m_LabelObjectContainer[labelObject->GetLabel()] = labelObject;
434 this->Modified();
435 }
436
437
438 template< typename TLabelObject >
439 void
440 LabelMap< TLabelObject >
PushLabelObject(LabelObjectType * labelObject)441 ::PushLabelObject(LabelObjectType *labelObject)
442 {
443 itkAssertOrThrowMacro( ( labelObject != nullptr ), "Input LabelObject can't be Null" );
444
445 if ( m_LabelObjectContainer.empty() )
446 {
447 if ( m_BackgroundValue == 0 )
448 {
449 labelObject->SetLabel(1);
450 }
451 else
452 {
453 labelObject->SetLabel(0);
454 }
455 }
456 else
457 {
458 LabelType lastLabel = m_LabelObjectContainer.rbegin()->first;
459 LabelType firstLabel = m_LabelObjectContainer.begin()->first;
460 if ( lastLabel != NumericTraits< LabelType >::max() && lastLabel + 1 != m_BackgroundValue )
461 {
462 labelObject->SetLabel(lastLabel + 1);
463 }
464 else if ( lastLabel != NumericTraits< LabelType >::max() && lastLabel + 1 != NumericTraits< LabelType >::max()
465 && lastLabel + 2 != m_BackgroundValue )
466 {
467 labelObject->SetLabel(lastLabel + 2);
468 }
469 else if ( firstLabel != NumericTraits< LabelType >::NonpositiveMin() && firstLabel - 1 != m_BackgroundValue )
470 {
471 labelObject->SetLabel(firstLabel - 1);
472 }
473 else
474 {
475 // search for an unused label
476 LabelType label = firstLabel;
477 LabelObjectContainerConstIterator it;
478 for ( it = m_LabelObjectContainer.begin();
479 it != m_LabelObjectContainer.end();
480 it++, label++ )
481 {
482 assert( ( it->second.IsNotNull() ) );
483 if ( label == m_BackgroundValue )
484 {
485 label++;
486 }
487 if ( label != it->first )
488 {
489 labelObject->SetLabel(label);
490 break;
491 }
492 }
493 if ( label == lastLabel )
494 {
495 itkExceptionMacro(<< "Can't push the label object: the label map is full.");
496 }
497 }
498 }
499 // modified is called in AddLabelObject()
500 this->AddLabelObject(labelObject);
501 }
502
503
504 template< typename TLabelObject >
505 void
506 LabelMap< TLabelObject >
RemoveLabelObject(LabelObjectType * labelObject)507 ::RemoveLabelObject(LabelObjectType *labelObject)
508 {
509 itkAssertOrThrowMacro( ( labelObject != nullptr ), "Input LabelObject can't be Null" );
510 // modified is called in RemoveLabel()
511 this->RemoveLabel( labelObject->GetLabel() );
512 }
513
514
515 template< typename TLabelObject >
516 void
517 LabelMap< TLabelObject >
RemoveLabel(const LabelType & label)518 ::RemoveLabel(const LabelType & label)
519 {
520 if ( m_BackgroundValue == label )
521 {
522 itkExceptionMacro(<< "Label "
523 << static_cast< typename NumericTraits< LabelType >::PrintType >( label )
524 << " is the background label.");
525 }
526 m_LabelObjectContainer.erase(label);
527 this->Modified();
528 }
529
530
531 template< typename TLabelObject >
532 void
533 LabelMap< TLabelObject >
ClearLabels()534 ::ClearLabels()
535 {
536 if ( !m_LabelObjectContainer.empty() )
537 {
538 m_LabelObjectContainer.clear();
539 this->Modified();
540 }
541 }
542
543
544 template< typename TLabelObject >
545 typename LabelMap< TLabelObject >::SizeValueType
546 LabelMap< TLabelObject >
GetNumberOfLabelObjects() const547 ::GetNumberOfLabelObjects() const
548 {
549 return static_cast<typename LabelMap< TLabelObject >::SizeValueType>( m_LabelObjectContainer.size() );
550 }
551
552
553 template< typename TLabelObject >
554 typename LabelMap< TLabelObject >::LabelVectorType
555 LabelMap< TLabelObject >
GetLabels() const556 ::GetLabels() const
557 {
558 LabelVectorType res;
559
560 res.reserve( this->GetNumberOfLabelObjects() );
561 for ( auto it = m_LabelObjectContainer.begin();
562 it != m_LabelObjectContainer.end();
563 it++ )
564 {
565 res.push_back(it->first);
566 }
567 return res;
568 }
569
570
571 template< typename TLabelObject >
572 typename LabelMap< TLabelObject >::LabelObjectVectorType
573 LabelMap< TLabelObject >
GetLabelObjects() const574 ::GetLabelObjects() const
575 {
576 LabelObjectVectorType res;
577
578 res.reserve( this->GetNumberOfLabelObjects() );
579 for ( auto it = m_LabelObjectContainer.begin();
580 it != m_LabelObjectContainer.end();
581 it++ )
582 {
583 res.push_back(it->second);
584 }
585 return res;
586 }
587
588
589 template< typename TLabelObject >
590 void
591 LabelMap< TLabelObject >
PrintLabelObjects(std::ostream & os) const592 ::PrintLabelObjects(std::ostream & os) const
593 {
594 for ( auto it = m_LabelObjectContainer.begin();
595 it != m_LabelObjectContainer.end();
596 it++ )
597 {
598 assert( ( it->second.IsNotNull() ) );
599 it->second->Print(os);
600 os << std::endl;
601 }
602 }
603
604
605 template< typename TLabelObject >
606 void
607 LabelMap< TLabelObject >
Optimize()608 ::Optimize()
609 {
610 for ( LabelObjectContainerConstIterator it = m_LabelObjectContainer.begin();
611 it != m_LabelObjectContainer.end();
612 it++ )
613 {
614 assert( ( it->second.IsNotNull() ) );
615 it->second->Optimize();
616 }
617 this->Modified();
618 }
619
620 } // end namespace itk
621
622 #endif
623