ChangeDetectionFrameworkExample.cxx 8.81 KB
Newer Older
Patrick Imbo's avatar
nomsg  
Patrick Imbo committed
1 2 3 4 5 6 7 8 9 10 11 12
/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$


  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.


13 14
     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
Patrick Imbo's avatar
nomsg  
Patrick Imbo committed
15 16 17
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
18

Jordi Inglada's avatar
Jordi Inglada committed
19 20 21 22 23 24

// Software Guide : BeginLatex
//
// This example illustrates the Change Detector framework implemented
// in OTB. This framework uses the generic programming approach. All
// change detection filters are
25
// \doxygen{otb}{BinaryFunctorNeighborhoodImageFilter}s, that is, they
Jordi Inglada's avatar
Jordi Inglada committed
26 27
// are filters taking two images as input and providing one image as
// output. The change detection computation itself is performed on a
28
// the neighborhood of each pixel of the input images.
Jordi Inglada's avatar
Jordi Inglada committed
29 30
//
// The first step required to build a change detection filter is to
31
// include the header of the parent class.
Jordi Inglada's avatar
Jordi Inglada committed
32
//
33
// Software Guide : EndLatex
Jordi Inglada's avatar
Jordi Inglada committed
34 35 36 37 38 39 40

// Software Guide : BeginCodeSnippet
#include "otbBinaryFunctorNeighborhoodImageFilter.h"
// Software Guide : EndCodeSnippet

#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
41
#include "itkUnaryFunctorImageFilter.h"
Jordi Inglada's avatar
Jordi Inglada committed
42
#include "itkRescaleIntensityImageFilter.h"
43
#include "otbImage.h"
Jordi Inglada's avatar
Jordi Inglada committed
44 45 46 47 48 49 50 51 52 53
#include "otbCommandProgressUpdate.h"

// Software Guide : BeginLatex
//
// The change
// detection operation itself is one of the templates of the change
// detection filters and takes the form of a function, that is,
// something accepting the syntax \code{foo()}. This can be
// implemented using classical C/C++ functions, but it is preferable
// to implement it using C++ functors. These are classical C++ classes
54
// which overload the \code{()} operator. This allows using them with
Jordi Inglada's avatar
Jordi Inglada committed
55 56
// the same syntax as C/C++ functions.
//
Emmanuel Christophe's avatar
typo  
Emmanuel Christophe committed
57
// Since change detectors operate on neighborhoods, the functor
Jordi Inglada's avatar
Jordi Inglada committed
58
// call will take 2 arguments which are
59
// \doxygen{itk}{ConstNeighborhoodIterator}s.
Jordi Inglada's avatar
Jordi Inglada committed
60 61 62 63 64
//
// The change detector functor is templated over the types of the
// input iterators and the output result type. The core of the change
// detection is implemented in the \code{operator()} section.
//
65
// Software Guide : EndLatex
Jordi Inglada's avatar
Jordi Inglada committed
66

67
// Software Guide : BeginCodeSnippet
OTB Bot's avatar
STYLE  
OTB Bot committed
68
template<class TInput1, class TInput2, class TOutput>
Jordi Inglada's avatar
Jordi Inglada committed
69 70 71 72
class MyChangeDetector
{
public:
  // The constructor and destructor.
OTB Bot's avatar
STYLE  
OTB Bot committed
73 74
  MyChangeDetector() {}
  ~MyChangeDetector() {}
Jordi Inglada's avatar
Jordi Inglada committed
75
  // Change detection operation
OTB Bot's avatar
STYLE  
OTB Bot committed
76 77
  inline TOutput operator ()(const TInput1& itA,
                             const TInput2& itB)
Jordi Inglada's avatar
Jordi Inglada committed
78
  {
79

Jordi Inglada's avatar
Jordi Inglada committed
80 81
    TOutput result = 0.0;

OTB Bot's avatar
STYLE  
OTB Bot committed
82 83
    for (unsigned long pos = 0; pos < itA.Size(); ++pos)
      {
84

OTB Bot's avatar
STYLE  
OTB Bot committed
85
      result += static_cast<TOutput>(itA.GetPixel(pos) - itB.GetPixel(pos));
Jordi Inglada's avatar
Jordi Inglada committed
86

OTB Bot's avatar
STYLE  
OTB Bot committed
87 88
      }
    return static_cast<TOutput>(result / itA.Size());
Jordi Inglada's avatar
Jordi Inglada committed
89
  }
90 91
};
// Software Guide : EndCodeSnippet
Jordi Inglada's avatar
Jordi Inglada committed
92 93 94 95 96 97 98 99 100 101

