HooverMetricsEstimation.cxx 8.74 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$


  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

  Some parts of this code are derived from ITK. See ITKCopyright.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 : BeginCommandLineArgs
//  INPUTS: {maur_GT.tif}, {maur_labelled.tif}
//  OUTPUTS: {maur_colored_GT.tif}
//  Software Guide : EndCommandLineArgs

// Software Guide : BeginLatex
//
// The following example shows how to compare two segmentations, using Hoover
// metrics. For instance, it can be used to compare a segmentation produced
OTB Bot's avatar
OTB Bot committed
32
// by your algorithm against a partial ground truth segmentation. In this
33 34 35
// example, the ground truth segmentation will be refered by the letters GT
// whereas the machine segmentation will be refered by MS.
//
OTB Bot's avatar
OTB Bot committed
36
// The estimation of Hoover metrics is done with two filters :
37 38 39 40 41
// \doxygen{otb}{HooverMatrixFilter} and \doxygen{otb}{HooverInstanceFilter}.
// The first one produces a matrix containing the number of overlapping pixels
// between MS regions and GT regions. The second one classifies each region among
// four types (called Hoover instances):
// \begin{itemize}
OTB Bot's avatar
OTB Bot committed
42
// \item Correct detection : a region is matched with an other one in the
43
// opposite segmentation, because they cover nearly the same area.
OTB Bot's avatar
OTB Bot committed
44
// \item Over-segmentation : a GT region is matched with a group of MS
45 46 47
// regions because they cover nearly the same area.
// \item Under-segmentation : a MS region is matched with a group of GT
// regions because they cover nearly the same area.
OTB Bot's avatar
OTB Bot committed
48
// \item Missed detection (for GT regions) or Noise (for MS region) :
49 50 51
// un-matched regions.
// \end{itemize}
// Note that a region can be tagged with two types. When the Hoover instance
OTB Bot's avatar
OTB Bot committed
52
// have been found, the instance filter computes overall scores for each
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
// category : they are the Hoover metrics \footnote{see http://www.trop.mips.uha.fr/pdf/ORASIS-2009.pdf}.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "otbHooverMatrixFilter.h"
#include "otbHooverInstanceFilter.h"
#include "otbLabelMapToAttributeImageFilter.h"
// Software Guide : EndCodeSnippet

#include "otbImage.h"
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
#include "itkLabelImageToLabelMapFilter.h"

