ChangeDetectionFrameworkExample.cxx 8.92 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Patrick Imbo's avatar
Patrick Imbo committed
20

21

22 23 24 25 26 27

// 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
28
// \doxygen{otb}{BinaryFunctorNeighborhoodImageFilter}s, that is, they
29 30
// are filters taking two images as input and providing one image as
// output. The change detection computation itself is performed on a
31
// the neighborhood of each pixel of the input images.
32 33
//
// The first step required to build a change detection filter is to
34
// include the header of the parent class.
35
//
36
// Software Guide : EndLatex
37 38 39 40 41 42 43

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

#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
44
#include "itkUnaryFunctorImageFilter.h"
45
#include "itkRescaleIntensityImageFilter.h"
46
#include "otbImage.h"
47 48 49 50 51 52 53 54 55 56
#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
57
// which overload the \code{()} operator. This allows using them with
58 59
// the same syntax as C/C++ functions.
//
Emmanuel Christophe's avatar
Emmanuel Christophe committed
60
// Since change detectors operate on neighborhoods, the functor
61
// call will take 2 arguments which are
62
// \doxygen{itk}{ConstNeighborhoodIterator}s.
63 64 65 66 67
//
// 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.
//
68
// Software Guide : EndLatex
69

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

83 84
    TOutput result = 0.0;

OTB Bot's avatar
OTB Bot committed
85 86
    for (unsigned long pos = 0; pos < itA.Size(); ++pos)
      {
87

OTB Bot's avatar
OTB Bot committed
88
      result += static_cast<TOutput>(itA.GetPixel(pos) - itB.GetPixel(pos));
89

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

// 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
105
// \doxygen{otb}{BinaryFunctorNeighborhoodImageFilter} which is
106 107 108
// 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
Emmanuel Christophe committed
109
// Inside the class only a few \code{typedef}s and the constructors
110 111 112 113
// and destructors have to be declared.
//
// Software Guide : EndLatex

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

128
  typedef typename otb::BinaryFunctorNeighborhoodImageFilter<
OTB Bot's avatar
OTB Bot committed
129 130 131 132 133 134
      TInputImage1, TInputImage2, TOutputImage,
      MyChangeDetector<
          typename itk::ConstNeighborhoodIterator<TInputImage1>,
          typename itk::ConstNeighborhoodIterator<TInputImage2>,
          typename TOutputImage::PixelType>
      >  Superclass;
OTB Bot's avatar
OTB Bot committed
135 136 137

  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;
138 139 140

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

142 143
protected:
  MyChangeDetectorImageFilter() {}
144
  ~MyChangeDetectorImageFilter() override {}
145 146

private:
147 148
  MyChangeDetectorImageFilter(const Self &) = delete;
  void operator =(const Self&) = delete;
149 150

};
151
// Software Guide : EndCodeSnippet
152 153 154

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

OTB Bot's avatar
OTB Bot committed
164
int main(int argc, char* argv[])
165 166
{

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

  // 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

186
  // Software Guide : BeginCodeSnippet
OTB Bot's avatar
OTB Bot committed
187 188 189 190 191 192
  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;
193 194 195 196 197
  // Software Guide : EndCodeSnippet

  // Software Guide : BeginLatex
  //
  // We declare the readers, the writer, but also the
198
  // \doxygen{itk}{RescaleIntensityImageFilter} which will be used to
199 200 201 202
  // rescale the result before writing it to a file.
  //
  // SoftwareGuide : EndLatex

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

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

217
  // Software Guide : BeginCodeSnippet
OTB Bot's avatar
OTB Bot committed
218 219
  typedef MyChangeDetectorImageFilter<InputImageType1, InputImageType2,
      ChangeImageType>      FilterType;
220 221
  // Software Guide : EndCodeSnippet

OTB Bot's avatar
OTB Bot committed
222 223 224
  ReaderType1::Pointer  reader1 = ReaderType1::New();
  ReaderType2::Pointer  reader2 = ReaderType2::New();
  WriterType::Pointer   writer = WriterType::New();
225 226 227 228 229 230 231 232 233 234 235 236 237
  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

238
  // Software Guide : BeginCodeSnippet
OTB Bot's avatar
OTB Bot committed
239 240 241 242 243 244 245 246 247 248 249 250
  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());
251
  // Software Guide : EndCodeSnippet
252 253 254 255 256 257

  typedef otb::CommandProgressUpdate<FilterType> CommandType;

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

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

  // Software Guide : BeginLatex
  //
271
  // And that is all.
272 273 274
  //
  // SoftwareGuide : EndLatex

275
  return EXIT_SUCCESS;
276 277

}