diff --git a/Modules/Applications/AppClassification/app/otbTrainImagesRegression.cxx b/Modules/Applications/AppClassification/app/otbTrainImagesRegression.cxx index ef99281c08d9e79dcf89bee485f108d3725c379a..6f3bd9fbdb21daf4a838ba6e9fb8742021d2b975 100644 --- a/Modules/Applications/AppClassification/app/otbTrainImagesRegression.cxx +++ b/Modules/Applications/AppClassification/app/otbTrainImagesRegression.cxx @@ -109,6 +109,24 @@ protected: std::string filePrefix = ""; }; + /** Compute the imageEnvelope of the first input predictor image, this envelope will be used as a + * polygon to perform sampling operations */ + void ComputeImageEnvelope( const std::string& filePrefix) + { + auto imageEnvelopeAppli = GetInternalApplication("imageEnvelope"); + auto& output = m_FileHandler["imageEnvelope"]; + + // For all input images, use the same vector file. + for (unsigned int i = 0; i< GetParameterImageList("io.il")->Size();i++) + output.push_back(GetParameterString("io.out") + "_" + filePrefix + "ImageEnvelope.shp"); + + imageEnvelopeAppli->SetParameterInputImage("in", GetParameterImageList("io.il")->GetNthElement(0)); + imageEnvelopeAppli->SetParameterString("out", output[0]); + + // Call ExecuteAndWriteOutput because VectorDataSetField's ExecuteInternal() does not write vector data. + imageEnvelopeAppli->ExecuteAndWriteOutput(); + } + /** Adds a class field to the input vectors, this is needed to perform sampling operations */ void AddRegressionField(const std::vector<std::string>& inputFileNames, const std::string& filePrefix) { @@ -120,12 +138,27 @@ protected: for (unsigned int i = 0; i < inputFileNames.size(); i++) { - outputFileNames.push_back(GetParameterString("io.out") + "_" + filePrefix + "Withfield" + std::to_string(i) + ".shp"); - setFieldAppli->SetParameterString("in", inputFileNames[i]); - setFieldAppli->SetParameterString("out", outputFileNames[i]); + // The application is not called if the input file has already be processed (i.e. if the input list contains ) + // the same file multiple times. Instead a link is created in the file handler. We can do this + // optimization here because the application only takes a vector Data as input but we cannot do it + // for other sampling operations (PolygonClassStatistics and SampleSelection) because the input images + // corresponding to one vector file may have different characteristics (resolution, origin, size) + auto sameFileName = std::find(inputFileNames.begin(),inputFileNames.begin()+i,inputFileNames[i]); + if (sameFileName!=inputFileNames.begin()+i) + { + // Create a link to the corresponding output + outputFileNames.push_back(outputFileNames[sameFileName-inputFileNames.begin()]); + } + else + { + outputFileNames.push_back(GetParameterString("io.out") + "_" + filePrefix + "Withfield" + std::to_string(i) + ".shp"); + setFieldAppli->SetParameterString("in", inputFileNames[i]); + + setFieldAppli->SetParameterString("out", outputFileNames[i]); - // Call ExecuteAndWriteOutput because VectorDataSetField's ExecuteInternal() does not write vector data. - setFieldAppli->ExecuteAndWriteOutput(); + // Call ExecuteAndWriteOutput because VectorDataSetField's ExecuteInternal() does not write vector data. + setFieldAppli->ExecuteAndWriteOutput(); + } } } @@ -250,7 +283,7 @@ protected: auto& trainSampleFileNameList = m_FileHandler["trainsamples"]; std::vector<std::string> featureNames; - for (unsigned int i = 0; i < GetParameterStringList("io.vd").size(); i++) + for (unsigned int i = 0; i < GetParameterImageList("io.il")->Size(); i++) { featureNames.push_back(m_FeaturePrefix + std::to_string(i)); } @@ -284,7 +317,7 @@ protected: AddParameter(ParameterType_InputVectorDataList, "io.vd", "Input Vector Data List"); SetParameterDescription("io.vd", "A list of vector data to select the training samples."); - MandatoryOn("io.vd"); + MandatoryOff("io.vd"); AddParameter(ParameterType_InputVectorDataList, "io.valid", "Validation Vector Data List"); SetParameterDescription("io.valid", "A list of vector data to select the validation samples."); @@ -294,6 +327,9 @@ protected: /** Init sampling parameters and applications */ void InitSampling() { + if (!IsParameterEnabled("io.vd") || !HasValue("io.vd")) + AddApplication("ImageEnvelope", "imageEnvelope", "Compute the image envelope"); + AddApplication("VectorDataSetField", "setfield", "Set additional vector field"); AddApplication("PolygonClassStatistics", "polystat", "Polygon analysis"); AddApplication("MultiImageSamplingRate", "rates", "Sampling rates"); @@ -379,11 +415,22 @@ private: void DoExecute() override { SamplingParameters trainParams; - trainParams.inputVectorList = GetParameterStringList("io.vd"); trainParams.filePrefix = "train"; + if (HasValue("sample.nt")) trainParams.numberOfSamples = GetParameterInt("sample.nt"); - + + if (IsParameterEnabled("io.vd") && HasValue("io.vd")) + { + trainParams.inputVectorList = GetParameterStringList("io.vd"); + } + else + { + otbAppLogINFO("No input training vector data: the image envelope will be used."); + ComputeImageEnvelope(trainParams.filePrefix); + trainParams.inputVectorList = m_FileHandler["imageEnvelope"]; + } + PerformSampling(trainParams); if (IsParameterEnabled("io.valid") && HasValue("io.valid"))