OTB  6.7.0
Orfeo Toolbox
otbImageToEdgePathFilter.txx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
3  *
4  * This file is part of Orfeo Toolbox
5  *
6  * https://www.orfeo-toolbox.org/
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #ifndef otbImageToEdgePathFilter_txx
22 #define otbImageToEdgePathFilter_txx
23 
25 #include "otbMacro.h"
29 
30 namespace otb
31 {
32 /*
33  * Constructor.
34  */
35 template <class TInputImage, class TOutputPath>
38 {
39  m_ForegroundValue = PixelType(255);
40 }
44 template <class TInputImage, class TOutputPath>
45 void
48 {
49 
50  const InputImageType * inputImage = this->GetInput();
51  OutputPathType * outputPath = this->GetOutput();
52 
53  otbMsgDebugMacro(<< "Foreground value : " << m_ForegroundValue);
54 
55  PixelType initPadConstant(0);
56  if (initPadConstant == m_ForegroundValue)
57  {
58  initPadConstant = 1;
59  }
60 
64 
65  // Padding to deal with near the border objects.
66  typename PadFilterType::Pointer pad = PadFilterType::New();
67  pad->SetInput(inputImage);
68  pad->SetConstant(initPadConstant);
69  SizeType padSize;
70  padSize[ 0 ] = 1;
71  padSize[ 1 ] = 1;
72  pad->SetPadUpperBound(padSize);
73  pad->SetPadLowerBound(padSize);
74  pad->Update();
75  // Iterate on the image to get a starting point
76  LinearIteratorType linIter(pad->GetOutput(), pad->GetOutput()->GetLargestPossibleRegion());
77  linIter.GoToBegin();
78  bool flag = true;
79  while (flag && !linIter.IsAtEnd())
80  {
81  if (linIter.Get() == m_ForegroundValue)
82  {
83  flag = false;
84  }
85  else
86  {
87  ++linIter;
88  }
89  }
90  typename InputImageType::IndexType start = linIter.GetIndex();
91 // outputPath->AddVertex(start);
92 
93  // Neighborhood definition
94  typename IteratorType::RadiusType radius;
95  radius.Fill(1);
96  IteratorType it(radius, pad->GetOutput(), pad->GetOutput()->GetLargestPossibleRegion());
97  const typename IteratorType::OffsetType LEFT = {{-1, 0}};
98  const typename IteratorType::OffsetType RIGHT = {{1, 0}};
99  const typename IteratorType::OffsetType UP = {{0, -1}};
100  const typename IteratorType::OffsetType DOWN = {{0, 1}};
101  const typename IteratorType::OffsetType LEFTUP = {{-1, -1}};
102  const typename IteratorType::OffsetType RIGHTDOWN = {{1, 1}};
103  const typename IteratorType::OffsetType RIGHTUP = {{1, -1}};
104  const typename IteratorType::OffsetType LEFTDOWN = {{-1, 1}};
105  const typename IteratorType::OffsetType CENTER = {{0, 0}};
106  it.ClearActiveList();
107  it.ActivateOffset(LEFT);
108  it.ActivateOffset(RIGHT);
109  it.ActivateOffset(UP);
110  it.ActivateOffset(DOWN);
111  it.ActivateOffset(CENTER);
112  it.ActivateOffset(RIGHTUP);
113  it.ActivateOffset(RIGHTDOWN);
114  it.ActivateOffset(LEFTUP);
115  it.ActivateOffset(LEFTDOWN);
116  // The rotation vector allows getting the clock-wise next pixel
117  std::vector<typename IteratorType::OffsetType> rotation;
118  rotation.push_back(RIGHT);
119  rotation.push_back(RIGHTDOWN);
120  rotation.push_back(DOWN);
121  rotation.push_back(LEFTDOWN);
122  rotation.push_back(LEFT);
123  rotation.push_back(LEFTUP);
124  rotation.push_back(UP);
125  rotation.push_back(RIGHTUP);
126  // Set up the iterator
127  it.SetLocation(start);
128 
129  ContinuousIndexType newVertex = it.GetIndex(CENTER);
130  if (it.GetPixel(RIGHT) == m_ForegroundValue) newVertex[0] -= 0.5;
131  if (it.GetPixel(LEFT) == m_ForegroundValue) newVertex[0] += 0.5;
132  if (it.GetPixel(UP) == m_ForegroundValue) newVertex[1] += 0.5;
133  if (it.GetPixel(DOWN) == m_ForegroundValue) newVertex[1] -= 0.5;
134  outputPath->AddVertex(newVertex);
135 
136  otbMsgDebugMacro(<< "START: " << start);
137  // stopping flag
138  flag = true;
139  int nbMove = 0;
140  // nexstart gives a clue of where to begin searching in next step of the search
141  int nextStart = 0;
142  // While the search has not eended
143  while (flag)
144  {
145  // move is used to walk the neighnorhood clock-wise
146  int move = nextStart;
147  // edgeFound indicate that the edge has been found.
148  bool EdgeFound = false;
149  // LastWasPositive indicate whether the previous pixel belong to the object or not
150  bool LastWasPositive(false);
151  // While unexplored pixels remain and no edge was found
152  while ((move < nextStart + 8) && (!EdgeFound))
153  {
154  //otbMsgDevMacro(<<"SEARCH: "<<move%8<<" "<<it.GetPixel(rotation[move%8])<<" LAST: "<<LastWasPositive);
155  // If last pixel was not in the object and the current is, we have found the edge
156  if ((!LastWasPositive) && (it.GetPixel(rotation[move % 8]) == m_ForegroundValue))
157  {
158  EdgeFound = true;
159  }
160  else
161  {
162  // Else goes on
163  LastWasPositive = (it.GetPixel(rotation[move % 8]) == m_ForegroundValue);
164  move++;
165  }
166  }
167  // Once the search has been completed, if an edge pixel was found
168  if (EdgeFound)
169  {
170  // Update the output path
171  it += rotation[move % 8];
172  nextStart = (move + 5) % 8;
173  newVertex = it.GetIndex(CENTER);
174  if (it.GetPixel(RIGHT) == m_ForegroundValue) newVertex[0] -= 0.5;
175  if (it.GetPixel(LEFT) == m_ForegroundValue) newVertex[0] += 0.5;
176  if (it.GetPixel(UP) == m_ForegroundValue) newVertex[1] += 0.5;
177  if (it.GetPixel(DOWN) == m_ForegroundValue) newVertex[1] -= 0.5;
178  outputPath->AddVertex(newVertex);
179  otbMsgDebugMacro(<< newVertex);
180  // If we came back to our start point after a sufficient number of moves
181  if ((it.GetIndex(CENTER) == start) && (nbMove >= 2))
182  {
183  // search end
184  flag = false;
185  }
186  else
187  {
188  // else
189  for (int i = 0; i < 8; ++i)
190  {
191  // If we came back near our starting pointer after a sufficient number of moves
192  if ((it.GetIndex(rotation[i]) == start) && (nbMove >= 2))
193  {
194  // search end
195  flag = false;
196  }
197  }
198  }
199  }
200  // else
201  else
202  {
203  // search ended, no pixel can be added to the edge path.
204  flag = false;
205  }
206  nbMove++;
207  }
208 }
209 template <class TInputImage, class TOutputPath>
210 void
212 ::PrintSelf(std::ostream& os, itk::Indent indent) const
213 {
214  Superclass::PrintSelf(os, indent);
215  os << "Foreground value : " << m_ForegroundValue << std::endl;
216 }
217 } // end namespace otb
218 
219 #endif
InputImageType::SizeType SizeType
InputImageType::PixelType PixelType
Superclass::InputImageType InputImageType
Template parameters typedef.
itk::Index< Monteverdi_DIMENSION > IndexType
Definition: mvdTypes.h:142
#define otbMsgDebugMacro(x)
Definition: otbMacro.h:64
OutputPathType::ContinuousIndexType ContinuousIndexType
TOutputPath OutputPathType
void PrintSelf(std::ostream &os, itk::Indent indent) const override