// Software Guide : BeginLatex
//
// The interest of using functors is that complex operations can be
// performed using internal \code{protected} class methods and that
// class variables can be used to store information so different pixel
// locations can access to results of previous computations.
//
// The next step is the definition of the change detector filter. As
// stated above, this filter will inherit from
102
// \doxygen{otb}{BinaryFunctorNeighborhoodImageFilter} which is
Jordi Inglada's avatar
Jordi Inglada committed
103 104 105
// templated over the 2 input image types, the output image type and
// the functor used to perform the change detection operation.
//
Emmanuel Christophe's avatar
typo  
Emmanuel Christophe committed
106
// Inside the class only a few \code{typedef}s and the constructors
Jordi Inglada's avatar
Jordi Inglada committed
107 108 109 110
// and destructors have to be declared.
//
// Software Guide : EndLatex

111
// Software Guide : BeginCodeSnippet
Jordi Inglada's avatar
Jordi Inglada committed
112 113
template <class TInputImage1, class TInputImage2, class TOutputImage>
class ITK_EXPORT MyChangeDetectorImageFilter :
OTB Bot's avatar
STYLE  
OTB Bot committed
114
  public otb::BinaryFunctorNeighborhoodImageFilter<
OTB Bot's avatar
STYLE  
OTB Bot committed
115 116 117 118 119
      TInputImage1, TInputImage2, TOutputImage,
      MyChangeDetector<
          typename itk::ConstNeighborhoodIterator<TInputImage1>,
          typename itk::ConstNeighborhoodIterator<TInputImage2>,
          typename TOutputImage::PixelType> >
Jordi Inglada's avatar
Jordi Inglada committed
120 121 122
{
public:
  /** Standard class typedefs. */
OTB Bot's avatar
STYLE  
OTB Bot committed
123 124
  typedef MyChangeDetectorImageFilter Self;

Jordi Inglada's avatar
Jordi Inglada committed
125
  typedef typename otb::BinaryFunctorNeighborhoodImageFilter<
OTB Bot's avatar
STYLE  
OTB Bot committed
126 127 128 129 130 131
      TInputImage1, TInputImage2, TOutputImage,
      MyChangeDetector<
          typename itk::ConstNeighborhoodIterator<TInputImage1>,
          typename itk::ConstNeighborhoodIterator<TInputImage2>,
          typename TOutputImage::PixelType>
      >  Superclass;
OTB Bot's avatar
STYLE  
OTB Bot committed
132 133 134

  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;
Jordi Inglada's avatar
Jordi Inglada committed
135 136 137

  /** Method for creation through the object factory. */
  itkNewMacro(Self);
138

Jordi Inglada's avatar
Jordi Inglada committed
139 140
protected:
  MyChangeDetectorImageFilter() {}
141
  ~MyChangeDetectorImageFilter() override {}
Jordi Inglada's avatar
Jordi Inglada committed
142 143

private:
OTB Bot's avatar
STYLE  
OTB Bot committed
144 145
  MyChangeDetectorImageFilter(const Self &); //purposely not implemented
  void operator =(const Self&); //purposely not implemented
Jordi Inglada's avatar
Jordi Inglada committed
146 147

};
148
// Software Guide : EndCodeSnippet
Jordi Inglada's avatar
Jordi Inglada committed
149 150 151 152 153

// Software Guide : BeginLatex
//
// Pay attention to the fact that no \code{.txx} file is needed, since
// filtering operation is implemented in the
154
// \doxygen{otb}{BinaryFunctorNeighborhoodImageFilter} class. So all
Jordi Inglada's avatar
Jordi Inglada committed
155 156 157 158 159 160
// the algorithmics part is inside the functor.
//
// We can now write a program using the change detector.
//
// SoftwareGuide : EndLatex

