SOMClassifierExample.cxxΒΆ
Example usage:
./SOMClassifierExample Input/ROI_QB_MUL_1.png Input/ROI_QB_MUL_SOM.png Output/ROI_QB_MUL_SOMCLASS.png
Example source code (SOMClassifierExample.cxx):
#include <fstream>
#include "otbImage.h"
#include "otbSOMMap.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
#include "itkImageRegionIterator.h"
#include "itkListSample.h"
// This example illustrates the use of the
// \doxygen{otb}{SOMClassifier} class for performing a classification
// using an existing Kohonen's Self Organizing. Actually, the SOM
// classification consists only in the attribution of the winner
// neuron index to a given feature vector.
//
// We will use the SOM created in section \ref{sec:SOMColorTable} and
// we will assume that each neuron represents a class in the image.
//
// The first thing to do is include the header file for the
// class.
#include "otbSOMClassifier.h"
int main(int argc, char* argv[])
{
if (argc != 4)
{
std::cout << "Usage : " << argv[0] << " inputImage modelFile outputImage" << std::endl;
return EXIT_FAILURE;
}
const char* imageFilename = argv[1];
const char* mapFilename = argv[2];
const char* outputFilename = argv[3];
using InputPixelType = double;
using LabelPixelType = unsigned char;
const unsigned int Dimension = 2;
using PixelType = itk::VariableLengthVector<InputPixelType>;
// As for the SOM learning step, we must define the types for the
// \code{otb::SOMMap}, and therefore, also for the distance to be
// used. We will also define the type for the SOM reader, which is
// actually an \doxygen{otb}{ImageFileReader} which the appropriate
// image type.
using DistanceType = itk::Statistics::EuclideanDistanceMetric<PixelType>;
using SOMMapType = otb::SOMMap<PixelType, DistanceType, Dimension>;
using SOMReaderType = otb::ImageFileReader<SOMMapType>;
using InputImageType = otb::VectorImage<InputPixelType, Dimension>;
using ReaderType = otb::ImageFileReader<InputImageType>;
// The classification will be performed by the
// \doxygen{otb}{SOMClassifier}, which, as most of the
// classifiers, works on
// \subdoxygen{itk}{Statistics}{ListSample}s. In order to be able
// to perform an image classification, we will need to use the
// \subdoxygen{itk}{Statistics}{ImageToListAdaptor} which is
// templated over the type of image to be adapted. The
// \code{SOMClassifier} is templated over the sample type, the SOMMap
// type and the pixel type for the labels.
using SampleType = itk::Statistics::ListSample<PixelType>;
using ClassifierType = otb::SOMClassifier<SampleType, SOMMapType, LabelPixelType>;
//
// The result of the classification will be stored on an image and
// saved to a file. Therefore, we define the types needed for this step.
using OutputImageType = otb::Image<LabelPixelType, Dimension>;
using WriterType = otb::ImageFileWriter<OutputImageType>;
//
// We can now start reading the input image and the SOM given as
// inputs to the program. We instantiate the readers as usual.
ReaderType::Pointer reader = ReaderType::New();
reader->SetFileName(imageFilename);
reader->Update();
SOMReaderType::Pointer somreader = SOMReaderType::New();
somreader->SetFileName(mapFilename);
somreader->Update();
//
// The conversion of the input data from image to list sample is
// easily done using the adaptor.
SampleType::Pointer sample = SampleType::New();
itk::ImageRegionIterator<InputImageType> it(reader->GetOutput(), reader->GetOutput()->GetLargestPossibleRegion());
sample->SetMeasurementVectorSize(reader->GetOutput()->GetNumberOfComponentsPerPixel());
it.GoToBegin();
while (!it.IsAtEnd())
{
sample->PushBack(it.Get());
++it;
}
//
// The classifier can now be instantiated. The input data is set by
// using the \code{SetSample()} method and the SOM si set using the
// \code{SetMap()} method. The classification is triggered by using
// the \code{Update()} method.
ClassifierType::Pointer classifier = ClassifierType::New();
classifier->SetSample(sample.GetPointer());
classifier->SetMap(somreader->GetOutput());
classifier->Update();
//
// Once the classification has been performed, the sample list
// obtained at the output of the classifier must be converted into an
// image. We create the image as follows :
OutputImageType::Pointer outputImage = OutputImageType::New();
outputImage->SetRegions(reader->GetOutput()->GetLargestPossibleRegion());
outputImage->Allocate();
//
// We can now get a pointer to the classification result.
ClassifierType::OutputType* membershipSample = classifier->GetOutput();
//
// And we can declare the iterators pointing to the front and the
// back of the sample list.
ClassifierType::OutputType::ConstIterator m_iter = membershipSample->Begin();
ClassifierType::OutputType::ConstIterator m_last = membershipSample->End();
//
// We also declare an \doxygen{itk}{ImageRegionIterator} in order
// to fill the output image with the class labels.
using OutputIteratorType = itk::ImageRegionIterator<OutputImageType>;
OutputIteratorType outIt(outputImage, outputImage->GetLargestPossibleRegion());
//
// We iterate through the sample list and the output image and assign
// the label values to the image pixels.
outIt.GoToBegin();
while (m_iter != m_last && !outIt.IsAtEnd())
{
outIt.Set(m_iter.GetClassLabel());
++m_iter;
++outIt;
}
//
// Finally, we write the classified image to a file.
WriterType::Pointer writer = WriterType::New();
writer->SetFileName(outputFilename);
writer->SetInput(outputImage);
writer->Update();
// Figure \ref{fig:SOMMAPCLASS} shows the result of the SOM classification.
// \begin{figure}
// \center
// \includegraphics[width=0.35\textwidth]{ROI_QB_MUL_1.eps}
// \includegraphics[width=0.2\textwidth]{ROI_QB_MUL_SOM.eps}
// \includegraphics[width=0.35\textwidth]{ROI_QB_MUL_SOMCLASS.eps}
// \itkcaption[SOM Image Classification]{Result of the SOM
// learning. Left: RGB image. Center: SOM. Right: Classified Image}
// \label{fig:SOMMAPCLASS}
// \end{figure}
return EXIT_SUCCESS;
}