diff --git a/Data/Baseline/OTB-Applications/Images/apTvClPredictRegressionTest_monovar.tif b/Data/Baseline/OTB-Applications/Images/apTvClImageRegressionTest_monovar.tif similarity index 100% rename from Data/Baseline/OTB-Applications/Images/apTvClPredictRegressionTest_monovar.tif rename to Data/Baseline/OTB-Applications/Images/apTvClImageRegressionTest_monovar.tif diff --git a/Documentation/Cookbook/rst/recipes/pbclassif.rst b/Documentation/Cookbook/rst/recipes/pbclassif.rst index 4202066085f000e6ec8f4b1f1eac313f277de09a..dbeeadd8abb8b9b775db2ffb3f65b834fbdea7b0 100644 --- a/Documentation/Cookbook/rst/recipes/pbclassif.rst +++ b/Documentation/Cookbook/rst/recipes/pbclassif.rst @@ -853,17 +853,6 @@ element is equal to 3 pixels, which corresponds to a ball included in a 7 x 7 pixels square. Pixels with more than one majority class keep their original labels. - - -Regression ----------- - -The machine learning models in OpenCV and LibSVM also support a -regression mode: they can be used to predict a numeric value (i.e. not -a class index) from an input predictor. The workflow is the same as -classification. First, the regression model is trained, then it can be -used to predict output values. The applications to do that are and . - .. |image_61| image:: ../Art/MonteverdiImages/classification_chain_inputimage.jpg .. |image_62| image:: ../Art/MonteverdiImages/classification_chain_fancyclassif_CMR_input.png .. |image_63| image:: ../Art/MonteverdiImages/classification_chain_fancyclassif_CMR_3.png @@ -877,144 +866,77 @@ used to predict output values. The applications to do that are and . Figure 6: From left to right: Original image, fancy colored classified image and regularized classification map with radius equal to 3 pixels. -The input data set for training must have the following structure: - -- *n* components for the input predictors - -- one component for the corresponding output value - -The application supports 2 input formats: - -- An image list: each image should have components matching the - structure detailed earlier (*n* feature components + 1 output value) - -- A CSV file: the first *n* columns are the feature components and the - last one is the output value - -If you have separate images for predictors and output values, you can -use the application. - -:: - otbcli_ConcatenateImages -il features.tif output_value.tif - -out training_set.tif +Regression +---------- -Statistics estimation -~~~~~~~~~~~~~~~~~~~~~ +The machine learning models in OpenCV, LibSVM and SharkML also support a +regression mode: they can be used to predict a numeric value (i.e. not +a class index) from an input predictor. The workflow is the same as +classification. First, the regression model is trained, then it can be +used to predict output values. -As in classification, a statistics estimation step can be performed -before training. It allows to normalize the dynamic of the input -predictors to a standard one: zero mean, unit standard deviation. The -main difference with the classification case is that with regression, -the dynamic of output values can also be reduced. +Two applications are available for training: -The statistics file format is identical to the output file from -application, for instance: +- `TrainVectorRegression` can be used to train a classifier with a set of geometries + containing a list of features (predictors) and the corresponding output value: -:: + :: - <?xml version="1.0" ?> - <FeatureStatistics> - <Statistic name="mean"> - <StatisticVector value="198.796" /> - <StatisticVector value="283.117" /> - <StatisticVector value="169.878" /> - <StatisticVector value="376.514" /> - </Statistic> - <Statistic name="stddev"> - <StatisticVector value="22.6234" /> - <StatisticVector value="41.4086" /> - <StatisticVector value="40.6766" /> - <StatisticVector value="110.956" /> - </Statistic> - </FeatureStatistics> - -In the application, normalization of input predictors and output values -is optional. There are 3 options: - -- No statistic file: normalization disabled - -- Statistic file with *n* components: normalization enabled for input - predictors only - -- Statistic file with *n+1* components: normalization enabled for - input predictors and output values - -If you use an image list as training set, you can run application. It -will produce a statistics file suitable for input and output -normalization (third option). + otbcli_TrainVectorRegression -io.vd samples.sqlite + -cfield predicted + -io.out model.rf + -classifier rf + -feat perimeter area width -:: + The validation set `io.valid` is used to compute the mean square error between the original output value and the value + predicted by the computed model. If no validation set is provided the input training sample is used to compute the mean square error. - otbcli_ComputeImagesStatistics -il training_set.tif - -out stats.xml -Training -~~~~~~~~ -Initially, the machine learning models in OTB only used classification. -But since they come from external libraries (OpenCV and LibSVM), the -regression mode was already implemented in these external libraries. So -the integration of these models in OTB has been improved in order to -allow the usage of regression mode. As a consequence , the machine -learning models have nearly the same set of parameters for -classification and regression mode. +- `TrainImagesRegression` can be used to train a classifier from multiple pairs of predictor images and label images. + There are two ways to use this application: -.. |image11| image:: ../Art/MonteverdiImages/classification_chain_inputimage.jpg -.. |image12| image:: ../Art/MonteverdiImages/QB_1_ortho_MV_C123456_CM.png -.. |image13| image:: ../Art/MonteverdiImages/classification_chain_inputimage.jpg -.. |image14| image:: ../Art/MonteverdiImages/QB_1_ortho_DS_V_P_C123456_CM.png + It is possible to provide for each input image a vector data file with geometries + corresponding to the input locations that will be used for training. This is achieved by using the `io.vd` parameter. + The `sample.nt` and `sample.nv` can be used to specify the number of sample extracted from the images, for training and + validation, respectively. -.. |image15| image:: ../Art/MonteverdiImages/classification_chain_inputimage.jpg - :scale: 88% + :: -- Decision Trees + otbcli_TrainImagesRegression -io.il inputPredictorImage.tif + -io.ip inputLabelImage.tif + -io.vd trainingData.shp + -classifier rf + -io.out model.txt + -sample.nt 1000 + -sample.nv 500 -- Gradient Boosted Trees -- Neural Network -- Random Forests + Alternatively, if no input vector data is provided, the training samples will be + extracted from the full image extent. -- K-Nearest Neighbors +Two applications are also available for predictions: -The behavior of application is very similar to . From the input data -set, a portion of the samples is used for training, whereas the other -part is used for validation. The user may also set the model to train -and its parameters. Once the training is done, the model is stored in an -output file. +- `VectorRegression` uses a regression machine learning model to predict output values based on a + list of features: :: - otbcli_TrainRegression -io.il training_set.tif - -io.imstat stats.xml - -io.out model.txt - -sample.vtr 0.5 - -classifier knn - -classifier.knn.k 5 - -classifier.knn.rule median - -Prediction -~~~~~~~~~~ - -Once the model is trained, it can be used in application to perform the -prediction on an entire image containing input predictors (i.e. an image -with only *n* feature components). If the model was trained with -normalization, the same statistic file must be used for prediction. The -behavior of with respect to statistic file is identical to: - -- no statistic file: normalization off - -- *n* components: input only - -- *n+1* components: input and output + otbcli_VectorRegression + -in input_vector_data.shp + -feat perimeter area width + -model model.txt + -out predicted_vector_data.shp -The model to use is read from file (the one produced during training). +- Similarly, `ImageRegression` takes an image of predictors as input and computes the output image using a regression model: :: - otbcli_PredictRegression -in features_bis.tif - -model model.txt - -imstat stats.xml - -out prediction.tif + otbcli_ImageRegression + -in input_image.tif + -model model.txt + -out predicted_image.tif + diff --git a/Modules/Applications/AppClassification/app/CMakeLists.txt b/Modules/Applications/AppClassification/app/CMakeLists.txt index c981d9ec5bcf06530dae674b5aefa38c109e411a..dec69e29e9145507184f0d6b827e477dc7cceee5 100644 --- a/Modules/Applications/AppClassification/app/CMakeLists.txt +++ b/Modules/Applications/AppClassification/app/CMakeLists.txt @@ -71,8 +71,8 @@ otb_create_application( LINK_LIBRARIES ${${otb-module}_LIBRARIES}) otb_create_application( - NAME PredictRegression - SOURCES otbPredictRegression.cxx + NAME ImageRegression + SOURCES otbImageRegression.cxx LINK_LIBRARIES ${${otb-module}_LIBRARIES}) otb_create_application( diff --git a/Modules/Applications/AppClassification/app/otbImageClassifier.cxx b/Modules/Applications/AppClassification/app/otbImageClassifier.cxx index 1900c8e416fbcfb3295891b03d1bac06bf4f11b0..0f883375f0520e84460730da5f89b8e2eda7ab5c 100644 --- a/Modules/Applications/AppClassification/app/otbImageClassifier.cxx +++ b/Modules/Applications/AppClassification/app/otbImageClassifier.cxx @@ -84,7 +84,7 @@ private: SetDocLimitations("The input image must have the same type, order and number of bands as the images used to produce the statistics file and the SVM model file. If a statistics file was used during training by the TrainImagesClassifier, it is mandatory to use the same statistics file for classification. If an input mask is used, its size must match the input image size."); SetDocAuthors("OTB-Team"); - SetDocSeeAlso("TrainImagesClassifier, ValidateImagesClassifier, ComputeImagesStatistics"); + SetDocSeeAlso("TrainImagesClassifier, ComputeImagesStatistics"); AddDocTag(Tags::Learning); diff --git a/Modules/Applications/AppClassification/app/otbImageRegression.cxx b/Modules/Applications/AppClassification/app/otbImageRegression.cxx new file mode 100644 index 0000000000000000000000000000000000000000..15f4e7b4d0c664b0bb6a054e76184d690fdf5308 --- /dev/null +++ b/Modules/Applications/AppClassification/app/otbImageRegression.cxx @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES) + * + * This file is part of Orfeo Toolbox + * + * https://www.orfeo-toolbox.org/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "otbWrapperApplication.h" +#include "otbWrapperApplicationFactory.h" + +#include "itkUnaryFunctorImageFilter.h" +#include "otbChangeLabelImageFilter.h" +#include "otbStandardWriterWatcher.h" +#include "otbStatisticsXMLFileReader.h" +#include "otbShiftScaleVectorImageFilter.h" +#include "otbImageClassificationFilter.h" +#include "otbMultiToMonoChannelExtractROI.h" +#include "otbImageToVectorImageCastFilter.h" +#include "otbMachineLearningModelFactory.h" + +namespace otb +{ +namespace Functor +{ +/** + * simple affine function : y = ax+b + */ +template <class TInput, class TOutput> +class AffineFunctor +{ +public: + typedef double InternalType; + + void SetA(InternalType a) + { + m_A = a; + } + + void SetB(InternalType b) + { + m_B = b; + } + + inline TOutput operator()(const TInput& x) const + { + return static_cast<TOutput>(static_cast<InternalType>(x) * m_A + m_B); + } + +private: + InternalType m_A = 1.0; + InternalType m_B = 0.0; +}; +} + +namespace Wrapper +{ + +class ImageRegression : public Application +{ +public: + /** Standard class typedefs. */ + typedef ImageRegression Self; + typedef Application Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Standard macro */ + itkNewMacro(Self); + + itkTypeMacro(ImageRegression, otb::Application); + + /** Filters typedef */ + typedef UInt8ImageType MaskImageType; + typedef itk::VariableLengthVector<FloatVectorImageType::InternalPixelType> MeasurementType; + typedef otb::StatisticsXMLFileReader<MeasurementType> StatisticsReader; + typedef otb::ShiftScaleVectorImageFilter<FloatVectorImageType, FloatVectorImageType> RescalerType; + typedef itk::UnaryFunctorImageFilter<FloatImageType, FloatImageType, otb::Functor::AffineFunctor<float, float>> OutputRescalerType; + typedef otb::ImageClassificationFilter<FloatVectorImageType, FloatImageType, MaskImageType> ClassificationFilterType; + typedef ClassificationFilterType::Pointer ClassificationFilterPointerType; + typedef ClassificationFilterType::ModelType ModelType; + typedef ModelType::Pointer ModelPointerType; + typedef ClassificationFilterType::ValueType ValueType; + typedef ClassificationFilterType::LabelType LabelType; + typedef otb::MachineLearningModelFactory<ValueType, LabelType> MachineLearningModelFactoryType; + +protected: + ~ImageRegression() override + { + MachineLearningModelFactoryType::CleanFactories(); + } + +private: + void DoInit() override + { + SetName("ImageRegression"); + SetDescription("Performs a prediction of the input image according to a regression model file."); + + // Documentation + SetDocLongDescription( + "This application predict output values from an input " + "image, based on a regression model file produced either by " + "TrainVectorRegression or TrainImagesRegression. " + "Pixels of the output image will contain the predicted values from " + "the regression model (single band). The input pixels " + "can be optionally centered and reduced according " + "to the statistics file produced by the " + "ComputeImagesStatistics application. An optional " + "input mask can be provided, in which case only " + "input image pixels whose corresponding mask value " + "is greater than zero will be processed. The remaining " + "of pixels will be given the value zero in the output " + "image."); + + SetDocLimitations( + "The input image must contain the feature bands used for " + "the model training. " + "If a statistics file was used during training by the " + "TrainRegression, it is mandatory to use the same " + "statistics file for prediction. If an input mask is " + "used, its size must match the input image size."); + SetDocAuthors("OTB-Team"); + SetDocSeeAlso("TrainImagesRegression, TrainVectorRegression, VectorRegression, ComputeImagesStatistics"); + + AddDocTag(Tags::Learning); + + AddParameter(ParameterType_InputImage, "in", "Input Image"); + SetParameterDescription("in", "The input image to predict."); + + AddParameter(ParameterType_InputImage, "mask", "Input Mask"); + SetParameterDescription("mask", + "The mask restrict the " + "classification of the input image to the area where mask pixel values " + "are greater than zero."); + MandatoryOff("mask"); + + AddParameter(ParameterType_InputFilename, "model", "Model file"); + SetParameterDescription("model", + "A regression model file (produced either by " + "TrainVectorRegression application or the TrainImagesRegression application)."); + + AddParameter(ParameterType_InputFilename, "imstat", "Statistics file"); + SetParameterDescription("imstat", + "An XML file containing mean and standard" + " deviation to center and reduce samples before prediction " + "(produced by the ComputeImagesStatistics application). If this file contains " + "one more band than the sample size, the last stat of the last band will be" + "applied to expand the output predicted value."); + MandatoryOff("imstat"); + + AddParameter(ParameterType_OutputImage, "out", "Output Image"); + SetParameterDescription("out", "Output image containing predicted values"); + + AddRAMParameter(); + + // Doc example parameter settings + SetDocExampleParameterValue("in", "QB_1_ortho.tif"); + SetDocExampleParameterValue("imstat", "EstimateImageStatisticsQB1.xml"); + SetDocExampleParameterValue("model", "clsvmModelQB1.svm"); + SetDocExampleParameterValue("out", "clLabeledImageQB1.tif"); + + SetOfficialDocLink(); + } + + void DoUpdateParameters() override + { + // Nothing to do here : all parameters are independent + } + + void DoExecute() override + { + // Load input image + auto inImage = GetParameterImage("in"); + inImage->UpdateOutputInformation(); + unsigned int nbFeatures = inImage->GetNumberOfComponentsPerPixel(); + + // Load svm model + otbAppLogINFO("Loading model"); + auto model = MachineLearningModelFactoryType::CreateMachineLearningModel(GetParameterString("model"), MachineLearningModelFactoryType::ReadMode); + + if (model.IsNull()) + { + otbAppLogFATAL(<< "Error when loading model " << GetParameterString("model") << " : unsupported model type"); + } + + model->Load(GetParameterString("model")); + model->SetRegressionMode(true); + otbAppLogINFO("Model loaded"); + + // Classify + auto classificationFilter = ClassificationFilterType::New(); + classificationFilter->SetModel(model); + + auto outputImage = classificationFilter->GetOutput(); + + RescalerType::Pointer rescaler; + OutputRescalerType::Pointer outRescaler; + // Normalize input image if asked + if (IsParameterEnabled("imstat")) + { + otbAppLogINFO("Input image normalization activated."); + // Normalize input image (optional) + auto statisticsReader = StatisticsReader::New(); + MeasurementType meanMeasurementVector; + MeasurementType stddevMeasurementVector; + rescaler = RescalerType::New(); + // Load input image statistics + statisticsReader->SetFileName(GetParameterString("imstat")); + meanMeasurementVector = statisticsReader->GetStatisticVectorByName("mean"); + stddevMeasurementVector = statisticsReader->GetStatisticVectorByName("stddev"); + otbAppLogINFO("mean used: " << meanMeasurementVector); + otbAppLogINFO("standard deviation used: " << stddevMeasurementVector); + if (meanMeasurementVector.Size() == nbFeatures + 1) + { + double outMean = meanMeasurementVector[nbFeatures]; + double outStdDev = stddevMeasurementVector[nbFeatures]; + meanMeasurementVector.SetSize(nbFeatures, false); + stddevMeasurementVector.SetSize(nbFeatures, false); + outRescaler = OutputRescalerType::New(); + outRescaler->SetInput(classificationFilter->GetOutput()); + outRescaler->GetFunctor().SetA(outStdDev); + outRescaler->GetFunctor().SetB(outMean); + outputImage = outRescaler->GetOutput(); + } + else if (meanMeasurementVector.Size() != nbFeatures) + { + otbAppLogFATAL("Wrong number of components in statistics file : " << meanMeasurementVector.Size()); + } + + // Rescale vector image + rescaler->SetScale(stddevMeasurementVector); + rescaler->SetShift(meanMeasurementVector); + rescaler->SetInput(inImage); + + classificationFilter->SetInput(rescaler->GetOutput()); + } + else + { + otbAppLogINFO("Input image normalization deactivated."); + classificationFilter->SetInput(inImage); + } + + if (IsParameterEnabled("mask")) + { + otbAppLogINFO("Using input mask"); + // Load mask image and cast into LabeledImageType + auto inMask = GetParameterUInt8Image("mask"); + classificationFilter->SetInputMask(inMask); + } + + SetParameterOutputImage<FloatImageType>("out", outputImage); + RegisterPipeline(); + } +}; +} +} + +OTB_APPLICATION_EXPORT(otb::Wrapper::ImageRegression) diff --git a/Modules/Applications/AppClassification/app/otbPredictRegression.cxx b/Modules/Applications/AppClassification/app/otbPredictRegression.cxx deleted file mode 100644 index b088810145126212e8c99ed904d1232c306c1f7c..0000000000000000000000000000000000000000 --- a/Modules/Applications/AppClassification/app/otbPredictRegression.cxx +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES) - * - * This file is part of Orfeo Toolbox - * - * https://www.orfeo-toolbox.org/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "otbWrapperApplication.h" -#include "otbWrapperApplicationFactory.h" - -#include "itkUnaryFunctorImageFilter.h" -#include "otbChangeLabelImageFilter.h" -#include "otbStandardWriterWatcher.h" -#include "otbStatisticsXMLFileReader.h" -#include "otbShiftScaleVectorImageFilter.h" -#include "otbImageClassificationFilter.h" -#include "otbMultiToMonoChannelExtractROI.h" -#include "otbImageToVectorImageCastFilter.h" -#include "otbMachineLearningModelFactory.h" - -namespace otb -{ -namespace Functor -{ -/** - * simple affine function : y = ax+b - */ -template<class TInput, class TOutput> -class AffineFunctor -{ -public: - typedef double InternalType; - - // constructor - AffineFunctor() : m_A(1.0),m_B(0.0) {} - - // destructor - virtual ~AffineFunctor() {} - - void SetA(InternalType a) - { - m_A = a; - } - - void SetB(InternalType b) - { - m_B = b; - } - - inline TOutput operator()(const TInput & x) const - { - return static_cast<TOutput>( static_cast<InternalType>(x)*m_A + m_B); - } -private: - InternalType m_A; - InternalType m_B; -}; - -} - -namespace Wrapper -{ - -class PredictRegression : public Application -{ -public: - /** Standard class typedefs. */ - typedef PredictRegression Self; - typedef Application Superclass; - typedef itk::SmartPointer<Self> Pointer; - typedef itk::SmartPointer<const Self> ConstPointer; - - /** Standard macro */ - itkNewMacro(Self); - - itkTypeMacro(PredictRegression, otb::Application); - - /** Filters typedef */ - typedef UInt8ImageType MaskImageType; - typedef itk::VariableLengthVector<FloatVectorImageType::InternalPixelType> MeasurementType; - typedef otb::StatisticsXMLFileReader<MeasurementType> StatisticsReader; - typedef otb::ShiftScaleVectorImageFilter<FloatVectorImageType, FloatVectorImageType> RescalerType; - typedef itk::UnaryFunctorImageFilter< - FloatImageType, - FloatImageType, - otb::Functor::AffineFunctor<float,float> > OutputRescalerType; - typedef otb::ImageClassificationFilter<FloatVectorImageType, FloatImageType, MaskImageType> ClassificationFilterType; - typedef ClassificationFilterType::Pointer ClassificationFilterPointerType; - typedef ClassificationFilterType::ModelType ModelType; - typedef ModelType::Pointer ModelPointerType; - typedef ClassificationFilterType::ValueType ValueType; - typedef ClassificationFilterType::LabelType LabelType; - typedef otb::MachineLearningModelFactory<ValueType, LabelType> MachineLearningModelFactoryType; - -protected: - - ~PredictRegression() override - { - MachineLearningModelFactoryType::CleanFactories(); - } - -private: - void DoInit() override - { - SetName("PredictRegression"); - SetDescription("Performs a prediction of the input image according to a regression model file."); - - // Documentation - SetDocLongDescription("This application predict output values from an input" - " image, based on a regression model file produced by" - " the TrainRegression application. Pixels of the " - "output image will contain the predicted values from" - "the regression model (single band). The input pixels" - " can be optionally centered and reduced according " - "to the statistics file produced by the " - "ComputeImagesStatistics application. An optional " - "input mask can be provided, in which case only " - "input image pixels whose corresponding mask value " - "is greater than 0 will be processed. The remaining" - " of pixels will be given the value 0 in the output" - " image."); - - SetDocLimitations("The input image must contain the feature bands used for" - " the model training (without the predicted value). " - "If a statistics file was used during training by the " - "TrainRegression, it is mandatory to use the same " - "statistics file for prediction. If an input mask is " - "used, its size must match the input image size."); - SetDocAuthors("OTB-Team"); - SetDocSeeAlso("TrainRegression, ComputeImagesStatistics"); - - AddDocTag(Tags::Learning); - - AddParameter(ParameterType_InputImage, "in", "Input Image"); - SetParameterDescription( "in", "The input image to predict."); - - // TODO : use CSV input/output ? - - AddParameter(ParameterType_InputImage, "mask", "Input Mask"); - SetParameterDescription( "mask", "The mask restrict the " - "classification of the input image to the area where mask pixel values " - "are greater than 0."); - MandatoryOff("mask"); - - AddParameter(ParameterType_InputFilename, "model", "Model file"); - SetParameterDescription("model", "A regression model file (produced by " - "TrainRegression application)."); - - AddParameter(ParameterType_InputFilename, "imstat", "Statistics file"); - SetParameterDescription("imstat", "An XML file containing mean and standard" - " deviation to center and reduce samples before prediction " - "(produced by ComputeImagesStatistics application). If this file contains" - "one more band than the sample size, the last stat of the last band will be" - "applied to expand the output predicted value"); - MandatoryOff("imstat"); - - AddParameter(ParameterType_OutputImage, "out", "Output Image"); - SetParameterDescription( "out", "Output image containing predicted values"); - - AddRAMParameter(); - - // Doc example parameter settings - SetDocExampleParameterValue("in", "QB_1_ortho.tif"); - SetDocExampleParameterValue("imstat", "EstimateImageStatisticsQB1.xml"); - SetDocExampleParameterValue("model", "clsvmModelQB1.svm"); - SetDocExampleParameterValue("out", "clLabeledImageQB1.tif"); - - SetOfficialDocLink(); - } - - void DoUpdateParameters() override - { - // Nothing to do here : all parameters are independent - } - - void DoExecute() override - { - // Load input image - FloatVectorImageType::Pointer inImage = GetParameterImage("in"); - inImage->UpdateOutputInformation(); - unsigned int nbFeatures = inImage->GetNumberOfComponentsPerPixel(); - - // Load svm model - otbAppLogINFO("Loading model"); - m_Model = MachineLearningModelFactoryType::CreateMachineLearningModel(GetParameterString("model"), - MachineLearningModelFactoryType::ReadMode); - - if (m_Model.IsNull()) - { - otbAppLogFATAL(<< "Error when loading model " << GetParameterString("model") << " : unsupported model type"); - } - - m_Model->Load(GetParameterString("model")); - m_Model->SetRegressionMode(true); - otbAppLogINFO("Model loaded"); - - // Classify - m_ClassificationFilter = ClassificationFilterType::New(); - m_ClassificationFilter->SetModel(m_Model); - - FloatImageType::Pointer outputImage = m_ClassificationFilter->GetOutput(); - - // Normalize input image if asked - if(IsParameterEnabled("imstat") ) - { - otbAppLogINFO("Input image normalization activated."); - // Normalize input image (optional) - StatisticsReader::Pointer statisticsReader = StatisticsReader::New(); - MeasurementType meanMeasurementVector; - MeasurementType stddevMeasurementVector; - m_Rescaler = RescalerType::New(); - // Load input image statistics - statisticsReader->SetFileName(GetParameterString("imstat")); - meanMeasurementVector = statisticsReader->GetStatisticVectorByName("mean"); - stddevMeasurementVector = statisticsReader->GetStatisticVectorByName("stddev"); - otbAppLogINFO( "mean used: " << meanMeasurementVector ); - otbAppLogINFO( "standard deviation used: " << stddevMeasurementVector ); - if (meanMeasurementVector.Size() == nbFeatures + 1) - { - double outMean = meanMeasurementVector[nbFeatures]; - double outStdDev = stddevMeasurementVector[nbFeatures]; - meanMeasurementVector.SetSize(nbFeatures,false); - stddevMeasurementVector.SetSize(nbFeatures,false); - m_OutRescaler = OutputRescalerType::New(); - m_OutRescaler->SetInput(m_ClassificationFilter->GetOutput()); - m_OutRescaler->GetFunctor().SetA(outStdDev); - m_OutRescaler->GetFunctor().SetB(outMean); - outputImage = m_OutRescaler->GetOutput(); - } - else if (meanMeasurementVector.Size() != nbFeatures) - { - otbAppLogFATAL("Wrong number of components in statistics file : "<<meanMeasurementVector.Size()); - } - - // Rescale vector image - m_Rescaler->SetScale(stddevMeasurementVector); - m_Rescaler->SetShift(meanMeasurementVector); - m_Rescaler->SetInput(inImage); - - m_ClassificationFilter->SetInput(m_Rescaler->GetOutput()); - } - else - { - otbAppLogINFO("Input image normalization deactivated."); - m_ClassificationFilter->SetInput(inImage); - } - - - if(IsParameterEnabled("mask")) - { - otbAppLogINFO("Using input mask"); - // Load mask image and cast into LabeledImageType - MaskImageType::Pointer inMask = GetParameterUInt8Image("mask"); - - m_ClassificationFilter->SetInputMask(inMask); - } - - SetParameterOutputImage<FloatImageType>("out", outputImage); - - } - - ClassificationFilterType::Pointer m_ClassificationFilter; - ModelPointerType m_Model; - RescalerType::Pointer m_Rescaler; - OutputRescalerType::Pointer m_OutRescaler; - -}; - - -} -} - -OTB_APPLICATION_EXPORT(otb::Wrapper::PredictRegression) diff --git a/Modules/Applications/AppClassification/test/CMakeLists.txt b/Modules/Applications/AppClassification/test/CMakeLists.txt index b47c420c21388528cccb295d466a9304b810c781..9da705b64c50637a2417880c5b6010b075965623 100644 --- a/Modules/Applications/AppClassification/test/CMakeLists.txt +++ b/Modules/Applications/AppClassification/test/CMakeLists.txt @@ -785,16 +785,16 @@ if(OTB_USE_OPENCV) ${OTBAPP_BASELINE_FILES}/apTvClTrainRegressionTest_monovar.txt ${TEMP}/apTvClTrainRegressionTest_monovar.txt) - #----------- PredictRegression TESTS ---------------- - otb_test_application(NAME apTvClPredictRegressionTest_monovar - APP PredictRegression + #----------- ImageRegression TESTS ---------------- + otb_test_application(NAME apTvClImageRegressionTest_monovar + APP ImageRegression OPTIONS -in ${INPUTDATA}/QB_Toulouse_Ortho_PAN.tif -model ${OTBAPP_BASELINE_FILES}/apTvClTrainRegressionTest_monovar.rf -imstat ${INPUTDATA}/QB_Toulouse_Ortho_regression.xml - -out ${TEMP}/apTvClPredictRegressionTest_monovar.tif + -out ${TEMP}/apTvClImageRegressionTest_monovar.tif VALID --compare-image 1 - ${OTBAPP_BASELINE}/apTvClPredictRegressionTest_monovar.tif - ${TEMP}/apTvClPredictRegressionTest_monovar.tif) + ${OTBAPP_BASELINE}/apTvClImageRegressionTest_monovar.tif + ${TEMP}/apTvClImageRegressionTest_monovar.tif) endif()