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 #ifndef itkMergeLabelMapFilter_hxx
19 #define itkMergeLabelMapFilter_hxx
20 
21 #include "itkMergeLabelMapFilter.h"
22 #include "itkProgressReporter.h"
23 #include <deque>
24 
25 namespace itk
26 {
27 template< typename TImage >
28 MergeLabelMapFilter< TImage >
MergeLabelMapFilter()29 ::MergeLabelMapFilter()
30 {
31   this->m_Method = KEEP;
32 }
33 
34 template< typename TImage >
35 void
36 MergeLabelMapFilter< TImage >
GenerateData()37 ::GenerateData()
38 {
39   // Allocate the output
40   this->AllocateOutputs();
41 
42   switch ( this->m_Method )
43     {
44     case KEEP:
45       {
46       this->MergeWithKeep();
47       break;
48       }
49     case AGGREGATE:
50       {
51       this->MergeWithAggregate();
52       break;
53       }
54     case PACK:
55       {
56       this->MergeWithPack();
57       break;
58       }
59     case STRICT:
60       {
61       this->MergeWithStrict();
62       break;
63       }
64     default:
65       {
66       itkExceptionMacro(<< "No such method: " << this->m_Method);
67       }
68     }
69 }
70 
71 template< typename TImage >
72 void
73 MergeLabelMapFilter< TImage >
MergeWithKeep()74 ::MergeWithKeep()
75 {
76   ImageType *output = this->GetOutput();
77 
78   using VectorType = std::deque< LabelObjectPointer >;
79   VectorType labelObjects;
80 
81   ProgressReporter progress(this, 0, 1);
82 
83   for ( unsigned int i = 1; i < this->GetNumberOfIndexedInputs(); i++ )
84     {
85     typename ImageType::ConstIterator it2( this->GetInput(i) );
86     while ( ! it2.IsAtEnd() )
87       {
88       const LabelObjectType *lo = it2.GetLabelObject();
89       LabelObjectPointer     newLo = LabelObjectType::New();
90       newLo->template CopyAllFrom<LabelObjectType>(lo);
91 
92       if( ( output->GetBackgroundValue() != newLo->GetLabel() ) &&
93           ( !output->HasLabel( newLo->GetLabel() ) ) )
94         {
95         // we can keep the label
96         output->AddLabelObject(newLo);
97         }
98       else
99         {
100         // store the label object to read it later with another label
101         labelObjects.push_back(newLo);
102         }
103 
104       // go to the next label
105       progress.CompletedPixel();
106       ++it2;
107       }
108 
109     // add the other label objects, with a different label
110     auto it = labelObjects.begin();
111     while ( it != labelObjects.end() )
112       {
113       output->PushLabelObject(*it);
114       ++it;
115       }
116     }
117 }
118 
119 template< typename TImage >
120 void
121 MergeLabelMapFilter< TImage >
MergeWithStrict()122 ::MergeWithStrict()
123 {
124   ImageType *output = this->GetOutput();
125 
126   ProgressReporter progress(this, 0, 1);
127 
128   for ( unsigned int i = 1; i < this->GetNumberOfIndexedInputs(); i++ )
129     {
130     typename ImageType::ConstIterator it2( this->GetInput(i) );
131     while ( ! it2.IsAtEnd() )
132       {
133       const LabelObjectType *lo = it2.GetLabelObject();
134       LabelObjectPointer     newLo = LabelObjectType::New();
135       newLo->template CopyAllFrom<LabelObjectType>(lo);
136 
137       if ( output->GetBackgroundValue() != newLo->GetLabel() )
138         {
139         if ( !output->HasLabel( newLo->GetLabel() ) )
140           {
141           // we can keep the label
142           output->AddLabelObject(newLo);
143           }
144         else
145           {
146           itkExceptionMacro(<< "Label "
147                             << static_cast< typename itk::NumericTraits< PixelType >::PrintType >( newLo->GetLabel() )
148                             << " from input " << i
149                             << " is already in use.");
150           }
151         }
152       else
153         {
154         itkGenericExceptionMacro(<<"Label "
155                             << static_cast< typename itk::NumericTraits< PixelType >::PrintType >( newLo->GetLabel() )
156                             << " from input " << i
157                             << " is output background value.");
158         }
159 
160       // go to the next label
161       progress.CompletedPixel();
162       ++it2;
163       }
164     }
165 }
166 
167 template< typename TImage >
168 void
169 MergeLabelMapFilter< TImage >
MergeWithAggregate()170 ::MergeWithAggregate()
171 {
172   ImageType *output = this->GetOutput();
173 
174   ProgressReporter progress(this, 0, 1);
175 
176   for ( unsigned int i = 1; i < this->GetNumberOfIndexedInputs(); i++ )
177     {
178     typename ImageType::ConstIterator it2( this->GetInput(i) );
179     while ( ! it2.IsAtEnd() )
180       {
181       const LabelObjectType *lo = it2.GetLabelObject();
182 
183       bool hasLabel = output->HasLabel( lo->GetLabel() );
184       if ( !hasLabel && ( lo->GetLabel() != output->GetBackgroundValue() ) )
185         {
186         // we can keep the label
187         LabelObjectPointer newLo = LabelObjectType::New();
188         newLo->template CopyAllFrom<LabelObjectType>(lo);
189         output->AddLabelObject(newLo);
190         }
191       else
192         {
193         if ( hasLabel )
194           {
195           // add the lines of that object to the one already in the output
196           LabelObjectType *         mainLo = output->GetLabelObject( lo->GetLabel() );
197           typename LabelObjectType::ConstLineIterator lit( lo );
198           while ( ! lit.IsAtEnd() )
199             {
200             mainLo->AddLine( lit.GetLine() );
201             ++lit;
202             }
203 
204           // be sure to have the lines well organized
205           mainLo->Optimize();
206           }
207         }
208 
209       // go to the next label
210       progress.CompletedPixel();
211       ++it2;
212       }
213     }
214 }
215 
216 template< typename TImage >
217 void
218 MergeLabelMapFilter< TImage >
MergeWithPack()219 ::MergeWithPack()
220 {
221   ProgressReporter progress(this, 0, 1);
222 
223   ImageType *output = this->GetOutput();
224 
225   // get the label objects of the first input
226   typename ImageType::LabelObjectVectorType labelObjects = output->GetLabelObjects();
227 
228   // and put back the objects in the map
229   output->ClearLabels();
230 
231   auto it = labelObjects.begin();
232 
233   while ( it != labelObjects.end() )
234     {
235     output->PushLabelObject(*it);
236 
237     // go to the next label
238     progress.CompletedPixel();
239     it++;
240     }
241 
242   // now, the next images
243   for ( unsigned int i = 1; i < this->GetNumberOfIndexedInputs(); i++ )
244     {
245     typename ImageType::ConstIterator it2( this->GetInput(i) );
246     while ( ! it2.IsAtEnd() )
247       {
248       const LabelObjectType *lo = it2.GetLabelObject();
249       LabelObjectPointer     newLo = LabelObjectType::New();
250       newLo->template CopyAllFrom<LabelObjectType>(lo);
251       output->PushLabelObject(newLo);
252 
253       // go to the next label
254       progress.CompletedPixel();
255       ++it2;
256       }
257     }
258 }
259 
260 template< typename TImage >
261 void
262 MergeLabelMapFilter< TImage >
PrintSelf(std::ostream & os,Indent indent) const263 ::PrintSelf(std::ostream & os, Indent indent) const
264 {
265   Superclass::PrintSelf(os, indent);
266 
267   os << indent << "Method: "  << this->m_Method << std::endl;
268 }
269 } // end namespace itk
270 #endif
271