From 0b6d6171fbeb78431fbe75e92bbf45994ff6e23b Mon Sep 17 00:00:00 2001
From: Charles Peyrega <charles.peyrega@c-s.fr>
Date: Wed, 3 Jul 2013 19:22:59 +0200
Subject: [PATCH] DOC: Add 2 examples of fusion of classifications with
 majority voting and DS in the SG

---
 Examples/Classification/CMakeLists.txt        |   6 +
 ...haferFusionOfClassificationMapsExample.cxx | 331 ++++++++++++++++++
 ...otingFusionOfClassificationMapsExample.cxx | 134 +++++++
 3 files changed, 471 insertions(+)
 create mode 100644 Examples/Classification/DempsterShaferFusionOfClassificationMapsExample.cxx
 create mode 100644 Examples/Classification/MajorityVotingFusionOfClassificationMapsExample.cxx

diff --git a/Examples/Classification/CMakeLists.txt b/Examples/Classification/CMakeLists.txt
index 6fdc0a12ee..64aedec0e9 100644
--- a/Examples/Classification/CMakeLists.txt
+++ b/Examples/Classification/CMakeLists.txt
@@ -28,6 +28,12 @@ TARGET_LINK_LIBRARIES(SOMImageClassificationExample OTBIO OTBLearning)
 ADD_EXECUTABLE(SupervisedImageClassificationExample SupervisedImageClassificationExample.cxx )
 TARGET_LINK_LIBRARIES(SupervisedImageClassificationExample OTBIO OTBLearning)
 
+ADD_EXECUTABLE(MajorityVotingFusionOfClassificationMapsExample MajorityVotingFusionOfClassificationMapsExample.cxx )
+TARGET_LINK_LIBRARIES(MajorityVotingFusionOfClassificationMapsExample OTBIO)
+
+ADD_EXECUTABLE(DempsterShaferFusionOfClassificationMapsExample DempsterShaferFusionOfClassificationMapsExample.cxx )
+TARGET_LINK_LIBRARIES(DempsterShaferFusionOfClassificationMapsExample OTBIO)
+
 ADD_EXECUTABLE(ClassificationMapRegularizationExample ClassificationMapRegularizationExample.cxx )
 TARGET_LINK_LIBRARIES(ClassificationMapRegularizationExample OTBIO OTBCommon)
 
