otbDensePolygonClassStatistics.cxx 10.33 KiB
/*=========================================================================
     Copyright (c) 2018-2019 IRSTEA
     Copyright (c) 2020-2021 INRAE
     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.
=========================================================================*/
#include "itkFixedArray.h"
#include "itkObjectFactory.h"
#include "otbWrapperApplicationFactory.h"
// Application engine
#include "otbStandardFilterWatcher.h"
#include "itkFixedArray.h"
// Filters
#include "otbStatisticsXMLFileWriter.h"
#include "otbWrapperElevationParametersHandler.h"
#include "otbVectorDataToLabelImageFilter.h"
#include "otbImageToNoDataMaskFilter.h"
#include "otbStreamingStatisticsMapFromLabelImageFilter.h"
#include "otbVectorDataIntoImageProjectionFilter.h"
#include "otbImageToVectorImageCastFilter.h"
// OGR
#include "otbOGR.h"
namespace otb
namespace Wrapper
/** Utility function to negate std::isalnum */
bool IsNotAlphaNum(char c)
  return !std::isalnum(c);
class DensePolygonClassStatistics : public Application
public:
  /** Standard class typedefs. */
  typedef DensePolygonClassStatistics   Self;
  typedef Application                   Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;
  /** Standard macro */
  itkNewMacro(Self);
  itkTypeMacro(DensePolygonClassStatistics, Application);
  /** DataObjects typedef */
  typedef UInt32ImageType                           LabelImageType;
  typedef UInt8ImageType                            MaskImageType;
  typedef VectorData<>                              VectorDataType;
  /** ProcessObjects typedef */
  typedef otb::VectorDataIntoImageProjectionFilter<VectorDataType,
      FloatVectorImageType>                                                       VectorDataReprojFilterType;
  typedef otb::VectorDataToLabelImageFilter<VectorDataType, LabelImageType>       RasterizeFilterType;
  typedef otb::VectorImage<MaskImageType::PixelType>                              InternalMaskImageType;
  typedef otb::ImageToNoDataMaskFilter<FloatVectorImageType, MaskImageType>       NoDataMaskFilterType;
  typedef otb::ImageToVectorImageCastFilter<MaskImageType, InternalMaskImageType> CastFilterType;
  typedef otb::StreamingStatisticsMapFromLabelImageFilter<InternalMaskImageType,
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
LabelImageType> StatsFilterType; typedef otb::StatisticsXMLFileWriter<FloatVectorImageType::PixelType> StatWriterType; void DoInit() { SetName("DensePolygonClassStatistics"); SetDescription("Computes statistics on a training polygon set."); // Documentation SetDocLongDescription("The application processes a dense set of polygons " "intended for training (they should have a field giving the associated " "class). The geometries are analyzed against a support image to compute " "statistics : \n" " - number of samples per class\n" " - number of samples per geometry\n"); SetDocLimitations("None"); SetDocAuthors("Remi Cresson"); AddDocTag(Tags::Learning); AddParameter(ParameterType_InputImage, "in", "Input image"); SetParameterDescription("in", "Support image that will be classified"); AddParameter(ParameterType_InputVectorData, "vec", "Input vectors"); SetParameterDescription("vec","Input geometries to analyze"); AddParameter(ParameterType_OutputFilename, "out", "Output XML statistics file"); SetParameterDescription("out","Output file to store statistics (XML format)"); AddParameter(ParameterType_ListView, "field", "Field Name"); SetParameterDescription("field","Name of the field carrying the class number in the input vectors."); SetListViewSingleSelectionMode("field",true); ElevationParametersHandler::AddElevationParameters(this, "elev"); AddRAMParameter(); // Doc example parameter settings SetDocExampleParameterValue("in", "support_image.tif"); SetDocExampleParameterValue("vec", "variousVectors.shp"); SetDocExampleParameterValue("field", "label"); SetDocExampleParameterValue("out","polygonStat.xml"); } void DoExecute() { // Retrieve the field name std::vector<int> selectedCFieldIdx = GetSelectedItems("field"); if(selectedCFieldIdx.empty()) { otbAppLogFATAL(<<"No field has been selected for data labelling!"); } std::vector<std::string> cFieldNames = GetChoiceNames("field"); std::string fieldName = cFieldNames[selectedCFieldIdx.front()]; otb::Wrapper::ElevationParametersHandler::SetupDEMHandlerFromElevationParameters(this,"elev"); // Get inputs FloatVectorImageType::Pointer xs = GetParameterImage("in"); VectorDataType* shp = GetParameterVectorData("vec"); // Reproject vector data m_VectorDataReprojectionFilter = VectorDataReprojFilterType::New(); m_VectorDataReprojectionFilter->SetInputVectorData(shp); m_VectorDataReprojectionFilter->SetInputImage(xs);
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
m_VectorDataReprojectionFilter->Update(); // Internal no-data value const LabelImageType::ValueType intNoData = itk::NumericTraits<LabelImageType::ValueType>::max(); // Rasterize vector data (geometry ID) m_RasterizeFIDFilter = RasterizeFilterType::New(); m_RasterizeFIDFilter->AddVectorData(m_VectorDataReprojectionFilter->GetOutput()); m_RasterizeFIDFilter->SetOutputOrigin(xs->GetOrigin()); m_RasterizeFIDFilter->SetOutputSpacing(xs->GetSignedSpacing()); m_RasterizeFIDFilter->SetOutputSize(xs->GetLargestPossibleRegion().GetSize()); m_RasterizeFIDFilter->SetBurnAttribute("________"); // Trick to get the polygon ID m_RasterizeFIDFilter->SetGlobalWarningDisplay(false); m_RasterizeFIDFilter->SetOutputProjectionRef(xs->GetProjectionRef()); m_RasterizeFIDFilter->SetBackgroundValue(intNoData); m_RasterizeFIDFilter->SetDefaultBurnValue(0); // Rasterize vector data (geometry class) m_RasterizeClassFilter = RasterizeFilterType::New(); m_RasterizeClassFilter->AddVectorData(m_VectorDataReprojectionFilter->GetOutput()); m_RasterizeClassFilter->SetOutputOrigin(xs->GetOrigin()); m_RasterizeClassFilter->SetOutputSpacing(xs->GetSignedSpacing()); m_RasterizeClassFilter->SetOutputSize(xs->GetLargestPossibleRegion().GetSize()); m_RasterizeClassFilter->SetBurnAttribute(fieldName); m_RasterizeClassFilter->SetOutputProjectionRef(xs->GetProjectionRef()); m_RasterizeClassFilter->SetBackgroundValue(intNoData); m_RasterizeClassFilter->SetDefaultBurnValue(0); // No data mask m_NoDataFilter = NoDataMaskFilterType::New(); m_NoDataFilter->SetInput(xs); m_NoDataCastFilter = CastFilterType::New(); m_NoDataCastFilter->SetInput(m_NoDataFilter->GetOutput()); // Stats (geometry ID) m_FIDStatsFilter = StatsFilterType::New(); m_FIDStatsFilter->SetInput(m_NoDataCastFilter->GetOutput()); m_FIDStatsFilter->SetInputLabelImage(m_RasterizeFIDFilter->GetOutput()); m_FIDStatsFilter->GetStreamer()->SetAutomaticAdaptativeStreaming(GetParameterInt("ram")); AddProcess(m_FIDStatsFilter->GetStreamer(), "Computing number of samples per vector"); m_FIDStatsFilter->Update(); // Stats (geometry class) m_ClassStatsFilter = StatsFilterType::New(); m_ClassStatsFilter->SetInput(m_NoDataCastFilter->GetOutput()); m_ClassStatsFilter->SetInputLabelImage(m_RasterizeClassFilter->GetOutput()); m_ClassStatsFilter->GetStreamer()->SetAutomaticAdaptativeStreaming(GetParameterInt("ram")); AddProcess(m_ClassStatsFilter->GetStreamer(), "Computing number of samples per class"); m_ClassStatsFilter->Update(); // Remove the no-data entries StatsFilterType::LabelPopulationMapType fidMap = m_FIDStatsFilter->GetLabelPopulationMap(); StatsFilterType::LabelPopulationMapType classMap = m_ClassStatsFilter->GetLabelPopulationMap(); fidMap.erase(intNoData); classMap.erase(intNoData); m_StatWriter = StatWriterType::New(); m_StatWriter->SetFileName(this->GetParameterString("out")); m_StatWriter->AddInputMap<StatsFilterType::LabelPopulationMapType>("samplesPerClass", classMap); m_StatWriter->AddInputMap<StatsFilterType::LabelPopulationMapType>("samplesPerVector", fidMap); m_StatWriter->Update(); } void DoUpdateParameters() { if (HasValue("vec")) { std::string vectorFile = GetParameterString("vec");
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
ogr::DataSource::Pointer ogrDS = ogr::DataSource::New(vectorFile, ogr::DataSource::Modes::Read); ogr::Layer layer = ogrDS->GetLayer(0); ogr::Feature feature = layer.ogr().GetNextFeature(); ClearChoices("field"); for(int iField=0; iField<feature.ogr().GetFieldCount(); iField++) { std::string key, item = feature.ogr().GetFieldDefnRef(iField)->GetNameRef(); key = item; std::string::iterator end = std::remove_if(key.begin(),key.end(),IsNotAlphaNum); std::transform(key.begin(), end, key.begin(), tolower); OGRFieldType fieldType = feature.ogr().GetFieldDefnRef(iField)->GetType(); if(fieldType == OFTString || fieldType == OFTInteger || fieldType == OFTInteger64) { std::string tmpKey="field."+key.substr(0, end - key.begin()); AddChoice(tmpKey,item); } } } // Check that the extension of the output parameter is XML (mandatory for // StatisticsXMLFileWriter) // Check it here to trigger the error before polygons analysis if (HasValue("out")) { // Store filename extension // Check that the right extension is given : expected .xml const std::string extension = itksys::SystemTools::GetFilenameLastExtension(this->GetParameterString("out")); if (itksys::SystemTools::LowerCase(extension) != ".xml") { otbAppLogFATAL( << extension << " is a wrong extension for parameter \"out\": Expected .xml" ); } } } private: // Filters VectorDataReprojFilterType::Pointer m_VectorDataReprojectionFilter; RasterizeFilterType::Pointer m_RasterizeFIDFilter; RasterizeFilterType::Pointer m_RasterizeClassFilter; NoDataMaskFilterType::Pointer m_NoDataFilter; CastFilterType::Pointer m_NoDataCastFilter; StatsFilterType::Pointer m_FIDStatsFilter; StatsFilterType::Pointer m_ClassStatsFilter; StatWriterType::Pointer m_StatWriter; }; } // end of namespace Wrapper } // end of namespace otb OTB_APPLICATION_EXPORT(otb::Wrapper::DensePolygonClassStatistics)