# SVMImageEstimatorClassificationMultiExample.cxx¶

Example usage:

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


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}
// \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"

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.
using InputPixelType         = unsigned short;
const unsigned int Dimension = 2;

using InputImageType = otb::VectorImage<InputPixelType, Dimension>;

using TrainingImageType = otb::Image<InputPixelType, Dimension>;

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

//  As usual, we define the readers for the images.

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

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

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

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

ImageToListSample::Pointer imToList = ImageToListSample::New();
imToList->Update();

ImageToTargetListSample::Pointer imToTargetList = ImageToTargetListSample::New();
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).

using ClassifierType = otb::ImageClassificationFilter<InputImageType, TrainingImageType>;

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);

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

using WriterType = otb::ImageFileWriter<TrainingImageType>;

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.

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

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

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

using WriterRescaledType = otb::ImageFileWriter<RGBImageType>;

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;
}