SVMImageEstimatorClassificationMultiExample.cxxΒΆ

Example usage:

./SVMImageEstimatorClassificationMultiExample Input/ROI_QB_MUL_1.png \
                                              Input/ROI_mask_multi.png \
                                              Output/ROI_QB_MUL_1_SVN_CLASS_MULTI.png \
                                              Output/ROI_QB_MUL_1_SVN_CLASS_MULTI_Rescaled.jpg \
                                              Output/ROI_mask_multi.png

Example source code (SVMImageEstimatorClassificationMultiExample.cxx):

// This example illustrates the OTB's multi-class SVM
// capabilities. The theory behind this kind of classification is out
// of the scope of this guide. In OTB, the multi-class SVM
// classification is used in the same way as the two-class
// one. Figure~\ref{fig:SVMROISMULTI} shows the image to be classified
// and the associated ground truth, which is composed of 4 classes.
// \begin{figure}
// \center
// \includegraphics[width=0.45\textwidth]{ROI_QB_MUL_1.eps}
// \includegraphics[width=0.45\textwidth]{ROI_mask_multi.eps}
// \itkcaption[SVM Image Model Estimation]{Images used for the
// estimation of the SVM model. Left: RGB image. Right: image of labels.}
// \label{fig:SVMROISMULTI}
// \end{figure}

// The following header files are needed for the program:


#include "itkMacro.h"
#include "otbImage.h"
#include "otbVectorImage.h"
#include <iostream>

#include "otbLibSVMMachineLearningModel.h"
#include "itkImageToListSampleFilter.h"
#include "otbImageClassificationFilter.h"

#include "otbImageFileWriter.h"

#include "itkUnaryFunctorImageFilter.h"
#include "itkScalarToRGBPixelFunctor.h"
#include "itkBinaryThresholdImageFilter.h"

#include "otbImageFileReader.h"

