22 #ifndef otbLabelImageSmallRegionMergingFilter_hxx
23 #define otbLabelImageSmallRegionMergingFilter_hxx
26 #include "itkConstShapedNeighborhoodIterator.h"
27 #include "itkProgressReporter.h"
31 template <
class TInputLabelImage>
36 template <
class TInputLabelImage>
39 m_LabelPopulation = labelPopulation;
42 for (
auto label : m_LabelPopulation)
44 m_LUT[label.first] = label.first;
48 template <
class TInputLabelImage>
52 return m_LabelPopulation;
56 template <
class TInputLabelImage>
59 m_LabelStatistic = labelStatistic;
62 template <
class TInputLabelImage>
66 return m_LabelStatistic;
69 template <
class TInputLabelImage>
76 template <
class TInputLabelImage>
79 m_NeighboursMapsTmp.clear();
80 m_NeighboursMapsTmp.resize(this->GetNumberOfThreads());
83 template <
class TInputLabelImage>
89 for (
unsigned int threadId = 0; threadId < this->GetNumberOfThreads(); threadId++)
91 for (
auto const& neighbours : m_NeighboursMapsTmp[threadId])
93 neighboursMap[neighbours.first].insert(neighbours.second.begin(), neighbours.second.end());
100 for (
auto const& neighbours : neighboursMap)
102 double proximity = itk::NumericTraits<double>::max();
105 auto const& statsLabel = m_LabelStatistic[label];
107 for (
auto const& neighbour : neighbours.second)
109 auto const& statsNeighbour = m_LabelStatistic[neighbour];
110 assert(statsLabel.Size() == statsNeighbour.Size());
112 double distance = (statsLabel - statsNeighbour).GetSquaredNorm();
113 if (distance < proximity)
115 proximity = distance;
116 closestNeighbour = neighbour;
120 auto curLabelLUT = FindCorrespondingLabel(label);
121 auto adjLabelLUT = FindCorrespondingLabel(closestNeighbour);
125 if (curLabelLUT < adjLabelLUT)
127 m_LUT[adjLabelLUT] = curLabelLUT;
131 m_LUT[curLabelLUT] = adjLabelLUT;
136 for (
auto& label : m_LUT)
138 label.second = FindCorrespondingLabel(label.first);
143 for (
auto const& label : m_LUT)
145 if ((label.second != label.first) && (m_LabelPopulation[label.first] != 0))
148 auto const& populationFirst = m_LabelPopulation[label.first];
149 auto const& populationSecond = m_LabelPopulation[label.second];
150 auto const& statisticFirst = m_LabelStatistic[label.first];
151 auto const& statisticSecond = m_LabelStatistic[label.second];
153 m_LabelStatistic[label.second] = ((statisticFirst * populationFirst) + (statisticSecond * populationSecond)) / (populationFirst + populationSecond);
155 m_LabelPopulation[label.second] += populationFirst;
158 m_LabelPopulation[label.first] = 0;
163 template <
class TInputLabelImage>
168 auto correspondingLabel = m_LUT[label];
169 while (label != correspondingLabel)
171 label = correspondingLabel;
172 correspondingLabel = m_LUT[correspondingLabel];
174 return correspondingLabel;
177 template <
class TInputLabelImage>
181 Superclass::GenerateInputRequestedRegion();
184 auto inputPtr =
const_cast<TInputLabelImage*
>(this->GetInput());
188 auto inputRequestedRegion = inputPtr->GetRequestedRegion();
191 inputRequestedRegion.PadByRadius(1);
193 if (inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()))
195 inputPtr->SetRequestedRegion(inputRequestedRegion);
204 inputPtr->SetRequestedRegion(inputRequestedRegion);
207 itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
208 e.SetLocation(ITK_LOCATION);
210 "Requested region is (at least partially) outside the "
211 "largest possible region.");
212 e.SetDataObject(inputPtr);
217 template <
class TInputLabelImage>
220 using IteratorType = itk::ImageRegionConstIterator<TInputLabelImage>;
221 using NeighborhoodIteratorType = itk::ConstShapedNeighborhoodIterator<TInputLabelImage>;
223 typename NeighborhoodIteratorType::RadiusType radius;
226 auto labelImage = this->GetInput();
228 IteratorType it(labelImage, outputRegionForThread);
229 NeighborhoodIteratorType itN(radius, labelImage, outputRegionForThread);
232 typename IteratorType::OffsetType top = {{0, -1}};
233 itN.ActivateOffset(top);
234 typename IteratorType::OffsetType bottom = {{0, 1}};
235 itN.ActivateOffset(bottom);
236 typename IteratorType::OffsetType right = {{1, 0}};
237 itN.ActivateOffset(right);
238 typename IteratorType::OffsetType left = {{-1, 0}};
239 itN.ActivateOffset(left);
241 for (it.GoToBegin(); !it.IsAtEnd(); ++it, ++itN)
243 assert(!itN.IsAtEnd());
244 int currentLabel = m_LUT[it.Get()];
246 if (m_LabelPopulation[currentLabel] == m_Size)
248 for (
auto ci = itN.Begin(); !ci.IsAtEnd(); ci++)
250 int neighbourLabel = m_LUT[ci.Get()];
251 if (neighbourLabel != currentLabel)
252 m_NeighboursMapsTmp[threadId][currentLabel].insert(neighbourLabel);
258 template <
class TInputLabelImage>
261 Superclass::PrintSelf(os, indent);
264 template <
class TInputLabelImage>
270 template <
class TInputLabelImage>
273 m_SmallRegionMergingFilter->GetFilter()->SetInput(labelImage);
276 template <
class TInputLabelImage>
279 m_SmallRegionMergingFilter->GetFilter()->SetLabelPopulation(labelPopulation);
282 template <
class TInputLabelImage>
286 return m_SmallRegionMergingFilter->GetFilter()->GetLabelPopulation();
289 template <
class TInputLabelImage>
292 m_SmallRegionMergingFilter->GetFilter()->SetLabelStatistic(labelStatistic);
295 template <
class TInputLabelImage>
299 return m_SmallRegionMergingFilter->GetFilter()->GetLabelStatistic();
302 template <
class TInputLabelImage>
305 return m_SmallRegionMergingFilter->GetFilter()->GetLUT();
308 template <
class TInputLabelImage>
311 this->GenerateData();
314 template <
class TInputLabelImage>
317 this->SetProgress(0.0);
320 for (
unsigned int size = 1; size < m_MinSize; size++)
322 m_SmallRegionMergingFilter->GetFilter()->SetSize(size);
323 m_SmallRegionMergingFilter->Update();
324 this->UpdateProgress(
static_cast<double>(size + 1) / m_MinSize);