HooverMetricsEstimation.cxx 8.78 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
STYLE  
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
STYLE  
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
STYLE  
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
STYLE  
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
STYLE  
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
STYLE  
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 77
// 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 "otbAttributesMapLabelObject.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;
    }
78

79 80
  // Software Guide : BeginLatex
  // The filters \doxygen{otb}{HooverMatrixFilter} and \doxygen{otb}{HooverInstanceFilter}
81
  // are designed to handle \doxygen{itk}{LabelMap} images, made with \doxygen{otb}{AttributesMapLabelObject}.
OTB Bot's avatar
STYLE  
OTB Bot committed
82
  // This type of label object allows to store generic attributes. Each region can store
83
  // a set of attributes: in this case, Hoover instances and metrics will be stored.
84 85 86 87 88 89 90
  // 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;
91

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

96 97 98 99 100 101
  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;
102

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

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

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

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

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

126 127 128 129
  // 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
130

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

138 139
  // Software Guide : BeginLatex
  // The instance filter computes the Hoover metrics for each region. These metrics
OTB Bot's avatar
STYLE  
OTB Bot committed
140
  // are stored as attributes in each label object. The threshold parameter
141
  // corresponds to the overlapping ratio above which two regions can be matched.
142
  // The extended attributes can be used if the user wants to keep a trace of the
OTB Bot's avatar
STYLE  
OTB Bot committed
143 144
  // 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
145 146
  // of the associated MS region (the same principle goes for other types of instance).
  // Software Guide : EndLatex
147

148 149 150 151 152 153 154 155
  // 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
156

157 158 159 160 161
  // 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
162

163 164 165
  // Software Guide : BeginCodeSnippet
  AttributeImageFilterType::Pointer attributeImageGT = AttributeImageFilterType::New();
  attributeImageGT->SetInput(instances->GetOutputGroundTruthLabelMap());
166 167 168 169
  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));
170

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

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

183 184 185 186 187 188 189
  // 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
190

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

196 197
  return EXIT_SUCCESS;
}