OTB Bot's avatar
STYLE  
OTB Bot committed
161
int main(int argc, char* argv[])
Jordi Inglada's avatar
Jordi Inglada committed
162 163
{

OTB Bot's avatar
STYLE  
OTB Bot committed
164 165
  if (argc < 5)
    {
Jordi Inglada's avatar
Jordi Inglada committed
166
    std::cerr << "Usage: " << std::endl;
OTB Bot's avatar
STYLE  
OTB Bot committed
167 168
    std::cerr << argv[0] <<
    " inputImageFile1 inputImageFile2  radius outputImageFile " << std::endl;
Jordi Inglada's avatar
Jordi Inglada committed
169
    return -1;
OTB Bot's avatar
STYLE  
OTB Bot committed
170
    }
Jordi Inglada's avatar
Jordi Inglada committed
171 172 173 174 175 176 177 178 179 180 181 182

  // Define the dimension of the images
  const unsigned int Dimension = 2;

  // Software Guide : BeginLatex
  //
  // As usual, we start by defining the image types. The internal
  // computations will be performed with floating point precision,
  // while the output image will be stored using one byte per pixel.
  //
  // SoftwareGuide : EndLatex

183
  // Software Guide : BeginCodeSnippet
OTB Bot's avatar
STYLE  
OTB Bot committed
184 185 186 187 188 189
  typedef float                                    InternalPixelType;
  typedef unsigned char                            OutputPixelType;
  typedef otb::Image<InternalPixelType, Dimension> InputImageType1;
  typedef otb::Image<InternalPixelType, Dimension> InputImageType2;
  typedef otb::Image<InternalPixelType, Dimension> ChangeImageType;
  typedef otb::Image<OutputPixelType, Dimension>   OutputImageType;
Jordi Inglada's avatar
Jordi Inglada committed
190 191 192 193 194
  // Software Guide : EndCodeSnippet

  // Software Guide : BeginLatex
  //
  // We declare the readers, the writer, but also the
195
  // \doxygen{itk}{RescaleIntensityImageFilter} which will be used to
Jordi Inglada's avatar
Jordi Inglada committed
196 197 198 199
  // rescale the result before writing it to a file.
  //
  // SoftwareGuide : EndLatex

200
  // Software Guide : BeginCodeSnippet
OTB Bot's avatar
STYLE  
OTB Bot committed
201 202 203 204
  typedef otb::ImageFileReader<InputImageType1> ReaderType1;
  typedef otb::ImageFileReader<InputImageType2> ReaderType2;
  typedef otb::ImageFileWriter<OutputImageType> WriterType;
  typedef itk::RescaleIntensityImageFilter<ChangeImageType,
OTB Bot's avatar
STYLE  
OTB Bot committed
205
      OutputImageType> RescalerType;
206
  // Software Guide : EndCodeSnippet
Jordi Inglada's avatar
Jordi Inglada committed
207 208 209 210 211 212 213

  // Software Guide : BeginLatex
  //
  // The next step is declaring the filter for the change detection.
  //
  // SoftwareGuide : EndLatex

214
  // Software Guide : BeginCodeSnippet
OTB Bot's avatar
STYLE  
OTB Bot committed
215 216
  typedef MyChangeDetectorImageFilter<InputImageType1, InputImageType2,
      ChangeImageType>      FilterType;
217 218
  // Software Guide : EndCodeSnippet

OTB Bot's avatar
STYLE  
OTB Bot committed
219 220 221
  ReaderType1::Pointer  reader1 = ReaderType1::New();
  ReaderType2::Pointer  reader2 = ReaderType2::New();
  WriterType::Pointer   writer = WriterType::New();
Jordi Inglada's avatar
Jordi Inglada committed
222 223 224 225 226 227 228 229 230 231 232 233 234
  FilterType::Pointer   filter = FilterType::New();
  RescalerType::Pointer rescaler = RescalerType::New();

  const char * inputFilename1  = argv[1];
  const char * inputFilename2  = argv[2];
  const char * outputFilename = argv[4];

  // Software Guide : BeginLatex
  //
  // We connect the pipeline.
  //
  // SoftwareGuide : EndLatex

235
  // Software Guide : BeginCodeSnippet
OTB Bot's avatar
STYLE  
OTB Bot committed
236 237 238 239 240 241 242 243 244 245 246 247
  reader1->SetFileName(inputFilename1);
  reader2->SetFileName(inputFilename2);
  writer->SetFileName(outputFilename);
  rescaler->SetOutputMinimum(itk::NumericTraits<OutputPixelType>::min());
  rescaler->SetOutputMaximum(itk::NumericTraits<OutputPixelType>::max());

  filter->SetInput1(reader1->GetOutput());
  filter->SetInput2(reader2->GetOutput());
  filter->SetRadius(atoi(argv[3]));

  rescaler->SetInput(filter->GetOutput());
  writer->SetInput(rescaler->GetOutput());
248
  // Software Guide : EndCodeSnippet
Jordi Inglada's avatar
Jordi Inglada committed
249 250 251 252 253 254

  typedef otb::CommandProgressUpdate<FilterType> CommandType;

  CommandType::Pointer observer = CommandType::New();
  filter->AddObserver(itk::ProgressEvent(), observer);

255
  try
OTB Bot's avatar
STYLE  
OTB Bot committed
256
    {
257
    writer->Update();
OTB Bot's avatar
STYLE  
OTB Bot committed
258 259 260
    }
  catch (itk::ExceptionObject& err)
    {
261 262
    std::cout << "ExceptionObject caught !" << std::endl;
    std::cout << err << std::endl;
Jordi Inglada's avatar
Jordi Inglada committed
263
    return -1;
OTB Bot's avatar
STYLE  
OTB Bot committed
264
    }
Jordi Inglada's avatar
Jordi Inglada committed
265 266 267

  // Software Guide : BeginLatex
  //
268
  // And that is all.
Jordi Inglada's avatar
Jordi Inglada committed
269 270 271
  //
  // SoftwareGuide : EndLatex

272
  return EXIT_SUCCESS;
Jordi Inglada's avatar
Jordi Inglada committed
273 274

}