Forked from HYCAR-Hydro / airGR
Source project has a limited visibility.
otbPatchesExtraction.cxx 9.15 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"
// Filter
#include "otbTensorflowSampler.h"
// Stack
#include "otbTensorflowSource.h"
namespace otb
namespace Wrapper
class PatchesExtraction : public Application
public:
  /** Standard class typedefs. */
  typedef PatchesExtraction                   Self;
  typedef Application                         Superclass;
  typedef itk::SmartPointer<Self>             Pointer;
  typedef itk::SmartPointer<const Self>       ConstPointer;
  /** Standard macro */
  itkNewMacro(Self);
  itkTypeMacro(PatchesExtraction, Application);
  /** Filter typedef */
  typedef otb::TensorflowSampler<FloatVectorImageType, VectorDataType> SamplerType;
  /** Typedefs for image concatenation */
  typedef TensorflowSource<FloatVectorImageType>                       TFSourceType;
  // Store stuff related to one source
  struct SourceBundle
    TFSourceType                       m_ImageSource;   // Image source
    FloatVectorImageType::SizeType     m_PatchSize;          // Patch size
    std::string                        m_KeyIn;   // Key of input image list
    std::string                        m_KeyOut;  // Key of output samples image
    std::string                        m_KeyPszX; // Key for samples sizes X
    std::string                        m_KeyPszY; // Key for samples sizes Y
    std::string                        m_KeyNoData; // Key for no-data value
    FloatVectorImageType::InternalPixelType m_NoDataValue; // No data value
  // Add an input source, which includes:
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
// -an input image list // -an output image (samples) // -an input patchsize (dimensions of samples) // void AddAnInputImage() { // Number of source unsigned int inputNumber = m_Bundles.size() + 1; // Create keys and descriptions std::stringstream ss_group_key, ss_desc_group, ss_key_in, ss_key_out, ss_desc_in, ss_desc_out, ss_key_dims_x, ss_desc_dims_x, ss_key_dims_y, ss_desc_dims_y, ss_key_nodata, ss_desc_nodata; ss_group_key << "source" << inputNumber; ss_desc_group << "Parameters for source " << inputNumber; ss_key_out << ss_group_key.str() << ".out"; ss_desc_out << "Output patches for image " << inputNumber; ss_key_in << ss_group_key.str() << ".il"; ss_desc_in << "Input image(s) " << inputNumber; ss_key_dims_x << ss_group_key.str() << ".patchsizex"; ss_desc_dims_x << "X patch size for image " << inputNumber; ss_key_dims_y << ss_group_key.str() << ".patchsizey"; ss_desc_dims_y << "Y patch size for image " << inputNumber; ss_key_nodata << ss_group_key.str() << ".nodata"; ss_desc_nodata << "No-data value for image " << inputNumber; // Populate group AddParameter(ParameterType_Group, ss_group_key.str(), ss_desc_group.str()); AddParameter(ParameterType_InputImageList, ss_key_in.str(), ss_desc_in.str() ); AddParameter(ParameterType_OutputImage, ss_key_out.str(), ss_desc_out.str()); AddParameter(ParameterType_Int, ss_key_dims_x.str(), ss_desc_dims_x.str()); SetMinimumParameterIntValue (ss_key_dims_x.str(), 1); AddParameter(ParameterType_Int, ss_key_dims_y.str(), ss_desc_dims_y.str()); SetMinimumParameterIntValue (ss_key_dims_y.str(), 1); AddParameter(ParameterType_Float, ss_key_nodata.str(), ss_desc_nodata.str()); MandatoryOff (ss_key_nodata.str()); // Add a new bundle SourceBundle bundle; bundle.m_KeyIn = ss_key_in.str(); bundle.m_KeyOut = ss_key_out.str(); bundle.m_KeyPszX = ss_key_dims_x.str(); bundle.m_KeyPszY = ss_key_dims_y.str(); bundle.m_KeyNoData = ss_key_nodata.str(); m_Bundles.push_back(bundle); } // // Prepare bundles from the number of points // void PrepareInputs() { for (auto& bundle: m_Bundles) { // Create a stack of input images FloatVectorImageListType::Pointer list = GetParameterImageList(bundle.m_KeyIn); bundle.m_ImageSource.Set(list); // Patch size bundle.m_PatchSize[0] = GetParameterInt(bundle.m_KeyPszX); bundle.m_PatchSize[1] = GetParameterInt(bundle.m_KeyPszY); // No data value if (HasValue(bundle.m_KeyNoData)) { bundle.m_NoDataValue = GetParameterFloat(bundle.m_KeyNoData); } }
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
} void DoInit() { // Documentation SetName("PatchesExtraction"); SetDescription("This application extracts patches in multiple input images. Change " "the " + tf::ENV_VAR_NAME_NSOURCES + " environment variable to set the number of " "sources."); SetDocLongDescription("The application takes an input vector layer which is a set of " "points, typically the output of the \"SampleSelection\" or the \"LabelImageSampleSelection\" " "application to sample patches in the input images (samples are centered on the points). " "A \"source\" parameters group is composed of (i) an input image list (can be " "one image e.g. high res. image, or multiple e.g. time series), (ii) the size " "of the patches to sample, and (iii) the output images of patches which will " "be generated at the end of the process. The example below show how to " "set the samples sizes. For a SPOT6 image for instance, the patch size can " "be 64x64 and for an input Sentinel-2 time series the patch size could be " "1x1. Note that if a dimension size is not defined, the largest one will " "be used (i.e. input image dimensions. The number of input sources can be changed " "at runtime by setting the system environment variable " + tf::ENV_VAR_NAME_NSOURCES); SetDocAuthors("Remi Cresson"); AddDocTag(Tags::Learning); // Input/output images AddAnInputImage(); for (int i = 1; i < tf::GetNumberOfSources() ; i++) AddAnInputImage(); // Input vector data AddParameter(ParameterType_InputVectorData, "vec", "Positions of the samples (must be in the same projection as input image)"); // Output label AddParameter(ParameterType_OutputImage, "outlabels", "output labels"); SetDefaultOutputPixelType ("outlabels", ImagePixelType_uint8); MandatoryOff ("outlabels"); // Class field AddParameter(ParameterType_String, "field", "field of class in the vector data"); // Examples values SetDocExampleParameterValue("vec", "points.sqlite"); SetDocExampleParameterValue("source1.il", "$s2_list"); SetDocExampleParameterValue("source1.patchsizex", "16"); SetDocExampleParameterValue("source1.patchsizey", "16"); SetDocExampleParameterValue("field", "class"); SetDocExampleParameterValue("source1.out", "outpatches_16x16.tif"); SetDocExampleParameterValue("outlabels", "outlabels.tif"); } void DoExecute() { PrepareInputs(); // Setup the filter SamplerType::Pointer sampler = SamplerType::New(); sampler->SetInputVectorData(GetParameterVectorData("vec")); sampler->SetField(GetParameterAsString("field")); for (auto& bundle: m_Bundles) { if (HasValue(bundle.m_KeyNoData)) { otbAppLogINFO("Rejecting samples that have at least one no-data value"); sampler->PushBackInputWithPatchSize(bundle.m_ImageSource.Get(), bundle.m_PatchSize, bundle.m_NoDataValue);
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
} else { sampler->PushBackInputWithPatchSize(bundle.m_ImageSource.Get(), bundle.m_PatchSize); } } // Run the filter AddProcess(sampler, "Sampling patches"); sampler->Update(); // Show numbers otbAppLogINFO("Number of samples collected: " << sampler->GetNumberOfAcceptedSamples()); otbAppLogINFO("Number of samples rejected : " << sampler->GetNumberOfRejectedSamples()); // Save patches image if (sampler->GetNumberOfAcceptedSamples()>0) { for (unsigned int i = 0 ; i < m_Bundles.size() ; i++) { SetParameterOutputImage(m_Bundles[i].m_KeyOut, sampler->GetOutputPatchImages()[i]); } } else { otbAppLogFATAL("No patch to sample. Please check that your vector data falls inside your images, and no-data values."); } // Save label image (if needed) if (HasValue("outlabels")) { SetParameterOutputImage("outlabels", sampler->GetOutputLabelImage()); } } void DoUpdateParameters() { } private: std::vector<SourceBundle> m_Bundles; }; // end of class } // end namespace wrapper } // end namespace otb OTB_APPLICATION_EXPORT(otb::Wrapper::PatchesExtraction)