int main(int itkNotUsed(argc), char* argv[])
{

  const char* inputImageFileName          = argv[1];
  const char* trainingImageFileName       = argv[2];
  const char* outputImageFileName         = argv[3];
  const char* outputRescaledImageFileName = argv[4];
  //  const char* outputModelFileName = argv[4];

  //  We define the types for the input and training images. Even if the
  //  input image will be an RGB image, we can read it as a 3 component
  //  vector image. This simplifies the interfacing with OTB's SVM
  //  framework.
  typedef unsigned short InputPixelType;
  const unsigned int     Dimension = 2;

  typedef otb::VectorImage<InputPixelType, Dimension> InputImageType;

  typedef otb::Image<InputPixelType, Dimension> TrainingImageType;

  //  The \doxygen{otb}{LibSVMMachineLearningModel} class is templated over
  //  the input (features) and the training (labels) values.
  typedef otb::LibSVMMachineLearningModel<InputPixelType, InputPixelType> ModelType;


  //  As usual, we define the readers for the images.
  typedef otb::ImageFileReader<InputImageType>    InputReaderType;
  typedef otb::ImageFileReader<TrainingImageType> TrainingReaderType;

  InputReaderType::Pointer    inputReader    = InputReaderType::New();
  TrainingReaderType::Pointer trainingReader = TrainingReaderType::New();


  //  We read the images. It is worth to note that, in order to ensure
  //  the pipeline coherence, the output of the objects which precede the
  //  model estimator in the pipeline, must be up to date, so we call
  //  the corresponding \code{Update} methods.
  inputReader->SetFileName(inputImageFileName);
  trainingReader->SetFileName(trainingImageFileName);

  //~ inputReader->Update();
  //~ trainingReader->Update();


  //  The input data is contained in images. Only label values greater than 0
  //  shall be used, so we create two iterators to fill the input and target
  //  ListSamples.


  typedef itk::BinaryThresholdImageFilter<TrainingImageType, TrainingImageType> ThresholdFilterType;
  ThresholdFilterType::Pointer                                                  thresholder = ThresholdFilterType::New();
  thresholder->SetInput(trainingReader->GetOutput());
  thresholder->SetLowerThreshold(1);
  thresholder->SetOutsideValue(0);
  thresholder->SetInsideValue(1);

  typedef itk::Statistics::ImageToListSampleFilter<InputImageType, TrainingImageType>    ImageToListSample;
  typedef itk::Statistics::ImageToListSampleFilter<TrainingImageType, TrainingImageType> ImageToTargetListSample;

  ImageToListSample::Pointer imToList = ImageToListSample::New();
  imToList->SetInput(inputReader->GetOutput());
  imToList->SetMaskImage(thresholder->GetOutput());
  imToList->SetMaskValue(1);
  imToList->Update();

  ImageToTargetListSample::Pointer imToTargetList = ImageToTargetListSample::New();
  imToTargetList->SetInput(trainingReader->GetOutput());
  imToTargetList->SetMaskImage(thresholder->GetOutput());
  imToTargetList->SetMaskValue(1);
  imToTargetList->Update();


  //  We can now instantiate the model and set its parameters.
  ModelType::Pointer svmModel = ModelType::New();
  svmModel->SetInputListSample(const_cast<ModelType::InputListSampleType*>(imToList->GetOutput()));
  svmModel->SetTargetListSample(const_cast<ModelType::TargetListSampleType*>(imToTargetList->GetOutput()));


  //  The model training procedure is triggered by calling the
  //  model's \code{Train} method.
  svmModel->Train();


  // We have now all the elements to create a classifier. The classifier
  // is templated over the sample type (the type of the data to be
  // classified) and the label type (the type of the output of the classifier).

  typedef otb::ImageClassificationFilter<InputImageType, TrainingImageType> ClassifierType;

  ClassifierType::Pointer classifier = ClassifierType::New();

  // We set the classifier parameters : number of classes, SVM model,
  // the sample data. And we trigger the classification process by
  // calling the \code{Update} method.

  classifier->SetModel(svmModel);
  classifier->SetInput(inputReader->GetOutput());

  // After the classification step, we usually want to get the
  // results. The classifier gives an output under the form of a sample
  // list. This list supports the classical STL iterators. Therefore, we
  // will create an output image and fill it up with the results of the
  // classification. The pixel type of the output image is the same as
  // the one used for the labels.


  // We allocate the memory for the output image using the information
  // from the input image.


  // We can now declare the iterators on the list that we get at the
  // output of the classifier as well as the iterator to fill the output image.


  // We will iterate through the list, get the labels and assign pixel
  // values to the output image.


  typedef otb::ImageFileWriter<TrainingImageType> WriterType;

  WriterType::Pointer writer = WriterType::New();

  writer->SetFileName(outputImageFileName);
  writer->SetInput(classifier->GetOutput());

  writer->Update();

  // Only for visualization purposes, we choose a color mapping to the image of
  // classes before saving it to a file. The
  // \subdoxygen{itk}{Functor}{ScalarToRGBPixelFunctor} class is a special
  // function object designed to hash a scalar value into an
  // \doxygen{itk}{RGBPixel}. Plugging this functor into the
  // \doxygen{itk}{UnaryFunctorImageFilter} creates an image filter for that
  // converts scalar images to RGB images.

  typedef itk::RGBPixel<unsigned char>                                                       RGBPixelType;
  typedef otb::Image<RGBPixelType, 2>                                                        RGBImageType;
  typedef itk::Functor::ScalarToRGBPixelFunctor<unsigned long>                               ColorMapFunctorType;
  typedef itk::UnaryFunctorImageFilter<TrainingImageType, RGBImageType, ColorMapFunctorType> ColorMapFilterType;
  ColorMapFilterType::Pointer                                                                colormapper = ColorMapFilterType::New();

  colormapper->SetInput(classifier->GetOutput());

  // We can now create an image file writer and save the image.

  typedef otb::ImageFileWriter<RGBImageType> WriterRescaledType;

  WriterRescaledType::Pointer writerRescaled = WriterRescaledType::New();

  writerRescaled->SetFileName(outputRescaledImageFileName);
  writerRescaled->SetInput(colormapper->GetOutput());

  writerRescaled->Update();

  // Figure \ref{fig:SVMCLASSMULTI} shows the result of the SVM classification.
  // \begin{figure}
  // \center
  // \includegraphics[width=0.45\textwidth]{ROI_QB_MUL_1.eps}
  // \includegraphics[width=0.45\textwidth]{ROI_QB_MUL_1_SVN_CLASS_MULTI_Rescaled.eps}
  // \itkcaption[SVM Image Classification]{Result of the SVM
  // classification . Left: RGB image. Right: image of classes.}
  // \label{fig:SVMCLASSMULTI}
  // \end{figure}

  return EXIT_SUCCESS;
}