diff --git a/Examples/Classification/CMakeLists.txt b/Examples/Classification/CMakeLists.txt index 6fdc0a12eecca9dde200701fb6391d5e8385e71e..64aedec0e9347a33a7e7c06a585ce7cf411002be 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 0000000000000000000000000000000000000000..e1c50cf926d75e8a86120baf4db6a0a0f5b27abd --- /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 0000000000000000000000000000000000000000..0f5551b36db0965f2276b2c5ad2c974d0e230306 --- /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; +}