KullbackLeiblerProfileChDet.cxx

This example illustrates the class otb::KullbackLeiblerProfileImageFilter for detecting changes between pairs of images, according to a range of window size. This example is very similar, in its principle, to all of the change detection examples, especially the distance between distributions one which uses a fixed window size.

The main differences are:

  • a set of window range instead of a fixed size of window

  • an output of type otb::VectorImage

Then, the program begins with the otb::VectorImage and the otb::KullbackLeiblerProfileImageFilter header files in addition to those already detailed in the otb::MeanRatioImageFilter example.

../../../_images/KLProfileChDet.png

Fig. 13 Result of the Kullback-Leibler profile change detector, colored composition including the first, 12th and 24th channel of the generated output.

Example usage:

./KullbackLeiblerProfileChDet Input/GomaAvant.png Input/GomaApres.png Output/KLProfileChDet.png 5 51 1 12 24

Example source code (KullbackLeiblerProfileChDet.cxx):

#include "otbImage.h"
#include "otbMultiChannelExtractROI.h"
#include "otbVectorRescaleIntensityImageFilter.h"
#include "otbKullbackLeiblerProfileImageFilter.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"

int main(int argc, char* argv[])
{
  if (argc != 9)
  {
    std::cerr << "Change detection based on Kullback-Leibler distance between local pdf through an Edgeworth approximation\n";
    std::cerr << argv[0] << " imgAv imgAp imgResu winSizeMin winSizeMax outRedIndex outGreenIndex outBlueIndex\n";
    return EXIT_FAILURE;
  }

  char*        fileName1   = argv[1];
  char*        fileName2   = argv[2];
  char*        fileNameOut = argv[3];
  int          winSizeMin  = atoi(argv[4]);
  int          winSizeMax  = atoi(argv[5]);
  unsigned int ri          = atoi(argv[6]);
  unsigned int gi          = atoi(argv[7]);
  unsigned int bi          = atoi(argv[8]);

  const unsigned int Dimension = 2;
  using PixelType              = double;
  using OutPixelType           = unsigned char;

  // The KullbackLeiblerProfileImageFilter is templated over
  // the types of the two input images and the type of the generated change
  // image (which is now of multi-components), in a similar way as the
  // KullbackLeiblerDistanceImageFilter.
  using ImageType           = otb::Image<PixelType, Dimension>;
  using VectorImageType     = otb::VectorImage<PixelType, Dimension>;
  using FilterType          = otb::KullbackLeiblerProfileImageFilter<ImageType, ImageType, VectorImageType>;
  using OutVectorImageType  = otb::VectorImage<OutPixelType, Dimension>;
  using ReaderType          = otb::ImageFileReader<ImageType>;
  using WriterType          = otb::ImageFileWriter<OutVectorImageType>;
  using ChannelSelecterType = otb::MultiChannelExtractROI<PixelType, PixelType>;
  using RescalerType        = otb::VectorRescaleIntensityImageFilter<VectorImageType, OutVectorImageType>;

  // The different elements of the pipeline can now be instantiated in the
  // same way as the ratio of means change detector example.
  ReaderType::Pointer reader1 = ReaderType::New();
  reader1->SetFileName(fileName1);

  ReaderType::Pointer reader2 = ReaderType::New();
  reader2->SetFileName(fileName2);

  // Two parameters are now required to give the minimum and the maximum size
  // of the analysis window. The program will begin by performing change
  // detection through the smaller window size and then applying moments update
  // by incrementing the radius of the analysis window (i.e. add a ring of
  // width 1 pixel around the current neighborhood shape). The process is
  // applied until the larger window size is reached.
  FilterType::Pointer filter = FilterType::New();
  filter->SetRadius((winSizeMin - 1) / 2, (winSizeMax - 1) / 2);
  filter->SetInput1(reader1->GetOutput());
  filter->SetInput2(reader2->GetOutput());

  ChannelSelecterType::Pointer channelSelecter = ChannelSelecterType::New();
  channelSelecter->SetInput(filter->GetOutput());
  channelSelecter->SetChannel(ri);
  channelSelecter->SetChannel(gi);
  channelSelecter->SetChannel(bi);

  RescalerType::Pointer rescaler = RescalerType::New();
  rescaler->SetInput(channelSelecter->GetOutput());
  OutVectorImageType::PixelType min, max;
  min.SetSize(3);
  max.SetSize(3);
  min.Fill(0);
  max.Fill(255);
  rescaler->SetOutputMinimum(min);
  rescaler->SetOutputMaximum(max);

  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName(fileNameOut);
  writer->SetInput(rescaler->GetOutput());
  writer->Update();
}