OTB  6.1.0
Orfeo Toolbox
otbLineDetectorImageFilterBase.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 otbLineDetectorImageFilterBase_txx
22 #define otbLineDetectorImageFilterBase_txx
23 
25 
26 #include "itkDataObject.h"
27 
31 #include "itkImageRegionIterator.h"
33 #include "itkProgressReporter.h"
34 #include "otbMacro.h"
35 #include "otbMath.h"
36 
37 namespace otb
38 {
39 
43 template <class TInputImage, class TOutputImage, class TOutputImageDirection, class InterpolatorType>
46 {
47  this->SetNumberOfRequiredOutputs(2);
48  this->SetNumberOfRequiredOutputs(1);
49  m_Radius.Fill(1);
50  m_LengthLine = 1;
51  m_WidthLine = 0;
52  m_Threshold = 0;
53  m_NumberOfDirections = 4;
54  m_FaceList.Fill(0);
55 // THOMAS : donc contructeur de base
56 // this->SetNthOutput(0, OutputImageType::New());
57 // this->SetNthOutput(1, OutputImageType::New());
58 }
60 
61 template <class TInputImage, class TOutputImage, class TOutputImageDirection, class InterpolatorType>
62 void
64 ::GenerateInputRequestedRegion() throw (itk::InvalidRequestedRegionError)
65  {
66  // call the superclass' implementation of this method
67  Superclass::GenerateInputRequestedRegion();
68 
69  // get pointers to the input and output
70  typename Superclass::InputImagePointer inputPtr = const_cast<TInputImage *>(this->GetInput());
71  typename Superclass::OutputImagePointer outputPtr = this->GetOutput();
72 
73  if (!inputPtr || !outputPtr)
74  {
75  return;
76  }
77 
78  // get a copy of the input requested region (should equal the output
79  // requested region)
80  typename TInputImage::RegionType inputRequestedRegion;
81  inputRequestedRegion = inputPtr->GetRequestedRegion();
82 
83  // Define the size of the region by the radius
84  m_Radius[1] = static_cast<unsigned int>(3 * (2 * m_WidthLine + 1) + 2);
85  m_Radius[0] = 2 * m_LengthLine + 1;
86 
87  // Define the size of the facelist by taking into account the rotation of the region
88  m_FaceList[0] =
89  static_cast<unsigned int>(vcl_sqrt(static_cast<double>(
90  (m_Radius[0] * m_Radius[0]) + (m_Radius[1] * m_Radius[1]))) + 1);
91  m_FaceList[1] = m_FaceList[0];
92 
93  otbMsgDevMacro(<< "Radius : " << m_Radius[0] << " " << m_Radius[1]);
94  otbMsgDevMacro(<< "-> FaceList : " << m_FaceList[0] << " " << m_FaceList[1]);
95 
96  // pad the input requested region by the operator radius
97  inputRequestedRegion.PadByRadius(m_FaceList);
98 
99  // crop the input requested region at the input's largest possible region
100  if (inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()))
101  {
102  inputPtr->SetRequestedRegion(inputRequestedRegion);
103  return;
104  }
105  else
106  {
107  // Couldn't crop the region (requested region is outside the largest
108  // possible region). Throw an exception.
109 
110  // store what we tried to request (prior to trying to crop)
111  inputPtr->SetRequestedRegion(inputRequestedRegion);
112 
113  // build an exception
114  itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
115  std::ostringstream msg;
116  msg << static_cast<const char *>(this->GetNameOfClass())
117  << "::GenerateInputRequestedRegion()";
118  e.SetLocation(msg.str().c_str());
119  e.SetDescription("Requested region is (at least partially) outside the largest possible region.");
120  e.SetDataObject(inputPtr);
121  throw e;
122  }
123  }
124 
125 /*
126  * Set up state of filter before multi-threading.
127  * InterpolatorType::SetInputImage is not thread-safe and hence
128  * has to be set up before ThreadedGenerateData
129  */
130 template <class TInputImage, class TOutputImage, class TOutputImageDirection, class InterpolatorType>
131 void
134 {
135  typename OutputImageType::Pointer output = this->GetOutput();
136  output->FillBuffer(0);
137  typename OutputImageType::Pointer outputDirection = this->GetOutputDirection();
138  outputDirection->FillBuffer(0);
139 }
140 
141 template <class TInputImage, class TOutputImage, class TOutputImageDirection, class InterpolatorType>
142 void
145  const OutputImageRegionType& outputRegionForThread,
146  itk::ThreadIdType threadId
147  )
148 {
149 
150  typename InputImageType::ConstPointer input = this->GetInput();
151 
152  InterpolatorPointer interpolator2 = InterpolatorType::New();
153  interpolator2->SetInputImage(input);
154 
160 
161  // Allocate output
162  typename OutputImageType::Pointer output = this->GetOutput();
163  typename OutputImageType::Pointer outputDir = this->GetOutputDirection();
164 
165  // Find the data-set boundary "faces"
168 
170  faceList = bC(input, outputRegionForThread, m_FaceList);
171 
172  // support progress methods/callbacks
173  itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels());
174 
175  typename TInputImage::IndexType bitIndex;
176  typename InterpolatorType::ContinuousIndexType Index;
177 
178  // --------------------------------------------------------------------------
179 
180  // Number of direction
181  const unsigned int NB_DIR = this->GetNumberOfDirections();
182  // Number of zone
183  const int NB_ZONE = 3;
184  // Definition of the 4 directions
185  //double Theta[NB_DIR];
186  //ROMAIN
187  double* Theta = new double[NB_DIR];
188 
189  // La rotation nulle correspond a un contour horizontal -> 0 !!
190  for (unsigned int i = 0; i < NB_DIR; ++i)
191  {
192  Theta[i] = (CONST_PI * (i / double(NB_DIR)));
193  /* if(Theta[i]>CONST_PI)
194  Theta[i] = Theta[i]-CONST_PI;
195  if((i/double(NB_DIR))==0.5)
196  Theta[i]=0.; */
197  }
198 
199  // Number of the zone
200  unsigned int zone;
201 
202  // Intensity of the linear feature
203  double R;
204 
205  // Direction of detection
206  double Direction = 0.;
207 
208  // Pixel location in the input image
209  int X, Y;
210 
211  // Pixel location after rotation in the system axis of the region
212  double xout, yout;
213 
214  // location of the central pixel in the input image
215  int Xc, Yc;
216 
217  // location of the central pixel between zone 1 and 2 and between zone 1 and 3
218  int Yc12, Yc13;
219 
220  //---------------------------------------------------------------------------
221  otbMsgDevMacro(<< "Theta : " << Theta[0] << " " << Theta[1] << " " << Theta[2] << " " << Theta[3]);
222 
223  // Process each of the boundary faces. These are N-d regions which border
224  // the edge of the buffer.
225 
226  //bool interiorFace = true;
227 
228  for (fit = faceList.begin(); fit != faceList.end(); ++fit)
229  {
230  bit = itk::ConstNeighborhoodIterator<InputImageType>(m_Radius, input, *fit);
231  cit = itk::ConstNeighborhoodIterator<InputImageType>(m_FaceList, input, *fit);
232 
234  itdir = itk::ImageRegionIterator<OutputImageType>(outputDir, *fit);
235 
236  bit.OverrideBoundaryCondition(&nbc);
237  bit.GoToBegin();
238  cit.OverrideBoundaryCondition(&nbc);
239  cit.GoToBegin();
240 
241  otbMsgDevMacro(<< " ------------------- FaceList --------------------------");
242 
243  while ((!bit.IsAtEnd()) && (!cit.IsAtEnd()))
244  {
245  InterpolatorPointer interpolator = InterpolatorType::New();
246  // Location of the central pixel of the region
247  off.Fill(0);
248  bitIndex = bit.GetIndex(off);
249  Xc = bitIndex[0];
250  Yc = bitIndex[1];
251 
252  // JULIEN : If the processed region is the center face
253  // the input image can be used for the interpolation
254  //if (interiorFace)
255  // {
256  // interpolator->SetInputImage(input);
257  // }
258  // else we must feed the interpolator with a partial image corresponding
259  // to the boundary conditions
260  //else
261  // {
262  typename InputImageType::RegionType tempRegion;
263  typename InputImageType::SizeType tempSize;
264  tempSize[0] = 2 * m_FaceList[0] + 1;
265  tempSize[1] = 2 * m_FaceList[1] + 1;
266  tempRegion.SetSize(tempSize);
268  tempIndex[0] = off[0] - m_FaceList[0];
269  tempIndex[1] = off[1] - m_FaceList[1];
270  tempRegion.SetIndex(cit.GetIndex(tempIndex));
271  typename InputImageType::Pointer tempImage = InputImageType::New();
272  tempImage->SetRegions(tempRegion);
273  tempImage->Allocate();
274 
275  for (unsigned int p = 0; p <= 2 * m_FaceList[0]; ++p)
276  {
277  for (unsigned int q = 0; q <= 2 * m_FaceList[1]; q++)
278  {
280  index[0] = p - m_FaceList[0];
281  index[1] = q - m_FaceList[1];
282  tempImage->SetPixel(cit.GetIndex(index), cit.GetPixel(index));
283  }
284  }
285  interpolator->SetInputImage(tempImage);
286  // }
287 
288  // Location of the central pixel between zone 1 and zone 2
289  Yc12 = Yc - m_WidthLine - 1;
290 
291  // Location of the central pixel between zone 1 and zone 3
292  Yc13 = Yc + m_WidthLine + 1;
293 
294  // Contains for the 4 directions the the pixels belonging to each zone
295  //std::vector<double> PixelValues[NB_DIR][NB_ZONE];
296  // ROMAIN
297  std::vector<double>** PixelValues = ITK_NULLPTR;
298  PixelValues = new std::vector<double>*[NB_DIR];
299  for (unsigned int i = 0; i < NB_DIR; ++i)
300  {
301  PixelValues[i] = ITK_NULLPTR;
302  PixelValues[i] = new std::vector<double>[NB_ZONE];
303  }
304  //otbMsgDevMacro( << "\tCentre Xc/Yc="<<Xc<<" "<<Yc<<" Yc12/Yc13="<<Yc12<<" "<<Yc13);
305  // Loop on the region
306  for (unsigned int i = 0; i < m_Radius[0]; ++i)
307  for (unsigned int j = 0; j < m_Radius[1]; ++j)
308  {
309 
310  off[0] = i - m_Radius[0] / 2;
311  off[1] = j - m_Radius[1] / 2;
312 
313  bitIndex = bit.GetIndex(off);
314  X = bitIndex[0];
315  Y = bitIndex[1];
316 
317  // We determine in the horizontal direction with which zone the pixel belongs.
318  if (Y < Yc12) zone = 1;
319  else if ((Yc12 < Y) && (Y < Yc13)) zone = 0;
320  else if (Y > Yc13) zone = 2;
321  else continue;
322  //otbMsgDevMacro( << "\t\tPoint traite (i, j)=("<<i<<","<<j<<") -> X, Y="<<X<<","<<Y<<" zone="<<zone);
323  // Loop on the directions
324  for (unsigned int dir = 0; dir < NB_DIR; ++dir)
325  {
326  //ROTATION( (X-Xc), (Y-Yc), Theta[dir], xout, yout);
327 
328  xout = (X - Xc) * vcl_cos(Theta[dir]) - (Y - Yc) * vcl_sin(Theta[dir]);
329  yout = (X - Xc) * vcl_sin(Theta[dir]) + (Y - Yc) * vcl_cos(Theta[dir]);
330 
331  Index[0] = static_cast<CoordRepType>(xout + Xc);
332  Index[1] = static_cast<CoordRepType>(yout + Yc);
333 
334  PixelValues[dir][zone].push_back(static_cast<double>(interpolator->EvaluateAtContinuousIndex(Index)));
335  }
336  } // end of the loop on the pixels of the region
337 
338  R = 0.;
339  Direction = 0.;
340 
341  // Loop on the 4 directions
342 
343  for (unsigned int dir = 0; dir < NB_DIR; ++dir)
344  {
345 
346  double Rtemp = this->ComputeMeasure(&PixelValues[dir][0], &PixelValues[dir][1], &PixelValues[dir][2]);
347 
348  if (Rtemp > R)
349  {
350  R = Rtemp;
351  Direction = Theta[dir];
352  }
353 
354  } // end of the loop on the directions
355 
356  //otbMsgDevMacro( << "\t\tR, Direction : "<<R<<","<<Direction);
357  if (R >= this->GetThreshold())
358  {
359 
360  // Assignment of this value to the output pixel
361  it.Set(static_cast<OutputPixelType>(R));
362 
363  // Assignment of this value to the "outputdir" pixel
364  itdir.Set(static_cast<OutputPixelType>(Direction));
365  }
366  else
367  {
368 
370 
371  itdir.Set(static_cast<OutputPixelType>(0));
372  }
373  ++bit;
374  ++cit;
375  ++it;
376  ++itdir;
377  //interiorFace = false;
378  progress.CompletedPixel();
379 
380  // ROMAIN
381  for (unsigned int i = 0; i < NB_DIR; ++i)
382  {
383  delete[] PixelValues[i];
384  PixelValues[i] = ITK_NULLPTR;
385  }
386  delete[] PixelValues;
387  PixelValues = ITK_NULLPTR;
388  }
389 
390  }
391  delete[] Theta;
392 }
393 
394 template <class TInputImage, class TOutputImage, class TOutputImageDirection, class InterpolatorType>
395 double
397 ::ComputeMeasure(std::vector<double>* itkNotUsed(m1), std::vector<double>* itkNotUsed(m2), std::vector<double>* itkNotUsed(m3))
398 {
399  return 0;
400 }
401 
405 template <class TInputImage, class TOutputImage, class TOutputImageDirection, class InterpolatorType>
406 void
408 ::PrintSelf(std::ostream& os, itk::Indent indent) const
409 {
410  Superclass::PrintSelf(os, indent);
411  os << indent << "Length: " << m_LengthLine << std::endl;
412  os << indent << "Width: " << m_WidthLine << std::endl;
414 
415 }
416 
417 } // end namespace otb
418 
419 #endif
virtual IndexType GetIndex(void) const
const double CONST_PI
Definition: otbMath.h:48
virtual bool IsAtEnd() const
itk::Size< Monteverdi_DIMENSION > SizeType
Definition: mvdTypes.h:146
void SetDataObject(DataObject *dobj)
virtual void SetDescription(const std::string &s)
virtual void SetLocation(const std::string &s)
void Set(const PixelType &value) const
virtual void OverrideBoundaryCondition(const ImageBoundaryConditionPointerType i)
void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, itk::ThreadIdType threadId) ITK_OVERRIDE
InterpolatorType::CoordRepType CoordRepType
itk::Index< Monteverdi_DIMENSION > IndexType
Definition: mvdTypes.h:142
virtual PixelType GetPixel(NeighborIndexType i, bool &IsInBounds) const
void Fill(OffsetValueType value)
void PrintSelf(std::ostream &os, itk::Indent indent) const ITK_OVERRIDE
virtual double ComputeMeasure(std::vector< double > *m1, std::vector< double > *m2, std::vector< double > *m3)
unsigned int ThreadIdType
OutputImageType::RegionType OutputImageRegionType
#define otbMsgDevMacro(x)
Definition: otbMacro.h:98