int main(int argc, char* argv[])
{
  if(argc != 4)
    {
    std::cerr << "Usage: " << argv[0];
    std::cerr << " segmentationGT segmentationMS outputAttributeImage" << std::endl;
    return EXIT_FAILURE;
    }
77

78 79
  // Software Guide : BeginLatex
  // The filters \doxygen{otb}{HooverMatrixFilter} and \doxygen{otb}{HooverInstanceFilter}
80
  // are designed to handle \doxygen{itk}{LabelMap} images, made with \doxygen{otb}{AttributesMapLabelObject}.
81
  // This type of label object allows storing generic attributes. Each region can store
82
  // a set of attributes: in this case, Hoover instances and metrics will be stored.
83 84 85 86 87 88 89
  // Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef otb::AttributesMapLabelObject<unsigned int, 2, float> LabelObjectType;
  typedef itk::LabelMap<LabelObjectType>            LabelMapType;
  typedef otb::HooverMatrixFilter<LabelMapType>     HooverMatrixFilterType;
  typedef otb::HooverInstanceFilter<LabelMapType>   InstanceFilterType;
90

91 92 93
  typedef otb::Image<unsigned int, 2>               ImageType;
  typedef itk::LabelImageToLabelMapFilter
    <ImageType, LabelMapType>                       ImageToLabelMapFilterType;
94

95 96 97 98 99 100
  typedef otb::VectorImage<float, 2>                VectorImageType;
  typedef otb::LabelMapToAttributeImageFilter
      <LabelMapType, VectorImageType>               AttributeImageFilterType;
  // Software Guide : EndCodeSnippet
  typedef otb::ImageFileReader<ImageType>           ImageReaderType;
  typedef otb::ImageFileWriter<VectorImageType>     WriterType;
101

102 103
  ImageReaderType::Pointer gt_reader = ImageReaderType::New();
  gt_reader->SetFileName(argv[1]);
104

105 106
  ImageReaderType::Pointer ms_reader = ImageReaderType::New();
  ms_reader->SetFileName(argv[2]);
107

108
  // Software Guide : BeginLatex
OTB Bot's avatar
OTB Bot committed
109
  // The first step is to convert the images to label maps : we use
110
  // \doxygen{itk}{LabelImageToLabelMapFilter}. The background value sets
OTB Bot's avatar
OTB Bot committed
111
  // the label value of regions considered as background: there is no label object for the
112 113
  // background region.
  // Software Guide : EndLatex
114

115 116 117 118
  // Software Guide : BeginCodeSnippet
  ImageToLabelMapFilterType::Pointer gt_filter = ImageToLabelMapFilterType::New();
  gt_filter->SetInput(gt_reader->GetOutput());
  gt_filter->SetBackgroundValue(0);
119

120 121 122 123
  ImageToLabelMapFilterType::Pointer ms_filter = ImageToLabelMapFilterType::New();
  ms_filter->SetInput(ms_reader->GetOutput());
  ms_filter->SetBackgroundValue(0);
  // Software Guide : EndCodeSnippet
124

125 126 127 128
  // Software Guide : BeginLatex
  // The Hoover matrix filter has to be updated here. This matrix must be computed
  // before being given to the instance filter.
  // Software Guide : EndLatex
129

130 131 132 133 134 135
  // Software Guide : BeginCodeSnippet
  HooverMatrixFilterType::Pointer hooverFilter = HooverMatrixFilterType::New();
  hooverFilter->SetGroundTruthLabelMap(gt_filter->GetOutput());
  hooverFilter->SetMachineSegmentationLabelMap(ms_filter->GetOutput());
  hooverFilter->Update();
  // Software Guide : EndCodeSnippet
136

137 138
  // Software Guide : BeginLatex
  // The instance filter computes the Hoover metrics for each region. These metrics
OTB Bot's avatar
OTB Bot committed
139
  // are stored as attributes in each label object. The threshold parameter
140
  // corresponds to the overlapping ratio above which two regions can be matched.
141
  // The extended attributes can be used if the user wants to keep a trace of the
OTB Bot's avatar
OTB Bot committed
142 143
  // associations between MS and GT regions : i.e. if a GT region has been matched
  // as a correct detection, it will carry an attribute containing the label value
144 145
  // of the associated MS region (the same principle goes for other types of instance).
  // Software Guide : EndLatex
146

147 148 149 150 151 152 153 154
  // Software Guide : BeginCodeSnippet
  InstanceFilterType::Pointer instances = InstanceFilterType::New();
  instances->SetGroundTruthLabelMap(gt_filter->GetOutput());
  instances->SetMachineSegmentationLabelMap(ms_filter->GetOutput());
  instances->SetThreshold(0.75);
  instances->SetHooverMatrix(hooverFilter->GetHooverConfusionMatrix());
  instances->SetUseExtendedAttributes(false);
  // Software Guide : EndCodeSnippet
155

156 157 158 159 160
  // Software Guide : BeginLatex
  // The \doxygen{otb}{LabelMapToAttributeImageFilter} is designed to extract attributes
  // values from a label map and output them in the channels of a vector image. We set
  // the attribute to plot in each channel.
  // Software Guide : EndLatex
161

162 163 164
  // Software Guide : BeginCodeSnippet
  AttributeImageFilterType::Pointer attributeImageGT = AttributeImageFilterType::New();
  attributeImageGT->SetInput(instances->GetOutputGroundTruthLabelMap());
165 166 167 168
  attributeImageGT->SetAttributeForNthChannel(0, InstanceFilterType::GetNameFromAttribute(InstanceFilterType::ATTRIBUTE_RC));
  attributeImageGT->SetAttributeForNthChannel(1, InstanceFilterType::GetNameFromAttribute(InstanceFilterType::ATTRIBUTE_RF));
  attributeImageGT->SetAttributeForNthChannel(2, InstanceFilterType::GetNameFromAttribute(InstanceFilterType::ATTRIBUTE_RA));
  attributeImageGT->SetAttributeForNthChannel(3, InstanceFilterType::GetNameFromAttribute(InstanceFilterType::ATTRIBUTE_RM));
169

170 171 172 173 174
  WriterType::Pointer writer = WriterType::New();
  writer->SetInput(attributeImageGT->GetOutput());
  writer->SetFileName(argv[3]);
  writer->Update();
  // Software Guide : EndCodeSnippet
175

176 177
  // Software Guide : BeginLatex
  // The output image contains for each GT region its correct detection score ("RC", band 1),
OTB Bot's avatar
OTB Bot committed
178
  // its over-segmentation score ("RF", band 2), its under-segmentation score ("RA", band 3)
179 180
  // and its missed detection score ("RM", band 4).
  // Software Guide : EndLatex
181

182 183 184 185 186 187 188
  // Software Guide : BeginCodeSnippet
  std::cout << "Mean RC ="<< instances->GetMeanRC() << std::endl;
  std::cout << "Mean RF ="<< instances->GetMeanRF() << std::endl;
  std::cout << "Mean RA ="<< instances->GetMeanRA() << std::endl;
  std::cout << "Mean RM ="<< instances->GetMeanRM() << std::endl;
  std::cout << "Mean RN ="<< instances->GetMeanRN() << std::endl;
  // Software Guide : EndCodeSnippet
189

190
  // Software Guide : BeginLatex
OTB Bot's avatar
OTB Bot committed
191
  // The Hoover scores are also computed for the whole segmentations. Here is some explanation about the score names :
192 193
  // C = correct, F = fragmentation, A = aggregation, M = missed, N = noise.
  // Software Guide : EndLatex
194

195 196
  return EXIT_SUCCESS;
}