OTB  9.0.0
Orfeo Toolbox
otbLabelImageToLabelMapWithAdjacencyFilter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1999-2011 Insight Software Consortium
3  * Copyright (C) 2005-2022 Centre National d'Etudes Spatiales (CNES)
4  *
5  * This file is part of Orfeo Toolbox
6  *
7  * https://www.orfeo-toolbox.org/
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 #ifndef otbLabelImageToLabelMapWithAdjacencyFilter_hxx
23 #define otbLabelImageToLabelMapWithAdjacencyFilter_hxx
24 
26 #include "itkNumericTraits.h"
27 #include "itkProgressReporter.h"
28 #include "itkImageLinearConstIteratorWithIndex.h"
29 #include "itkImageRegionConstIteratorWithIndex.h"
30 
31 namespace otb
32 {
33 
34 template <class TInputImage, class TOutputImage>
36 {
37  m_BackgroundValue = itk::NumericTraits<OutputImagePixelType>::NonpositiveMin();
38 }
39 
40 template <class TInputImage, class TOutputImage>
42 {
43  for (unsigned int idx = 0; idx < this->GetNumberOfInputs(); ++idx)
44  {
45  InputImagePointer input = const_cast<InputImageType*>(this->GetInput(idx));
46  if (!input.IsNull())
47  {
48  input->SetRequestedRegionToLargestPossibleRegion();
49  // Check whether the input is an image of the appropriate
50  // dimension (use ProcessObject's version of the GetInput()
51  // method since it returns the input as a pointer to a
52  // DataObject as opposed to the subclass version which
53  // static_casts the input to an TInputImage).
54 
55  // Use the function object RegionCopier to copy the output region
56  // to the input. The default region copier has default implementations
57  // to handle the cases where the input and output are the same
58  // dimension, the input a higher dimension than the output, and the
59  // input a lower dimension than the output.
60  InputImageRegionType inputRegion;
61  this->CallCopyOutputRegionToInputRegion(inputRegion, this->GetOutput()->GetRequestedRegion());
62  input->SetRequestedRegion(inputRegion);
63  }
64  }
65 }
66 
67 
68 template <class TInputImage, class TOutputImage>
70 {
71 }
72 
73 
74 template <class TInputImage, class TOutputImage>
76 {
77  // init the temp images - one per thread
78  m_TemporaryImages.resize(this->GetNumberOfThreads());
79  // Clear previous adjacency map
80  m_TemporaryAdjacencyMaps.resize(this->GetNumberOfThreads());
81 
82  for (unsigned int i = 0; i < this->GetNumberOfThreads(); ++i)
83  {
84  if (i == 0)
85  {
86  // the first one is the output image
87  m_TemporaryImages[0] = this->GetOutput();
88  }
89  else
90  {
91  // the other must be created
92  m_TemporaryImages[i] = OutputImageType::New();
93  }
94 
95  // set the minimum data needed to create the objects properly
96  m_TemporaryImages[i]->SetBackgroundValue(m_BackgroundValue);
97  }
98 }
99 
100 
101 template <class TInputImage, class TOutputImage>
103 {
104  // Insert label1 in v neighbors
105  if (m_TemporaryAdjacencyMaps[threadId].find(label2) != m_TemporaryAdjacencyMaps[threadId].end())
106  {
107  m_TemporaryAdjacencyMaps[threadId][label2].insert(label1);
108  }
109  else
110  {
111  AdjacentLabelsContainerType newContainer;
112  newContainer.insert(label1);
113  m_TemporaryAdjacencyMaps[threadId][label2] = newContainer;
114  }
115  // Insert label2 in label1s neighbors
116  if (m_TemporaryAdjacencyMaps[threadId].find(label1) != m_TemporaryAdjacencyMaps[threadId].end())
117  {
118  m_TemporaryAdjacencyMaps[threadId][label1].insert(label2);
119  }
120  else
121  {
122  AdjacentLabelsContainerType newContainer;
123  newContainer.insert(label2);
124  m_TemporaryAdjacencyMaps[threadId][label1] = newContainer;
125  }
126 }
127 
128 template <class TInputImage, class TOutputImage>
130 {
131  // Get the first label
132  typename RLEVectorType::const_iterator it = line.begin();
133  LabelType previousLabel = it->label;
134  ++it;
135 
136  // Iterates on remaining RLE
137  while (it != line.end())
138  {
139  // Get the new label
140  LabelType nextLabel = it->label;
141 
142  // Add the adjacency
143  this->AddAdjacency(previousLabel, nextLabel, threadId);
144 
145  // Store previous label
146  previousLabel = nextLabel;
147  ++it;
148  }
149 }
150 
151 template <class TInputImage, class TOutputImage>
153  itk::ThreadIdType threadId)
154 {
155  // Provided to disable fully connected if needed
156  long offset = 1;
157 
158  // Iterate on line1
159  for (typename RLEVectorType::const_iterator it1 = line1.begin(); it1 != line1.end(); ++it1)
160  {
161  // Delimitate RLE1
162  long start1 = it1->where[0];
163  long end1 = start1 + it1->length - 1;
164  LabelType label1 = it1->label;
165 
166  // Iterate on line2
167  for (typename RLEVectorType::const_iterator it2 = line2.begin(); it2 != line2.end(); ++it2)
168  {
169  // Delimitate RLE2
170  long start2 = it2->where[0];
171  long end2 = start2 + it2->length - 1;
172  LabelType label2 = it2->label;
173 
174  // If labels are different
175  if (label1 != label2)
176  {
177  // Check adjacency
178  if (((start1 >= start2 - offset) && (start1 <= end2 + offset)) || ((end1 >= start2 - offset) && (end1 <= end2 + offset)) ||
179  ((start2 >= start1 - offset) && (start2 <= end1 + offset)) || ((end2 >= start1 - offset) && (end2 <= end1 + offset)))
180  {
181  // Add the adjacency
182  this->AddAdjacency(label1, label2, threadId);
183  }
184  }
185  }
186  }
187 }
188 
189 template <class TInputImage, class TOutputImage>
191  itk::ThreadIdType threadId)
192 {
193  itk::ProgressReporter progress(this, threadId, regionForThread.GetNumberOfPixels());
194 
195  typedef itk::ImageLinearConstIteratorWithIndex<InputImageType> InputLineIteratorType;
196 
197  InputLineIteratorType it(this->GetInput(), regionForThread);
198  it.SetDirection(0);
199 
200  RLEVectorType currentLine;
201  RLEVectorType previousLine;
202 
203  // Parse previous line if exists
204  typename InputImageType::RegionType previousLineRegion;
205  typename InputImageType::SizeType previousLineRegionSize;
206  typename InputImageType::IndexType previousLineRegionIndex;
207 
208  previousLineRegionIndex = regionForThread.GetIndex();
209  previousLineRegionIndex[1]--;
210 
211  previousLineRegionSize = regionForThread.GetSize();
212  previousLineRegionSize[1] = 1;
213 
214  previousLineRegion.SetIndex(previousLineRegionIndex);
215  previousLineRegion.SetSize(previousLineRegionSize);
216 
217  // If previous line is still in image
218  if (previousLineRegion.Crop(this->GetInput()->GetRequestedRegion()))
219  {
220  // Build an iterator
221  itk::ImageRegionConstIteratorWithIndex<InputImageType> pIt(this->GetInput(), previousLineRegion);
222  pIt.GoToBegin();
223 
224  // Iterate on line
225  while (!pIt.IsAtEnd())
226  {
227  const InputImagePixelType& v = pIt.Get();
228 
229  if (v != m_BackgroundValue)
230  {
231  // We've hit the start of a run
232  IndexType idx = pIt.GetIndex();
233  long length = 1;
234  ++pIt;
235  while (!pIt.IsAtEnd() && pIt.Get() == v)
236  {
237  ++length;
238  ++pIt;
239  }
240  previousLine.push_back(RLE(idx, length, v));
241  }
242  else
243  {
244  // go the the next pixel
245  ++pIt;
246  }
247  }
248  }
249 
250  for (it.GoToBegin(); !it.IsAtEnd(); it.NextLine())
251  {
252  // Go to beginning of line
253  it.GoToBeginOfLine();
254 
255  // Clear the previous current line
256  currentLine.clear();
257 
258  // Iterate on line
259  while (!it.IsAtEndOfLine())
260  {
261  const InputImagePixelType& v = it.Get();
262 
263  if (v != m_BackgroundValue)
264  {
265  // We've hit the start of a run
266  IndexType idx = it.GetIndex();
267  long length = 1;
268  ++it;
269  while (!it.IsAtEndOfLine() && it.Get() == v)
270  {
271  ++length;
272  ++it;
273  }
274  // create the run length object to go in the vector
275  m_TemporaryImages[threadId]->SetLine(idx, length, v);
276  currentLine.push_back(RLE(idx, length, v));
277  }
278  else
279  {
280  // go the the next pixel
281  ++it;
282  }
283  }
284 
285  // if no label object is present on current line we skip the process
286  if (currentLine.size() > 0)
287  {
288  // Parse lines for adjacency
289  this->ParseLine(currentLine, threadId);
290  this->ParseConsecutiveLines(previousLine, currentLine, threadId);
291  }
292 
293  // Store previous line
294  previousLine = currentLine;
295  }
296 }
297 
298 
299 template <class TInputImage, class TOutputImage>
301 {
302 
303  OutputImageType* output = this->GetOutput();
304 
305  // merge the lines from the temporary images in the output image
306  // don't use the first image - that's the output image
307  for (unsigned int i = 1; i < this->GetNumberOfThreads(); ++i)
308  {
309  typedef typename OutputImageType::LabelObjectVectorType LabelObjectVectorType;
310  const LabelObjectVectorType& labelObjectContainer = m_TemporaryImages[i]->GetLabelObjects();
311 
312  for (typename LabelObjectVectorType::const_iterator it = labelObjectContainer.begin(); it != labelObjectContainer.end(); ++it)
313  {
314  LabelObjectType* labelObject = *it;
315  if (output->HasLabel(labelObject->GetLabel()))
316  {
317  // merge the lines in the output's object
318  // ITKv4 iterate over the 2 LabelObjects src and output
319  typedef typename LabelObjectType::ConstLineIterator IteratorType;
320 
321  typename LabelObjectType::LabelObjectType* dest = output->GetLabelObject(labelObject->GetLabel());
322 
323  IteratorType srcIt;
324  srcIt = IteratorType(labelObject);
325  srcIt.GoToBegin();
326 
327  // ITKv4 Iterate over all lines of the source and add them to the
328  // output labelObject (can use the insert method over the
329  // container anymore (it is now private)
330  while (!srcIt.IsAtEnd())
331  {
332  dest->AddLine(srcIt.GetLine());
333  ++srcIt;
334  }
335  }
336  else
337  {
338  // simply take the object
339  output->AddLabelObject(labelObject);
340  }
341  }
342  }
343 
344  // Merge adjacency tables
345  AdjacencyMapType adjMap = m_TemporaryAdjacencyMaps[0];
346 
347  // For each remaining thread
348  for (itk::ThreadIdType threadId = 1; threadId < this->GetNumberOfThreads(); ++threadId)
349  {
350  // For each label in the thread adjacency map
351  for (typename AdjacencyMapType::const_iterator mit = m_TemporaryAdjacencyMaps[threadId].begin(); mit != m_TemporaryAdjacencyMaps[threadId].end(); ++mit)
352  {
353  // If the label exists in the main map
354  if (adjMap.find(mit->first) != adjMap.end())
355  {
356  // We need to merge
357  AdjacentLabelsContainerType adjLabels1 = adjMap[mit->first];
358  AdjacentLabelsContainerType adjLabels2 = mit->second;
359  std::vector<LabelType> mergedLabels(adjLabels1.size() + adjLabels2.size(), 0);
360 
361  // Merge
362  typename std::vector<LabelType>::const_iterator vend =
363  set_union(adjLabels1.begin(), adjLabels1.end(), adjLabels2.begin(), adjLabels2.end(), mergedLabels.begin());
364 
365  AdjacentLabelsContainerType mergedLabelsSet;
366 
367  for (typename std::vector<LabelType>::const_iterator vit = mergedLabels.begin(); vit != vend; ++vit)
368  {
369  mergedLabelsSet.insert(*vit);
370  }
371 
372  // Set the final result
373  adjMap[mit->first] = mergedLabelsSet;
374  }
375  else
376  {
377  // Set the labels
378  adjMap[mit->first] = mit->second;
379  }
380  }
381  }
382 
383  // Set the adjacency map to the output
384  output->SetAdjacencyMap(adjMap);
385 
386  // release the data in the temp images
387  m_TemporaryImages.clear();
388  m_TemporaryAdjacencyMaps.clear();
389 }
390 
391 
392 template <class TInputImage, class TOutputImage>
394 {
395  Superclass::PrintSelf(os, indent);
396 
397  os << indent << "BackgroundValue: " << static_cast<typename itk::NumericTraits<OutputImagePixelType>::PrintType>(m_BackgroundValue) << std::endl;
398 }
399 
400 } // end namespace otb
401 #endif
otb::LabelImageToLabelMapWithAdjacencyFilter::AfterThreadedGenerateData
void AfterThreadedGenerateData() override
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.hxx:300
otb::LabelImageToLabelMapWithAdjacencyFilter::OutputImageRegionType
OutputImageType::RegionType OutputImageRegionType
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.h:59
otb::LabelImageToLabelMapWithAdjacencyFilter::GenerateInputRequestedRegion
void GenerateInputRequestedRegion() override
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.hxx:41
otb::LabelImageToLabelMapWithAdjacencyFilter::InputImageRegionType
InputImageType::RegionType InputImageRegionType
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.h:53
otb::LabelImageToLabelMapWithAdjacencyFilter::RLEVectorType
std::vector< RLE > RLEVectorType
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.h:119
otb::LabelImageToLabelMapWithAdjacencyFilter::OutputImageType
TOutputImage OutputImageType
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.h:50
otb::LabelImageToLabelMapWithAdjacencyFilter::ThreadedGenerateData
void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, itk::ThreadIdType threadId) override
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.hxx:190
otb::find
string_view find(string_view const &haystack, string_view const &needle)
Definition: otbStringUtilities.h:305
otb::LabelImageToLabelMapWithAdjacencyFilter::AddAdjacency
void AddAdjacency(LabelType label1, LabelType label2, itk::ThreadIdType threadId)
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.hxx:102
otb::LabelImageToLabelMapWithAdjacencyFilter::AdjacencyMapType
OutputImageType::AdjacencyMapType AdjacencyMapType
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.h:62
otb
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
Definition: otbJoinContainer.h:32
otb::LabelImageToLabelMapWithAdjacencyFilter::IndexType
InputImageType::IndexType IndexType
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.h:55
otb::LabelImageToLabelMapWithAdjacencyFilter::PrintSelf
void PrintSelf(std::ostream &os, itk::Indent indent) const override
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.hxx:393
otb::LabelImageToLabelMapWithAdjacencyFilter::InputImageType
TInputImage InputImageType
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.h:49
otb::LabelImageToLabelMapWithAdjacencyFilter::LabelType
OutputImageType::LabelType LabelType
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.h:64
otb::LabelImageToLabelMapWithAdjacencyFilter::BeforeThreadedGenerateData
void BeforeThreadedGenerateData() override
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.hxx:75
otb::LabelImageToLabelMapWithAdjacencyFilter::LabelObjectType
OutputImageType::LabelObjectType LabelObjectType
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.h:61
otb::LabelImageToLabelMapWithAdjacencyFilter::EnlargeOutputRequestedRegion
void EnlargeOutputRequestedRegion(itk::DataObject *) override
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.hxx:69
otbLabelImageToLabelMapWithAdjacencyFilter.h
otb::LabelImageToLabelMapWithAdjacencyFilter::InputImagePixelType
InputImageType::PixelType InputImagePixelType
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.h:54
otb::LabelImageToLabelMapWithAdjacencyFilter::AdjacentLabelsContainerType
OutputImageType::AdjacentLabelsContainerType AdjacentLabelsContainerType
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.h:63
otb::LabelImageToLabelMapWithAdjacencyFilter::ParseConsecutiveLines
void ParseConsecutiveLines(const RLEVectorType &line1, const RLEVectorType &line2, itk::ThreadIdType threadId)
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.hxx:152
otb::LabelImageToLabelMapWithAdjacencyFilter::LabelImageToLabelMapWithAdjacencyFilter
LabelImageToLabelMapWithAdjacencyFilter()
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.hxx:35
otb::LabelImageToLabelMapWithAdjacencyFilter::RLE
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.h:99
otb::LabelImageToLabelMapWithAdjacencyFilter::InputImagePointer
InputImageType::Pointer InputImagePointer
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.h:51
otb::LabelImageToLabelMapWithAdjacencyFilter::ParseLine
void ParseLine(const RLEVectorType &line, itk::ThreadIdType threadId)
Definition: otbLabelImageToLabelMapWithAdjacencyFilter.hxx:129