From 22b2a5ab442da3f01e11ae582fa353d35b1c6690 Mon Sep 17 00:00:00 2001 From: Jordi Inglada <jordi.inglada@cesbio.cnes.fr> Date: Wed, 12 Sep 2018 11:28:02 +0200 Subject: [PATCH] REFAC: move code to functions so that DoExecute logic is readable --- .../app/otbZonalStatistics.cxx | 358 ++++++++++-------- 1 file changed, 198 insertions(+), 160 deletions(-) diff --git a/Modules/Applications/AppClassification/app/otbZonalStatistics.cxx b/Modules/Applications/AppClassification/app/otbZonalStatistics.cxx index 6c6734d33c..85ba0f82cd 100644 --- a/Modules/Applications/AppClassification/app/otbZonalStatistics.cxx +++ b/Modules/Applications/AppClassification/app/otbZonalStatistics.cxx @@ -59,23 +59,23 @@ public: typedef LabelImageType::ValueType LabelValueType; typedef otb::VectorData<double, 2> VectorDataType; typedef otb::VectorDataIntoImageProjectionFilter<VectorDataType, - FloatVectorImageType> VectorDataReprojFilterType; + FloatVectorImageType> VectorDataReprojFilterType; typedef otb::VectorDataToLabelImageFilter<VectorDataType, - LabelImageType> RasterizeFilterType; + LabelImageType> RasterizeFilterType; typedef VectorDataType::DataTreeType DataTreeType; typedef itk::PreOrderTreeIterator<DataTreeType> - TreeIteratorType; + TreeIteratorType; typedef VectorDataType::DataNodeType DataNodeType; typedef DataNodeType::PolygonListPointerType - PolygonListPointerType; + PolygonListPointerType; typedef otb::StreamingStatisticsMapFromLabelImageFilter<FloatVectorImageType, - LabelImageType> StatsFilterType; + LabelImageType> StatsFilterType; typedef otb::StatisticsXMLFileWriter<FloatVectorImageType::PixelType> - StatsWriterType; + StatsWriterType; typedef otb::LabelImageToVectorDataFilter<LabelImageType> - LabelImageToVectorFilterType; + LabelImageToVectorFilterType; typedef itk::BinaryThresholdImageFilter<LabelImageType, - LabelImageType> ThresholdFilterType; + LabelImageType> ThresholdFilterType; /** Standard macro */ itkNewMacro(Self); @@ -90,10 +90,10 @@ public: // Documentation SetDocName("ZonalStatistics"); SetDocLongDescription("This application computes zonal statistics from label image, or vector data. " - "The application inputs one input multiband image, and a label input. " - "If the label input is a raster, the output statistics are exported in a XML file. If the label " - "input is a vector data, the output statistics are exported in a new vector data with statistics " - "in the attribute table. The computed statistics are mean, min, max, and standard deviation."); + "The application inputs one input multiband image, and a label input. " + "If the label input is a raster, the output statistics are exported in a XML file. If the label " + "input is a vector data, the output statistics are exported in a new vector data with statistics " + "in the attribute table. The computed statistics are mean, min, max, and standard deviation."); SetDocLimitations("The shapefile must fit in memory"); SetDocAuthors("Remi Cresson"); @@ -162,15 +162,178 @@ public: return pix; } - void DoExecute() + void PrepareForLabelImageInput() { + otbAppLogINFO("Zone definition: label image"); + // Computing stats + m_StatsFilter->SetInputLabelImage(GetParameterInt32Image("inzone.labelimage.in")); + m_StatsFilter->Update(); + // In this zone definition mode, the user can provide a no-data value for the labels + if (HasUserValue("inzone.labelimage.nodata")) + m_IntNoData = GetParameterInt("inzone.labelimage.nodata"); + } - // Get input image - FloatVectorImageType::Pointer img = GetParameterImage("in"); + void PrepareForVectorDataInput() + { + otbAppLogINFO("Zone definition: vector"); + otbAppLogINFO("Loading vector data..."); + shp = GetParameterVectorData("inzone.vector.in"); + // Reproject vector data + if (GetParameterInt("inzone.vector.reproject") != 0) + { + ReprojectVectorDataIntoInputImage(); + } + else + { + m_VectorDataSrc = shp; + } + RasterizeInputVectorData(); + } + + void ReprojectVectorDataIntoInputImage() + { + otbAppLogINFO("Vector data reprojection enabled"); + m_VectorDataReprojectionFilter = VectorDataReprojFilterType::New(); + m_VectorDataReprojectionFilter->SetInputVectorData(shp); + m_VectorDataReprojectionFilter->SetInputImage(m_InputImage); + AddProcess(m_VectorDataReprojectionFilter, "Reproject vector data"); + m_VectorDataReprojectionFilter->Update(); + m_VectorDataSrc = m_VectorDataReprojectionFilter->GetOutput(); + } + + void RasterizeInputVectorData() + { + // Rasterize vector data + m_RasterizeFilter = RasterizeFilterType::New(); + m_RasterizeFilter->AddVectorData(m_VectorDataSrc); + m_RasterizeFilter->SetOutputOrigin(m_InputImage->GetOrigin()); + m_RasterizeFilter->SetOutputSpacing(m_InputImage->GetSignedSpacing()); + m_RasterizeFilter->SetOutputSize(m_InputImage->GetLargestPossibleRegion().GetSize()); + m_RasterizeFilter->SetOutputProjectionRef(m_InputImage->GetProjectionRef()); + m_RasterizeFilter->SetBurnAttribute("________"); + m_RasterizeFilter->SetDefaultBurnValue(0); + m_RasterizeFilter->SetGlobalWarningDisplay(false); + m_RasterizeFilter->SetBackgroundValue(m_IntNoData); + + // Computing stats + m_StatsFilter->SetInputLabelImage(m_RasterizeFilter->GetOutput()); + m_StatsFilter->Update(); + } + + void RemoveNoDataEntry() + { + m_CountMap = m_StatsFilter->GetLabelPopulationMap(); + m_MeanMap = m_StatsFilter->GetMeanValueMap(); + m_StdMap = m_StatsFilter->GetStandardDeviationValueMap(); + m_MinMap = m_StatsFilter->GetMinValueMap(); + m_MaxMap = m_StatsFilter->GetMaxValueMap(); + if (( GetParameterAsString("inzone") == "labelimage" && HasUserValue("inzone.labelimage.nodata")) + || (GetParameterAsString("inzone") == "vector") ) + { + otbAppLogINFO("Removing entries for label value " << m_IntNoData); + + m_CountMap.erase(m_IntNoData); + m_MeanMap.erase(m_IntNoData); + m_StdMap.erase(m_IntNoData); + m_MinMap.erase(m_IntNoData); + m_MaxMap.erase(m_IntNoData); + } + } + + void GenerateVectorDataFromLabelImage() + { + + // Mask for label image + m_ThresholdFilter = ThresholdFilterType::New(); + m_ThresholdFilter->SetInput(GetParameterInt32Image("inzone.labelimage.in")); + m_ThresholdFilter->SetInsideValue(0); + m_ThresholdFilter->SetOutsideValue(1); + m_ThresholdFilter->SetLowerThreshold(m_IntNoData); + m_ThresholdFilter->SetUpperThreshold(m_IntNoData); + + // Vectorize the image + m_LabelImageToVectorFilter = LabelImageToVectorFilterType::New(); + m_LabelImageToVectorFilter->SetInput(GetParameterInt32Image("inzone.labelimage.in")); + m_LabelImageToVectorFilter->SetInputMask(m_ThresholdFilter->GetOutput()); + m_LabelImageToVectorFilter->SetFieldName("polygon_id"); + AddProcess(m_LabelImageToVectorFilter, "Vectorize label image"); + m_LabelImageToVectorFilter->Update(); + + // The source vector data is the vectorized label image + m_VectorDataSrc = m_LabelImageToVectorFilter->GetOutput(); + + } + + void WriteVectorData() + { + // Add statistics fields + otbAppLogINFO("Writing output vector data"); + LabelValueType internalFID = -1; + m_NewVectorData = VectorDataType::New(); + DataNodeType::Pointer root = m_NewVectorData->GetDataTree()->GetRoot()->Get(); + DataNodeType::Pointer document = DataNodeType::New(); + document->SetNodeType(otb::DOCUMENT); + m_NewVectorData->GetDataTree()->Add(document, root); + DataNodeType::Pointer folder = DataNodeType::New(); + folder->SetNodeType(otb::FOLDER); + m_NewVectorData->GetDataTree()->Add(folder, document); + m_NewVectorData->SetProjectionRef(m_VectorDataSrc->GetProjectionRef()); + TreeIteratorType itVector(m_VectorDataSrc->GetDataTree()); + itVector.GoToBegin(); + + while (!itVector.IsAtEnd()) + { + if (!itVector.Get()->IsRoot() && !itVector.Get()->IsDocument() && !itVector.Get()->IsFolder()) + { + + DataNodeType::Pointer currentGeometry = itVector.Get(); + if (m_FromLabelImage) + internalFID = currentGeometry->GetFieldAsInt("polygon_id"); + else + internalFID++; + + // Add the geometry with the new fields + if (m_CountMap.count(internalFID) > 0) + { + currentGeometry->SetFieldAsDouble("count", m_CountMap[internalFID] ); + for (unsigned int band = 0 ; band < m_InputImage->GetNumberOfComponentsPerPixel() ; band++) + { + currentGeometry->SetFieldAsDouble(CreateFieldName("mean", band), m_MeanMap[internalFID][band] ); + currentGeometry->SetFieldAsDouble(CreateFieldName("stdev", band), m_StdMap [internalFID][band] ); + currentGeometry->SetFieldAsDouble(CreateFieldName("min", band), m_MinMap [internalFID][band] ); + currentGeometry->SetFieldAsDouble(CreateFieldName("max", band), m_MaxMap [internalFID][band] ); + } + m_NewVectorData->GetDataTree()->Add(currentGeometry, folder); + } + } + ++itVector; + } // next feature + SetParameterOutputVectorData("out.vector.filename", m_NewVectorData); + } + + void WriteXMLStatsFile() + { + // Write statistics in XML file + const std::string outXMLFile = this->GetParameterString("out.xml.filename"); + otbAppLogINFO("Writing " + outXMLFile) + StatsWriterType::Pointer statWriter = StatsWriterType::New(); + statWriter->SetFileName(outXMLFile); + statWriter->AddInputMap<StatsFilterType::LabelPopulationMapType>("count",m_CountMap); + statWriter->AddInputMap<StatsFilterType::PixelValueMapType>("mean",m_MeanMap); + statWriter->AddInputMap<StatsFilterType::PixelValueMapType>("std",m_StdMap); + statWriter->AddInputMap<StatsFilterType::PixelValueMapType>("min",m_MinMap); + statWriter->AddInputMap<StatsFilterType::PixelValueMapType>("max",m_MaxMap); + statWriter->Update(); + } + + void DoExecute() + { + // Get input image + m_InputImage = GetParameterImage("in"); // Statistics filter m_StatsFilter = StatsFilterType::New(); - m_StatsFilter->SetInput(img); + m_StatsFilter->SetInput(m_InputImage); if (HasUserValue("inbv")) { m_StatsFilter->SetUseNoDataValue(true); @@ -178,170 +341,36 @@ public: } m_StatsFilter->GetStreamer()->SetAutomaticAdaptativeStreaming(GetParameterInt("ram")); AddProcess(m_StatsFilter->GetStreamer(), "Computing statistics"); - // Internal no-data value - LabelValueType intNoData = itk::NumericTraits<LabelValueType>::max(); - + m_IntNoData = itk::NumericTraits<LabelValueType>::max(); // Select zone definition mode - const bool fromLabelImage = (GetParameterAsString("inzone") == "labelimage"); - if (fromLabelImage) + m_FromLabelImage = (GetParameterAsString("inzone") == "labelimage"); + if (m_FromLabelImage) { - otbAppLogINFO("Zone definition: label image"); - - // Computing stats - m_StatsFilter->SetInputLabelImage(GetParameterInt32Image("inzone.labelimage.in")); - m_StatsFilter->Update(); - - // In this zone definition mode, the user can provide a no-data value for the labels - if (HasUserValue("inzone.labelimage.nodata")) - intNoData = GetParameterInt("inzone.labelimage.nodata"); - + PrepareForLabelImageInput(); } else if (GetParameterAsString("inzone") == "vector") { - otbAppLogINFO("Zone definition: vector"); - - otbAppLogINFO("Loading vector data..."); - VectorDataType* shp = GetParameterVectorData("inzone.vector.in"); - - // Reproject vector data - if (GetParameterInt("inzone.vector.reproject") != 0) - { - otbAppLogINFO("Vector data reprojection enabled"); - m_VectorDataReprojectionFilter = VectorDataReprojFilterType::New(); - m_VectorDataReprojectionFilter->SetInputVectorData(shp); - m_VectorDataReprojectionFilter->SetInputImage(img); - AddProcess(m_VectorDataReprojectionFilter, "Reproject vector data"); - m_VectorDataReprojectionFilter->Update(); - m_VectorDataSrc = m_VectorDataReprojectionFilter->GetOutput(); - } - else - { - m_VectorDataSrc = shp; - } - - // Rasterize vector data - m_RasterizeFilter = RasterizeFilterType::New(); - m_RasterizeFilter->AddVectorData(m_VectorDataSrc); - m_RasterizeFilter->SetOutputOrigin(img->GetOrigin()); - m_RasterizeFilter->SetOutputSpacing(img->GetSignedSpacing()); - m_RasterizeFilter->SetOutputSize(img->GetLargestPossibleRegion().GetSize()); - m_RasterizeFilter->SetOutputProjectionRef(img->GetProjectionRef()); - m_RasterizeFilter->SetBurnAttribute("________"); - m_RasterizeFilter->SetDefaultBurnValue(0); - m_RasterizeFilter->SetGlobalWarningDisplay(false); - m_RasterizeFilter->SetBackgroundValue(intNoData); - - // Computing stats - m_StatsFilter->SetInputLabelImage(m_RasterizeFilter->GetOutput()); - m_StatsFilter->Update(); + PrepareForVectorDataInput(); } else { otbAppLogFATAL("Unknown zone definition mode"); } - // Remove the no-data entry - StatsFilterType::LabelPopulationMapType countMap = m_StatsFilter->GetLabelPopulationMap(); - StatsFilterType::PixelValueMapType meanMap = m_StatsFilter->GetMeanValueMap(); - StatsFilterType::PixelValueMapType stdMap = m_StatsFilter->GetStandardDeviationValueMap(); - StatsFilterType::PixelValueMapType minMap = m_StatsFilter->GetMinValueMap(); - StatsFilterType::PixelValueMapType maxMap = m_StatsFilter->GetMaxValueMap(); - if (( GetParameterAsString("inzone") == "labelimage" && HasUserValue("inzone.labelimage.nodata")) - || (GetParameterAsString("inzone") == "vector") ) - { - otbAppLogINFO("Removing entries for label value " << intNoData); - - countMap.erase(intNoData); - meanMap.erase(intNoData); - stdMap.erase(intNoData); - minMap.erase(intNoData); - maxMap.erase(intNoData); - } - + RemoveNoDataEntry(); // Generate output if (GetParameterAsString("out") == "vector") { - if (fromLabelImage) + if (m_FromLabelImage) { - // Mask for label image - m_ThresholdFilter = ThresholdFilterType::New(); - m_ThresholdFilter->SetInput(GetParameterInt32Image("inzone.labelimage.in")); - m_ThresholdFilter->SetInsideValue(0); - m_ThresholdFilter->SetOutsideValue(1); - m_ThresholdFilter->SetLowerThreshold(intNoData); - m_ThresholdFilter->SetUpperThreshold(intNoData); - - // Vectorize the image - m_LabelImageToVectorFilter = LabelImageToVectorFilterType::New(); - m_LabelImageToVectorFilter->SetInput(GetParameterInt32Image("inzone.labelimage.in")); - m_LabelImageToVectorFilter->SetInputMask(m_ThresholdFilter->GetOutput()); - m_LabelImageToVectorFilter->SetFieldName("polygon_id"); - AddProcess(m_LabelImageToVectorFilter, "Vectorize label image"); - m_LabelImageToVectorFilter->Update(); - - // The source vector data is the vectorized label image - m_VectorDataSrc = m_LabelImageToVectorFilter->GetOutput(); + GenerateVectorDataFromLabelImage(); } - - // Add statistics fields - otbAppLogINFO("Writing output vector data"); - LabelValueType internalFID = -1; - m_NewVectorData = VectorDataType::New(); - DataNodeType::Pointer root = m_NewVectorData->GetDataTree()->GetRoot()->Get(); - DataNodeType::Pointer document = DataNodeType::New(); - document->SetNodeType(otb::DOCUMENT); - m_NewVectorData->GetDataTree()->Add(document, root); - DataNodeType::Pointer folder = DataNodeType::New(); - folder->SetNodeType(otb::FOLDER); - m_NewVectorData->GetDataTree()->Add(folder, document); - m_NewVectorData->SetProjectionRef(m_VectorDataSrc->GetProjectionRef()); - TreeIteratorType itVector(m_VectorDataSrc->GetDataTree()); - itVector.GoToBegin(); - - while (!itVector.IsAtEnd()) - { - if (!itVector.Get()->IsRoot() && !itVector.Get()->IsDocument() && !itVector.Get()->IsFolder()) - { - - DataNodeType::Pointer currentGeometry = itVector.Get(); - if (fromLabelImage) - internalFID = currentGeometry->GetFieldAsInt("polygon_id"); - else - internalFID++; - - // Add the geometry with the new fields - if (countMap.count(internalFID) > 0) - { - currentGeometry->SetFieldAsDouble("count", countMap[internalFID] ); - for (unsigned int band = 0 ; band < img->GetNumberOfComponentsPerPixel() ; band++) - { - currentGeometry->SetFieldAsDouble(CreateFieldName("mean", band), meanMap[internalFID][band] ); - currentGeometry->SetFieldAsDouble(CreateFieldName("stdev", band), stdMap [internalFID][band] ); - currentGeometry->SetFieldAsDouble(CreateFieldName("min", band), minMap [internalFID][band] ); - currentGeometry->SetFieldAsDouble(CreateFieldName("max", band), maxMap [internalFID][band] ); - } - m_NewVectorData->GetDataTree()->Add(currentGeometry, folder); - } - } - ++itVector; - } // next feature - - SetParameterOutputVectorData("out.vector.filename", m_NewVectorData); + WriteVectorData(); } else if (GetParameterAsString("out") == "xml") { - // Write statistics in XML file - const std::string outXMLFile = this->GetParameterString("out.xml.filename"); - otbAppLogINFO("Writing " + outXMLFile) - StatsWriterType::Pointer statWriter = StatsWriterType::New(); - statWriter->SetFileName(outXMLFile); - statWriter->AddInputMap<StatsFilterType::LabelPopulationMapType>("count",countMap); - statWriter->AddInputMap<StatsFilterType::PixelValueMapType>("mean",meanMap); - statWriter->AddInputMap<StatsFilterType::PixelValueMapType>("std",stdMap); - statWriter->AddInputMap<StatsFilterType::PixelValueMapType>("min",minMap); - statWriter->AddInputMap<StatsFilterType::PixelValueMapType>("max",maxMap); - statWriter->Update(); + WriteXMLStatsFile(); } else { @@ -352,11 +381,20 @@ public: VectorDataType::Pointer m_VectorDataSrc; VectorDataType::Pointer m_NewVectorData; + VectorDataType* shp; VectorDataReprojFilterType::Pointer m_VectorDataReprojectionFilter; RasterizeFilterType::Pointer m_RasterizeFilter; StatsFilterType::Pointer m_StatsFilter; LabelImageToVectorFilterType::Pointer m_LabelImageToVectorFilter; ThresholdFilterType::Pointer m_ThresholdFilter; + FloatVectorImageType::Pointer m_InputImage; + LabelValueType m_IntNoData; + bool m_FromLabelImage; + StatsFilterType::LabelPopulationMapType m_CountMap; + StatsFilterType::PixelValueMapType m_MeanMap; + StatsFilterType::PixelValueMapType m_StdMap; + StatsFilterType::PixelValueMapType m_MinMap; + StatsFilterType::PixelValueMapType m_MaxMap; }; } -- GitLab