22 #ifndef otbLabelImageSmallRegionMergingFilter_hxx
23 #define otbLabelImageSmallRegionMergingFilter_hxx
26 #include "itkConstShapedNeighborhoodIterator.h"
27 #include "itkProgressReporter.h"
31 template <
class TInputLabelImage>
34 this->DynamicMultiThreadingOff();
37 template <
class TInputLabelImage>
40 m_LabelPopulation = labelPopulation;
43 for (
auto label : m_LabelPopulation)
45 m_LUT[label.first] = label.first;
49 template <
class TInputLabelImage>
53 return m_LabelPopulation;
57 template <
class TInputLabelImage>
60 m_LabelStatistic = labelStatistic;
63 template <
class TInputLabelImage>
67 return m_LabelStatistic;
70 template <
class TInputLabelImage>
77 template <
class TInputLabelImage>
80 m_NeighboursMapsTmp.clear();
81 m_NeighboursMapsTmp.resize(this->GetNumberOfWorkUnits());
84 template <
class TInputLabelImage>
90 for (
unsigned int threadId = 0; threadId < this->GetNumberOfWorkUnits(); threadId++)
92 for (
auto const& neighbours : m_NeighboursMapsTmp[threadId])
94 neighboursMap[neighbours.first].insert(neighbours.second.begin(), neighbours.second.end());
101 for (
auto const& neighbours : neighboursMap)
103 double proximity = itk::NumericTraits<double>::max();
106 auto const& statsLabel = m_LabelStatistic[label];
108 for (
auto const& neighbour : neighbours.second)
110 auto const& statsNeighbour = m_LabelStatistic[neighbour];
111 assert(statsLabel.Size() == statsNeighbour.Size());
113 double distance = (statsLabel - statsNeighbour).GetSquaredNorm();
114 if (distance < proximity)
116 proximity = distance;
117 closestNeighbour = neighbour;
121 auto curLabelLUT = FindCorrespondingLabel(label);
122 auto adjLabelLUT = FindCorrespondingLabel(closestNeighbour);
126 if (curLabelLUT < adjLabelLUT)
128 m_LUT[adjLabelLUT] = curLabelLUT;
132 m_LUT[curLabelLUT] = adjLabelLUT;
137 for (
auto& label : m_LUT)
139 label.second = FindCorrespondingLabel(label.first);
144 for (
auto const& label : m_LUT)
146 if ((label.second != label.first) && (m_LabelPopulation[label.first] != 0))
149 auto const& populationFirst = m_LabelPopulation[label.first];
150 auto const& populationSecond = m_LabelPopulation[label.second];
151 auto const& statisticFirst = m_LabelStatistic[label.first];
152 auto const& statisticSecond = m_LabelStatistic[label.second];
154 m_LabelStatistic[label.second] = ((statisticFirst * populationFirst) + (statisticSecond * populationSecond)) / (populationFirst + populationSecond);
156 m_LabelPopulation[label.second] += populationFirst;
159 m_LabelPopulation[label.first] = 0;
164 template <
class TInputLabelImage>
169 auto correspondingLabel = m_LUT[label];
170 while (label != correspondingLabel)
172 label = correspondingLabel;
173 correspondingLabel = m_LUT[correspondingLabel];
175 return correspondingLabel;
178 template <
class TInputLabelImage>
182 Superclass::GenerateInputRequestedRegion();
185 auto inputPtr =
const_cast<TInputLabelImage*
>(this->GetInput());
189 auto inputRequestedRegion = inputPtr->GetRequestedRegion();
192 inputRequestedRegion.PadByRadius(1);
194 if (inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()))
196 inputPtr->SetRequestedRegion(inputRequestedRegion);
205 inputPtr->SetRequestedRegion(inputRequestedRegion);
208 itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
209 e.SetLocation(ITK_LOCATION);
211 "Requested region is (at least partially) outside the "
212 "largest possible region.");
213 e.SetDataObject(inputPtr);
218 template <
class TInputLabelImage>
221 using IteratorType = itk::ImageRegionConstIterator<TInputLabelImage>;
222 using NeighborhoodIteratorType = itk::ConstShapedNeighborhoodIterator<TInputLabelImage>;
224 typename NeighborhoodIteratorType::RadiusType radius;
227 auto labelImage = this->GetInput();
229 IteratorType it(labelImage, outputRegionForThread);
230 NeighborhoodIteratorType itN(radius, labelImage, outputRegionForThread);
233 typename IteratorType::OffsetType top = {{0, -1}};
234 itN.ActivateOffset(top);
235 typename IteratorType::OffsetType bottom = {{0, 1}};
236 itN.ActivateOffset(bottom);
237 typename IteratorType::OffsetType right = {{1, 0}};
238 itN.ActivateOffset(right);
239 typename IteratorType::OffsetType left = {{-1, 0}};
240 itN.ActivateOffset(left);
242 for (it.GoToBegin(); !it.IsAtEnd(); ++it, ++itN)
244 assert(!itN.IsAtEnd());
245 int currentLabel = m_LUT[it.Get()];
247 if (m_LabelPopulation[currentLabel] == m_Size)
249 for (
auto ci = itN.Begin(); !ci.IsAtEnd(); ci++)
251 int neighbourLabel = m_LUT[ci.Get()];
252 if (neighbourLabel != currentLabel)
253 m_NeighboursMapsTmp[threadId][currentLabel].insert(neighbourLabel);
259 template <
class TInputLabelImage>
262 Superclass::PrintSelf(os, indent);
265 template <
class TInputLabelImage>
271 template <
class TInputLabelImage>
274 m_SmallRegionMergingFilter->GetFilter()->SetInput(labelImage);
277 template <
class TInputLabelImage>
280 m_SmallRegionMergingFilter->GetFilter()->SetLabelPopulation(labelPopulation);
283 template <
class TInputLabelImage>
287 return m_SmallRegionMergingFilter->GetFilter()->GetLabelPopulation();
290 template <
class TInputLabelImage>
293 m_SmallRegionMergingFilter->GetFilter()->SetLabelStatistic(labelStatistic);
296 template <
class TInputLabelImage>
300 return m_SmallRegionMergingFilter->GetFilter()->GetLabelStatistic();
303 template <
class TInputLabelImage>
306 return m_SmallRegionMergingFilter->GetFilter()->GetLUT();
309 template <
class TInputLabelImage>
312 this->GenerateData();
315 template <
class TInputLabelImage>
318 this->SetProgress(0.0);
321 for (
unsigned int size = 1; size < m_MinSize; size++)
323 m_SmallRegionMergingFilter->GetFilter()->SetSize(size);
324 m_SmallRegionMergingFilter->Update();
325 this->UpdateProgress(
static_cast<double>(size + 1) / m_MinSize);
PersistentLabelImageSmallRegionMergingFilterType::LabelPopulationType LabelPopulationType
LUTType const & GetLUT() const
void GenerateData() override
PersistentLabelImageSmallRegionMergingFilterType::LabelStatisticType LabelStatisticType
LabelPopulationType const & GetLabelPopulation() const
LabelStatisticType const & GetLabelStatistic() const
LabelImageSmallRegionMergingFilterType::Pointer m_SmallRegionMergingFilter
void SetInputLabelImage(const TInputLabelImage *labelImage)
LabelImageSmallRegionMergingFilter()
void SetLabelStatistic(LabelStatisticType const &labelStatistic)
void SetLabelPopulation(LabelPopulationType const &labelPopulation)
PersistentLabelImageSmallRegionMergingFilterType::LUTType LUTType
void GenerateInputRequestedRegion() override
void SetLabelStatistic(LabelStatisticType const &labelStatistic)
void SetLabelPopulation(LabelPopulationType const &labelPopulation)
InputImageType::PixelType InputLabelType
std::unordered_map< InputLabelType, std::set< InputLabelType > > NeighboursMapType
void ThreadedGenerateData(const RegionType &outputRegionForThread, itk::ThreadIdType threadId) override
LabelStatisticType const & GetLabelStatistic() const
PersistentLabelImageSmallRegionMergingFilter()
LabelPopulationType const & GetLabelPopulation() const
std::unordered_map< InputLabelType, RealVectorPixelType > LabelStatisticType
std::unordered_map< InputLabelType, double > LabelPopulationType
InputLabelType FindCorrespondingLabel(InputLabelType label)
std::unordered_map< InputLabelType, InputLabelType > LUTType
InputImageType::RegionType RegionType
LUTType const & GetLUT() const
virtual void Reset(void) override
virtual void Synthetize(void) override
void PrintSelf(std::ostream &os, itk::Indent indent) const override
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.