diff --git a/Examples/Classification/DempsterShaferFusionOfClassificationMapsExample.cxx b/Examples/Classification/DempsterShaferFusionOfClassificationMapsExample.cxx
new file mode 100644
index 0000000000..e1c50cf926
--- /dev/null
+++ b/Examples/Classification/DempsterShaferFusionOfClassificationMapsExample.cxx
@@ -0,0 +1,331 @@
+/*=========================================================================
+
+  Program:   ORFEO Toolbox
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
+  See OTBCopyright.txt for details.
+
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+
+
+// Software Guide : BeginLatex
+//
+// The fusion filter \doxygen{otb}{DSFusionOfClassifiersImageFilter} is based on the Dempster
+// Shafer (DS) fusion framework. For each pixel, it chooses the class label Ai for which the
+// belief function bel(Ai) is maximal after the DS combination of all the available masses of
+// belief of all the class labels. The masses of belief (MOBs) of all the labels present in each
+// classification map are read from input *.CSV confusion matrix files.
+// Moreover, the pixels into the input classification maps to be fused which are equal to the
+// \emph{nodataLabel} value are ignored by the fusion process. In case of not unique class labels,
+// the output pixel is set to the \emph{undecidedLabel} value.
+// We start by including the appropriate header files.
+//
+// Software Guide : EndLatex
+
+
+// Software Guide : BeginCodeSnippet
+#include "otbImageListToVectorImageFilter.h"
+#include "otbConfusionMatrixToMassOfBelief.h"
+#include "otbDSFusionOfClassifiersImageFilter.h"
+
+#include <fstream>
+// Software Guide : EndCodeSnippet
+
+#include "otbImage.h"
+#include "otbImageFileReader.h"
+#include "otbImageFileWriter.h"
+
+
+// Software Guide : BeginLatex
+//
+// We will assume unsigned short type input labeled images. We define a type for
+// confusion matrices as \doxygen{itk}{VariableSizeMatrix} which will be used to estimate the masses of belief of all the
+// class labels for each input classification map. For this purpose, the
+// \doxygen{otb}{ConfusionMatrixToMassOfBelief} will be used to convert each input confusion matrix
+// into masses of belief for each class label.
+//
+// Software Guide : EndLatex
+
+
+// Software Guide : BeginCodeSnippet
+  typedef unsigned short LabelPixelType;
+  typedef unsigned long ConfusionMatrixEltType;
+  typedef itk::VariableSizeMatrix<ConfusionMatrixEltType> ConfusionMatrixType;
+  typedef otb::ConfusionMatrixToMassOfBelief
+           <ConfusionMatrixType, LabelPixelType> ConfusionMatrixToMassOfBeliefType;
+  typedef ConfusionMatrixToMassOfBeliefType::MapOfClassesType MapOfClassesType;
+// Software Guide : EndCodeSnippet
+
+
+int CSVConfusionMatrixFileReader(const std::string fileName, MapOfClassesType &mapOfClassesRefClX, ConfusionMatrixType &confusionMatrixClX)
+  {
+    std::ifstream inFile;
+    inFile.open(fileName.c_str());
+
+    if (!inFile)
+      {
+      std::cerr << "Confusion Matrix File opening problem with file:" << std::endl;
+      std::cerr << fileName.c_str() << std::endl;
+      return EXIT_FAILURE;
+      }
+    else
+      {
+      LabelPixelType labelRef = 0, labelProd = 0;
+      std::string currentLine, refLabelsLine, prodLabelsLine, currentValue;
+      const char endCommentChar = ':';
+      const char separatorChar = ',';
+      const char eolChar = '\n';
+      std::getline(inFile, refLabelsLine, endCommentChar); // Skips the comments
+      std::getline(inFile, refLabelsLine, eolChar); // Gets the first line after the comment char until the End Of Line char
+      std::getline(inFile, prodLabelsLine, endCommentChar); // Skips the comments
+      std::getline(inFile, prodLabelsLine, eolChar); // Gets the second line after the comment char until the End Of Line char
+
+      std::istringstream issRefLabelsLine(refLabelsLine);
+      std::istringstream issProdLabelsLine(prodLabelsLine);
+
+      MapOfClassesType mapOfClassesProdClX;
+
+      mapOfClassesRefClX.clear();
+      mapOfClassesProdClX.clear();
+      int itLab = 0;
+      while (issRefLabelsLine.good())
+        {
+        std::getline(issRefLabelsLine, currentValue, separatorChar);
+        labelRef = static_cast<LabelPixelType> (std::atoi(currentValue.c_str()));
+        mapOfClassesRefClX[labelRef] = itLab;
+        ++itLab;
+        }
+
+      itLab = 0;
+      while (issProdLabelsLine.good())
+        {
+        std::getline(issProdLabelsLine, currentValue, separatorChar);
+        labelProd = static_cast<LabelPixelType> (std::atoi(currentValue.c_str()));
+        mapOfClassesProdClX[labelProd] = itLab;
+        ++itLab;
+        }
+
+      unsigned int nbRefLabelsClk = mapOfClassesRefClX.size();
+      unsigned int nbProdLabelsClk = mapOfClassesProdClX.size();
+      ConfusionMatrixType confusionMatrixClXTemp;
+      confusionMatrixClXTemp = ConfusionMatrixType(nbRefLabelsClk, nbProdLabelsClk);
+      confusionMatrixClXTemp.Fill(0);
+
+      // Reading the confusion matrix confusionMatrixClXTemp from the file
+      for (unsigned int itRow = 0; itRow < nbRefLabelsClk; ++itRow)
+        {
+        //Gets the itRow^th line after the header lines with the labels
+        std::getline(inFile, currentLine, eolChar);
+        std::istringstream issCurrentLine(currentLine);
+        unsigned int itCol = 0;
+        while (issCurrentLine.good())
+          {
+          std::getline(issCurrentLine, currentValue, separatorChar);
+          confusionMatrixClXTemp(itRow, itCol) = static_cast<ConfusionMatrixEltType> (std::atoi(currentValue.c_str()));
+          ++itCol;
+          }
+        }
+
+      MapOfClassesType::iterator  itMapOfClassesRef, itMapOfClassesProd;
+
+      // Formatting confusionMatrixClX from confusionMatrixClXTemp in order to make confusionMatrixClX a square matrix
+      // from the reference labels in mapOfClassesRefClX
+      int indiceLabelRef = 0, indiceLabelProd = 0;
+      int indiceLabelRefTemp = 0, indiceLabelProdTemp = 0;
+      // Initialization of confusionMatrixClX
+      confusionMatrixClX = ConfusionMatrixType(nbRefLabelsClk, nbRefLabelsClk);
+      confusionMatrixClX.Fill(0);
+      for (itMapOfClassesRef = mapOfClassesRefClX.begin(); itMapOfClassesRef != mapOfClassesRefClX.end(); ++itMapOfClassesRef)
+        {
+        // labels labelRef of mapOfClassesRefClX are already sorted
+        labelRef = itMapOfClassesRef->first;
+        indiceLabelRefTemp = itMapOfClassesRef->second;
+
+        for (itMapOfClassesProd = mapOfClassesProdClX.begin(); itMapOfClassesProd != mapOfClassesProdClX.end(); ++itMapOfClassesProd)
+          {
+          // labels labelProd of mapOfClassesProdClX are already sorted
+          labelProd = itMapOfClassesProd->first;
+          indiceLabelProdTemp = itMapOfClassesProd->second;
+
+          // If labelProd is present in mapOfClassesRefClX
+          if (mapOfClassesRefClX.count(labelProd) != 0)
+            {
+            // Indice of labelProd in mapOfClassesRefClX; itMapOfClassesRef->second elements are already SORTED
+            indiceLabelProd = mapOfClassesRefClX[labelProd];
+            confusionMatrixClX(indiceLabelRef, indiceLabelProd) = confusionMatrixClXTemp(indiceLabelRefTemp, indiceLabelProdTemp);
+            }
+          }
+        ++indiceLabelRef;
+        }
+      }
+    inFile.close();
+    return EXIT_SUCCESS;
+  }
+
+
+
+
+int main(int argc, char * argv[])
+{
+// Software Guide : BeginLatex
+//
+// The input labeled images to be fused are expected to be scalar images.
+//
+// Software Guide : EndLatex
+// Software Guide : BeginCodeSnippet
+  const unsigned int     Dimension = 2;
+  typedef otb::Image<LabelPixelType, Dimension> LabelImageType;
+  typedef otb::VectorImage<LabelPixelType, Dimension> VectorImageType;
+// Software Guide : EndCodeSnippet
+
+  LabelPixelType nodataLabel = atoi(argv[argc - 3]);
+  LabelPixelType undecidedLabel = atoi(argv[argc - 2]);
+  const char * outfname = argv[argc - 1];
+
+  unsigned int nbParameters = 3;
+  unsigned int nbClassificationMaps = (argc - 1 - nbParameters) / 2;
+
+  // Software Guide : BeginLatex
+  //
+  // We declare an \doxygen{otb}{ImageListToVectorImageFilter} which will stack all the
+  // input classification maps to be fused as a single VectorImage for which each
+  // band is a classification map. This VectorImage will then be the input of the
+  // Dempster Shafer fusion filter \doxygen{otb}{DSFusionOfClassifiersImageFilter}.
+  //
+  // Software Guide : EndLatex
+  // Software Guide : BeginCodeSnippet
+
+  typedef otb::ImageList<LabelImageType> LabelImageListType;
+  typedef otb::ImageListToVectorImageFilter
+            <LabelImageListType, VectorImageType> ImageListToVectorImageFilterType;
+  // Software Guide : EndCodeSnippet
+
+  typedef ConfusionMatrixToMassOfBeliefType::MassOfBeliefDefinitionMethod MassOfBeliefDefinitionMethod;
+
+
+// Software Guide : BeginLatex
+//
+// The Dempster Shafer fusion filter \doxygen{otb}{DSFusionOfClassifiersImageFilter} is declared.
+//
+// Software Guide : EndLatex
+// Software Guide : BeginCodeSnippet
+  // Dempster Shafer
+  typedef otb::DSFusionOfClassifiersImageFilter
+        <VectorImageType, LabelImageType> DSFusionOfClassifiersImageFilterType;
+// Software Guide : EndCodeSnippet
+
+  typedef DSFusionOfClassifiersImageFilterType::VectorOfMapOfMassesOfBeliefType VectorOfMapOfMassesOfBeliefType;
+
+// Software Guide : BeginLatex
+//
+// Both reader and writer are defined. Since the images
+// to classify can be very big, we will use a streamed writer which
+// will trigger the streaming ability of the fusion filter.
+//
+// Software Guide : EndLatex
+// Software Guide : BeginCodeSnippet
+  typedef otb::ImageFileReader<LabelImageType> ReaderType;
+  typedef otb::ImageFileWriter<LabelImageType> WriterType;
+// Software Guide : EndCodeSnippet
+
+
+// Software Guide : BeginLatex
+//
+// The image list of input classification maps is filled. Moreover, the input
+// confusion matrix files are converted into masses of belief.
+//
+// Software Guide : EndLatex
+// Software Guide : BeginCodeSnippet
+  ReaderType::Pointer reader;
+  LabelImageListType::Pointer imageList = LabelImageListType::New();
+  ConfusionMatrixToMassOfBeliefType::Pointer confusionMatrixToMassOfBeliefFilter;
+  confusionMatrixToMassOfBeliefFilter = ConfusionMatrixToMassOfBeliefType::New();
+
+  MassOfBeliefDefinitionMethod massOfBeliefDef;
+
+  // Several parameters are available to estimate the masses of belief
+  // from the confusion matrices: PRECISION, RECALL, ACCURACY and KAPPA
+  massOfBeliefDef = ConfusionMatrixToMassOfBeliefType::PRECISION;
+
+  VectorOfMapOfMassesOfBeliefType vectorOfMapOfMassesOfBelief;
+  for (unsigned int itCM = 0; itCM < nbClassificationMaps; ++itCM)
+    {
+    std::string fileNameClassifiedImage = argv[itCM + 1];
+    std::string fileNameConfMat = argv[itCM + 1 + nbClassificationMaps];
+
+    reader = ReaderType::New();
+    reader->SetFileName(fileNameClassifiedImage);
+    reader->Update();
+
+    imageList->PushBack(reader->GetOutput());
+
+    MapOfClassesType mapOfClassesClk;
+    ConfusionMatrixType confusionMatrixClk;
+
+    // The data (class labels and confusion matrix values) are read and
+    // extracted from the *.CSV file with an ad-hoc file parser
+    CSVConfusionMatrixFileReader(
+        fileNameConfMat, mapOfClassesClk, confusionMatrixClk);
+
+    // The parameters of the ConfusionMatrixToMassOfBelief filter are set
+    confusionMatrixToMassOfBeliefFilter->SetMapOfClasses(mapOfClassesClk);
+    confusionMatrixToMassOfBeliefFilter->SetConfusionMatrix(confusionMatrixClk);
+    confusionMatrixToMassOfBeliefFilter->SetDefinitionMethod(massOfBeliefDef);
+    confusionMatrixToMassOfBeliefFilter->Update();
+
+    // Vector containing ALL the K (= nbClassifiers) std::map<Label, MOB> of Masses
+    // of Belief
+    vectorOfMapOfMassesOfBelief.push_back(
+        confusionMatrixToMassOfBeliefFilter->GetMapMassOfBelief());
+    }
+// Software Guide : EndCodeSnippet
+
+
+// Software Guide : BeginLatex
+//
+// The image list of input classification maps is converted into a VectorImage to
+// be used as input of the \doxygen{otb}{DSFusionOfClassifiersImageFilter}.
+//
+// Software Guide : EndLatex
+// Software Guide : BeginCodeSnippet
+  // Image List To VectorImage
+  ImageListToVectorImageFilterType::Pointer imageListToVectorImageFilter;
+  imageListToVectorImageFilter = ImageListToVectorImageFilterType::New();
+  imageListToVectorImageFilter->SetInput(imageList);
+
+  DSFusionOfClassifiersImageFilterType::Pointer dsFusionFilter;
+  dsFusionFilter = DSFusionOfClassifiersImageFilterType::New();
+
+  // The parameters of the DSFusionOfClassifiersImageFilter are set
+  dsFusionFilter->SetInput(imageListToVectorImageFilter->GetOutput());
+  dsFusionFilter->SetInputMapsOfMassesOfBelief(&vectorOfMapOfMassesOfBelief);
+  dsFusionFilter->SetLabelForNoDataPixels(nodataLabel);
+  dsFusionFilter->SetLabelForUndecidedPixels(undecidedLabel);
+// Software Guide : EndCodeSnippet
+
+
+// Software Guide : BeginLatex
+//
+// Once it is plugged the pipeline triggers its execution by updating
+// the output of the writer.
+//
+// Software Guide : EndLatex
+
+// Software Guide : BeginCodeSnippet
+
+  WriterType::Pointer writer = WriterType::New();
+  writer->SetInput(dsFusionFilter->GetOutput());
+  writer->SetFileName(outfname);
+  writer->Update();
+// Software Guide : EndCodeSnippet
+  return EXIT_SUCCESS;
+}
diff --git a/Examples/Classification/MajorityVotingFusionOfClassificationMapsExample.cxx b/Examples/Classification/MajorityVotingFusionOfClassificationMapsExample.cxx
new file mode 100644
index 0000000000..0f5551b36d
--- /dev/null
+++ b/Examples/Classification/MajorityVotingFusionOfClassificationMapsExample.cxx
@@ -0,0 +1,134 @@
+/*=========================================================================
+
+  Program:   ORFEO Toolbox
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+
+  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
+  See OTBCopyright.txt for details.
+
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+
+
+// Software Guide : BeginLatex
+//
+// The Majority Voting fusion filter \doxygen{itk}{LabelVotingImageFilter} used is based on ITK.
+// For each pixel, it chooses the more frequent class label among the input classification maps.
+// In case of not unique class labels, the output pixel is set to the \emph{undecidedLabel} value.
+// We start by including the appropriate header file.
+//
+// Software Guide : EndLatex
+
+
+// Software Guide : BeginCodeSnippet
+#include "itkLabelVotingImageFilter.h"
+// Software Guide : EndCodeSnippet
+
+#include "otbImage.h"
+#include "otbImageFileReader.h"
+#include "otbImageFileWriter.h"
+
+int main(int argc, char * argv[])
+{
+// Software Guide : BeginLatex
+//
+// We will assume unsigned short type input labeled images.
+//
+// Software Guide : EndLatex
+// Software Guide : BeginCodeSnippet
+  const unsigned int     Dimension = 2;
+  typedef unsigned short LabelPixelType;
+// Software Guide : EndCodeSnippet
+
+
+  LabelPixelType undecidedLabel = atoi(argv[argc - 2]);
+  const char * outfname = argv[argc - 1];
+
+  unsigned int nbParameters = 2;
+  unsigned int nbClassificationMaps = (argc - 1 - nbParameters);
+
+
+// Software Guide : BeginLatex
+//
+// The input labeled images to be fused are expected to be scalar images.
+//
+// Software Guide : EndLatex
+// Software Guide : BeginCodeSnippet
+  typedef otb::Image<LabelPixelType, Dimension> LabelImageType;
+// Software Guide : EndCodeSnippet
+
+
+// Software Guide : BeginLatex
+//
+// The Majority Voting fusion filter \doxygen{itk}{LabelVotingImageFilter} based on ITK is templated
+// over the input and output labeled image type.
+//
+// Software Guide : EndLatex
+// Software Guide : BeginCodeSnippet
+  // Majority Voting
+  typedef itk::LabelVotingImageFilter<LabelImageType, LabelImageType>
+                                                             LabelVotingFilterType;
+// Software Guide : EndCodeSnippet
+
+// Software Guide : BeginLatex
+//
+// Both reader and writer are defined. Since the images
+// to classify can be very big, we will use a streamed writer which
+// will trigger the streaming ability of the fusion filter.
+//
+// Software Guide : EndLatex
+// Software Guide : BeginCodeSnippet
+  typedef otb::ImageFileReader<LabelImageType> ReaderType;
+  typedef otb::ImageFileWriter<LabelImageType> WriterType;
+// Software Guide : EndCodeSnippet
+
+
+// Software Guide : BeginLatex
+//
+// The input classification maps to be fused are pushed into
+// the \doxygen{itk}{LabelVotingImageFilter}. Moreover, the
+// label value for the undecided pixels (in case of not unique
+// majority voting) is set too.
+//
+// Software Guide : EndLatex
+// Software Guide : BeginCodeSnippet
+  ReaderType::Pointer reader;
+  LabelVotingFilterType::Pointer labelVotingFilter = LabelVotingFilterType::New();
+  for (unsigned int itCM = 0; itCM < nbClassificationMaps; ++itCM)
+    {
+    std::string fileNameClassifiedImage = argv[itCM + 1];
+
+    reader = ReaderType::New();
+    reader->SetFileName(fileNameClassifiedImage);
+    reader->Update();
+
+    labelVotingFilter->SetInput(itCM, reader->GetOutput());
+    }
+
+  labelVotingFilter->SetLabelForUndecidedPixels(undecidedLabel);
+// Software Guide : EndCodeSnippet
+
+
+// Software Guide : BeginLatex
+//
+// Once it is plugged the pipeline triggers its execution by updating
+// the output of the writer.
+//
+// Software Guide : EndLatex
+
+// Software Guide : BeginCodeSnippet
+
+  WriterType::Pointer writer = WriterType::New();
+  writer->SetInput(labelVotingFilter->GetOutput());
+  writer->SetFileName(outfname);
+  writer->Update();
+// Software Guide : EndCodeSnippet
+  return EXIT_SUCCESS;
+}
-- 
GitLab