diff --git a/CMake/OTBModuleHeaderTest.cmake b/CMake/OTBModuleHeaderTest.cmake index 186c56d487f76374968d54fcd6bbfc8cef13e106..ca2f7cb5ef27ff712e52ed3d05d55d2c499d298b 100644 --- a/CMake/OTBModuleHeaderTest.cmake +++ b/CMake/OTBModuleHeaderTest.cmake @@ -46,7 +46,7 @@ if(NOT OTB_USE_OPENCV) SET(BANNED_HEADERS "${BANNED_HEADERS} otbDecisionTreeMachineLearningModelFactory.h otbDecisionTreeMachineLearningModel.h otbKNearestNeighborsMachineLearningModelFactory.h otbKNearestNeighborsMachineLearningModel.h otbRandomForestsMachineLearningModelFactory.h otbRandomForestsMachineLearningModel.h otbSVMMachineLearningModelFactory.h otbSVMMachineLearningModel.h otbGradientBoostedTreeMachineLearningModelFactory.h otbGradientBoostedTreeMachineLearningModel.h otbBoostMachineLearningModelFactory.h otbBoostMachineLearningModel.h otbNeuralNetworkMachineLearningModelFactory.h otbNeuralNetworkMachineLearningModel.h otbNormalBayesMachineLearningModelFactory.h otbNormalBayesMachineLearningModel.h otbRequiresOpenCVCheck.h otbOpenCVUtils.h otbCvRTreesWrapper.h") endif() if(NOT OTB_USE_SHARK) - SET(BANNED_HEADERS "${BANNED_HEADERS} otbSharkRandomForestsMachineLearningModel.h otbSharkRandomForestsMachineLearningModel.txx otbSharkUtils.h otbRequiresSharkCheck.h otbSharkRandomForestsMachineLearningModelFactory.h") + SET(BANNED_HEADERS "${BANNED_HEADERS} otbSharkRandomForestsMachineLearningModel.h otbSharkRandomForestsMachineLearningModel.txx otbSharkUtils.h otbRequiresSharkCheck.h otbSharkRandomForestsMachineLearningModelFactory.h otbSharkKMeansMachineLearningModel.h otbSharkKMeansMachineLearningModel.txx otbSharkKMeansMachineLearningModelFactory.h otbSharkKMeansMachineLearningModelFactory.txx") endif() if(NOT OTB_USE_LIBSVM) SET(BANNED_HEADERS "${BANNED_HEADERS} otbLibSVMMachineLearningModel.h otbLibSVMMachineLearningModelFactory.h") @@ -64,7 +64,7 @@ endif() macro( otb_module_headertest _name ) - if( NOT ${_name}_THIRD_PARTY + if( NOT ${_name}_THIRD_PARTY AND EXISTS ${${_name}_SOURCE_DIR}/include AND PYTHON_EXECUTABLE AND NOT (PYTHON_VERSION_STRING VERSION_LESS 2.6) diff --git a/Modules/Applications/AppClassification/app/CMakeLists.txt b/Modules/Applications/AppClassification/app/CMakeLists.txt index e28ab734b922b98a067cee9aac88ddc4c832a44f..0d1475994c11bb266b43ef15309394172fee38b3 100644 --- a/Modules/Applications/AppClassification/app/CMakeLists.txt +++ b/Modules/Applications/AppClassification/app/CMakeLists.txt @@ -70,7 +70,6 @@ otb_create_application( SOURCES otbTrainVectorClassifier.cxx LINK_LIBRARIES ${${otb-module}_LIBRARIES}) - otb_create_application( NAME ComputeConfusionMatrix SOURCES otbComputeConfusionMatrix.cxx diff --git a/Modules/Applications/AppClassification/app/otbTrainImagesClassifier.cxx b/Modules/Applications/AppClassification/app/otbTrainImagesClassifier.cxx index 9797ec0fadd347f65f39ec561868e59074ac4f6b..2a84ff53e78b81d71c5eddc3f32967f5cd92fb0b 100644 --- a/Modules/Applications/AppClassification/app/otbTrainImagesClassifier.cxx +++ b/Modules/Applications/AppClassification/app/otbTrainImagesClassifier.cxx @@ -18,513 +18,210 @@ * limitations under the License. */ -#include "otbWrapperCompositeApplication.h" -#include "otbWrapperApplicationFactory.h" - -#include "otbOGRDataToSamplePositionFilter.h" -#include "otbSamplingRateCalculator.h" +#include "otbTrainImagesBase.h" namespace otb { namespace Wrapper { -class TrainImagesClassifier: public CompositeApplication +class TrainImagesClassifier : public TrainImagesBase { public: - /** Standard class typedefs. */ - typedef TrainImagesClassifier Self; - typedef CompositeApplication Superclass; - typedef itk::SmartPointer<Self> Pointer; + typedef TrainImagesClassifier Self; + typedef TrainImagesBase Superclass; + typedef itk::SmartPointer<Self> Pointer; typedef itk::SmartPointer<const Self> ConstPointer; - - /** Standard macro */ - itkNewMacro(Self) - - itkTypeMacro(TrainImagesClassifier, otb::Wrapper::CompositeApplication) - - /** filters typedefs*/ - typedef otb::OGRDataToSamplePositionFilter< - FloatVectorImageType, - UInt8ImageType, - otb::PeriodicSampler> PeriodicSamplerType; - - typedef otb::SamplingRateCalculator::MapRateType MapRateType; - -protected: - -private: - -bool RemoveFile(std::string &filePath) -{ - bool res = true; - if(itksys::SystemTools::FileExists(filePath.c_str())) - { - size_t posExt = filePath.rfind('.'); - if (posExt != std::string::npos && - filePath.compare(posExt,std::string::npos,".shp") == 0) + itkNewMacro( Self ) + itkTypeMacro( Self, Superclass ) + + void DoInit() ITK_OVERRIDE + { + SetName( "TrainImagesClassifier" ); + SetDescription( "Train a classifier from multiple pairs of images and training vector data." ); + + // Documentation + SetDocName( "Train a classifier from multiple images" ); + SetDocLongDescription( + "This application performs a classifier training from multiple pairs of input images and training vector data. " + "Samples are composed of pixel values in each band optionally centered and reduced using an XML statistics file produced by " + "the ComputeImagesStatistics application.\n The training vector data must contain polygons with a positive integer field " + "representing the class label. The name of this field can be set using the \"Class label field\" parameter. Training and validation " + "sample lists are built such that each class is equally represented in both lists. One parameter allows controlling the ratio " + "between the number of samples in training and validation sets. Two parameters allow managing the size of the training and " + "validation sets per class and per image.\n Several classifier parameters can be set depending on the chosen classifier. In the " + "validation process, the confusion matrix is organized the following way: rows = reference labels, columns = produced labels. " + "In the header of the optional confusion matrix output file, the validation (reference) and predicted (produced) class labels" + " are ordered according to the rows/columns of the confusion matrix.\n This application is based on LibSVM and OpenCV Machine Learning " + "(2.3.1 and later)." ); + SetDocLimitations( "None" ); + SetDocAuthors( "OTB-Team" ); + SetDocSeeAlso( "OpenCV documentation for machine learning http://docs.opencv.org/modules/ml/doc/ml.html " ); + + AddDocTag( Tags::Learning ); + + // Perform initialization + ClearApplications(); + InitIO(); + InitSampling(); + InitClassification(); + + AddDocTag( Tags::Learning ); + + // Doc example parameter settings + SetDocExampleParameterValue( "io.il", "QB_1_ortho.tif" ); + SetDocExampleParameterValue( "io.vd", "VectorData_QB1.shp" ); + SetDocExampleParameterValue( "io.imstat", "EstimateImageStatisticsQB1.xml" ); + SetDocExampleParameterValue( "sample.mv", "100" ); + SetDocExampleParameterValue( "sample.mt", "100" ); + SetDocExampleParameterValue( "sample.vtr", "0.5" ); + SetDocExampleParameterValue( "sample.vfn", "Class" ); + SetDocExampleParameterValue( "classifier", "libsvm" ); + SetDocExampleParameterValue( "classifier.libsvm.k", "linear" ); + SetDocExampleParameterValue( "classifier.libsvm.c", "1" ); + SetDocExampleParameterValue( "classifier.libsvm.opt", "false" ); + SetDocExampleParameterValue( "io.out", "svmModelQB1.txt" ); + SetDocExampleParameterValue( "io.confmatout", "svmConfusionMatrixQB1.csv" ); + } + + void DoUpdateParameters() ITK_OVERRIDE + { + if( HasValue( "io.vd" ) && IsParameterEnabled( "io.vd" )) { - std::string shxPath = filePath.substr(0,posExt) + std::string(".shx"); - std::string dbfPath = filePath.substr(0,posExt) + std::string(".dbf"); - std::string prjPath = filePath.substr(0,posExt) + std::string(".prj"); - RemoveFile(shxPath); - RemoveFile(dbfPath); - RemoveFile(prjPath); + UpdatePolygonClassStatisticsParameters(); } - res = itksys::SystemTools::RemoveFile(filePath.c_str()); - if (!res) + } + + /** + * Select and Extract samples for validation with computed statistics and rates. + * Validation samples could be empty if sample.vrt == 0 and if no dedicated validation are provided. + * If no dedicated validation is provided the training is split corresponding to the sample.vtr parameter, + * in this case if no vector data have been provided, the training rates and statistics are computed + * on the selection and extraction training result. + * fileNames.sampleOutputs contains training data and after an ExtractValidationData training data will + * be split to fileNames.sampleTrainOutputs. + * \param imageList + * \param fileNames + * \param validationVectorFileList + * \param rates + * \param HasInputVector + */ + void ExtractValidationData(FloatVectorImageListType *imageList, TrainFileNamesHandler& fileNames, + std::vector<std::string> validationVectorFileList, + const SamplingRates& rates, bool itkNotUsed(HasInputVector) ) + { + if( !validationVectorFileList.empty() ) // Compute class statistics and sampling rate of validation data if provided. { - otbAppLogINFO(<<"Unable to remove file "<<filePath); + ComputePolygonStatistics( imageList, validationVectorFileList, fileNames.polyStatValidOutputs ); + ComputeSamplingRate( fileNames.polyStatValidOutputs, fileNames.rateValidOut, rates.fmv ); + SelectAndExtractValidationSamples( fileNames, imageList, validationVectorFileList ); +// if( HasInputVector ) // if input vector is provided the sampleTrainOutputs is the previously extracted sampleOutputs + fileNames.sampleTrainOutputs = fileNames.sampleOutputs; } - } - return res; -} - -void DoInit() ITK_OVERRIDE -{ - SetName("TrainImagesClassifier"); - SetDescription( - "Train a classifier from multiple pairs of images and training vector data."); - - // Documentation - SetDocName("Train a classifier from multiple images"); - SetDocLongDescription( - "This application performs a classifier training from multiple pairs of input images and training vector data. " - "Samples are composed of pixel values in each band optionally centered and reduced using an XML statistics file produced by " - "the ComputeImagesStatistics application.\n The training vector data must contain polygons with a positive integer field " - "representing the class label. The name of this field can be set using the \"Class label field\" parameter. Training and validation " - "sample lists are built such that each class is equally represented in both lists. One parameter allows controlling the ratio " - "between the number of samples in training and validation sets. Two parameters allow managing the size of the training and " - "validation sets per class and per image.\n Several classifier parameters can be set depending on the chosen classifier. In the " - "validation process, the confusion matrix is organized the following way: rows = reference labels, columns = produced labels. " - "In the header of the optional confusion matrix output file, the validation (reference) and predicted (produced) class labels" - " are ordered according to the rows/columns of the confusion matrix.\n This application is based on LibSVM and OpenCV Machine Learning " - "(2.3.1 and later)."); - SetDocLimitations("None"); - SetDocAuthors("OTB-Team"); - SetDocSeeAlso("OpenCV documentation for machine learning http://docs.opencv.org/modules/ml/doc/ml.html "); - - AddDocTag(Tags::Learning); - - ClearApplications(); - AddApplication("PolygonClassStatistics", "polystat","Polygon analysis"); - AddApplication("MultiImageSamplingRate", "rates", "Sampling rates"); - AddApplication("SampleSelection", "select", "Sample selection"); - AddApplication("SampleExtraction","extraction", "Sample extraction"); - AddApplication("TrainVectorClassifier", "training", "Model training"); - - //Group IO - AddParameter(ParameterType_Group, "io", "Input and output data"); - SetParameterDescription("io", "This group of parameters allows setting input and output data."); - - AddParameter(ParameterType_InputImageList, "io.il", "Input Image List"); - SetParameterDescription("io.il", "A list of input images."); - AddParameter(ParameterType_InputVectorDataList, "io.vd", "Input Vector Data List"); - SetParameterDescription("io.vd", "A list of vector data to select the training samples."); - - AddParameter(ParameterType_InputVectorDataList, "io.valid", "Validation Vector Data List"); - SetParameterDescription("io.valid", "A list of vector data to select the training samples."); - MandatoryOff("io.valid"); - - ShareParameter("io.imstat","training.io.stats"); - ShareParameter("io.confmatout","training.io.confmatout"); - ShareParameter("io.out","training.io.out"); - - ShareParameter("elev","polystat.elev"); - - // Sampling settings - AddParameter(ParameterType_Group, "sample", "Training and validation samples parameters"); - SetParameterDescription("sample", - "This group of parameters allows you to set training and validation sample lists parameters."); - AddParameter(ParameterType_Int, "sample.mt", "Maximum training sample size per class"); - SetDefaultParameterInt("sample.mt", 1000); - SetParameterDescription("sample.mt", "Maximum size per class (in pixels) of " - "the training sample list (default = 1000) (no limit = -1). If equal to -1," - " then the maximal size of the available training sample list per class " - "will be equal to the surface area of the smallest class multiplied by the" - " training sample ratio."); - AddParameter(ParameterType_Int, "sample.mv", "Maximum validation sample size per class"); - SetDefaultParameterInt("sample.mv", 1000); - SetParameterDescription("sample.mv", "Maximum size per class (in pixels) of " - "the validation sample list (default = 1000) (no limit = -1). If equal to -1," - " then the maximal size of the available validation sample list per class " - "will be equal to the surface area of the smallest class multiplied by the " - "validation sample ratio."); - AddParameter(ParameterType_Int, "sample.bm", "Bound sample number by minimum"); - SetDefaultParameterInt("sample.bm", 1); - SetParameterDescription("sample.bm", "Bound the number of samples for each " - "class by the number of available samples by the smaller class. Proportions " - "between training and validation are respected. Default is true (=1)."); - AddParameter(ParameterType_Float, "sample.vtr", "Training and validation sample ratio"); - SetParameterDescription("sample.vtr", - "Ratio between training and validation samples (0.0 = all training, 1.0 = " - "all validation) (default = 0.5)."); - SetParameterFloat("sample.vtr",0.5, false); - SetMaximumParameterFloatValue("sample.vtr",1.0); - SetMinimumParameterFloatValue("sample.vtr",0.0); - - ShareParameter("sample.vfn","polystat.field"); - - // hide sampling parameters - //ShareParameter("sample.strategy","rates.strategy"); - //ShareParameter("sample.mim","rates.mim"); - - // Classifier settings - ShareParameter("classifier","training.classifier"); - - ShareParameter("rand","training.rand"); - - // Synchronization between applications - Connect("select.field", "polystat.field"); - Connect("select.layer", "polystat.layer"); - Connect("select.elev", "polystat.elev"); - - Connect("extraction.in", "select.in"); - Connect("extraction.vec", "select.out"); - Connect("extraction.field", "polystat.field"); - Connect("extraction.layer", "polystat.layer"); - - Connect("training.cfield", "polystat.field"); - - ShareParameter("ram","polystat.ram"); - Connect("select.ram", "polystat.ram"); - Connect("extraction.ram", "polystat.ram"); - - Connect("select.rand", "training.rand"); - - AddParameter(ParameterType_Empty,"cleanup","Temporary files cleaning"); - EnableParameter("cleanup"); - SetParameterDescription("cleanup","If activated, the application will try to clean all temporary files it created"); - MandatoryOff("cleanup"); - - // Doc example parameter settings - SetDocExampleParameterValue("io.il", "QB_1_ortho.tif"); - SetDocExampleParameterValue("io.vd", "VectorData_QB1.shp"); - SetDocExampleParameterValue("io.imstat", "EstimateImageStatisticsQB1.xml"); - SetDocExampleParameterValue("sample.mv", "100"); - SetDocExampleParameterValue("sample.mt", "100"); - SetDocExampleParameterValue("sample.vtr", "0.5"); - SetDocExampleParameterValue("sample.vfn", "Class"); - SetDocExampleParameterValue("classifier", "libsvm"); - SetDocExampleParameterValue("classifier.libsvm.k", "linear"); - SetDocExampleParameterValue("classifier.libsvm.c", "1"); - SetDocExampleParameterValue("classifier.libsvm.opt", "false"); - SetDocExampleParameterValue("io.out", "svmModelQB1.txt"); - SetDocExampleParameterValue("io.confmatout", "svmConfusionMatrixQB1.csv"); -} - -void DoUpdateParameters() ITK_OVERRIDE -{ - if ( HasValue("io.vd") ) - { - std::vector<std::string> vectorFileList = GetParameterStringList("io.vd"); - GetInternalApplication("polystat")->SetParameterString("vec",vectorFileList[0], false); - UpdateInternalParameters("polystat"); - } -} - -void DoExecute() ITK_OVERRIDE -{ - FloatVectorImageListType* imageList = GetParameterImageList("io.il"); - std::vector<std::string> vectorFileList = GetParameterStringList("io.vd"); - unsigned int nbInputs = imageList->Size(); - if (nbInputs > vectorFileList.size()) - { - otbAppLogFATAL("Missing input vector data files to match number of images ("<<nbInputs<<")."); - } - - // check if validation vectors are given - std::vector<std::string> validationVectorFileList; - bool dedicatedValidation = false; - if (IsParameterEnabled("io.valid") && HasValue("io.valid")) - { - dedicatedValidation = true; - validationVectorFileList = GetParameterStringList("io.valid"); - if (nbInputs > validationVectorFileList.size()) + else if(GetParameterFloat("sample.vtr") != 0.0)// Split training data to validation { - otbAppLogFATAL("Missing validation vector data files to match number of images ("<<nbInputs<<")."); +// if( !HasInputVector ) // Compute one class statistics and sampling rate for the generated vector. +// ComputePolygonStatistics( imageList, fileNames.sampleOutputs, fileNames.polyStatTrainOutputs ); +// ComputeSamplingRate( fileNames.polyStatTrainOutputs, fileNames.rateTrainOut, rates.fmt ); + SplitTrainingToValidationSamples( fileNames, imageList ); } - } - - // Prepare temporary file names - std::string outModel(GetParameterString("io.out")); - std::vector<std::string> polyStatTrainOutputs; - std::vector<std::string> polyStatValidOutputs; - std::vector<std::string> ratesTrainOutputs; - std::vector<std::string> ratesValidOutputs; - std::vector<std::string> sampleOutputs; - std::vector<std::string> sampleTrainOutputs; - std::vector<std::string> sampleValidOutputs; - std::string rateTrainOut; - if (dedicatedValidation) - { - rateTrainOut = outModel + "_ratesTrain.csv"; - } - else - { - rateTrainOut = outModel + "_rates.csv"; - } - std::string rateValidOut(outModel + "_ratesValid.csv"); - for (unsigned int i=0 ; i<nbInputs ; i++) - { - std::ostringstream oss; - oss <<i+1; - std::string strIndex(oss.str()); - if (dedicatedValidation) + else // nothing to do, except update fileNames { - polyStatTrainOutputs.push_back(outModel + "_statsTrain_" + strIndex + ".xml"); - polyStatValidOutputs.push_back(outModel + "_statsValid_" + strIndex + ".xml"); - ratesTrainOutputs.push_back(outModel + "_ratesTrain_" + strIndex + ".csv"); - ratesValidOutputs.push_back(outModel + "_ratesValid_" + strIndex + ".csv"); - sampleOutputs.push_back(outModel + "_samplesTrain_" + strIndex + ".shp"); + fileNames.sampleTrainOutputs = fileNames.sampleOutputs; } - else + } + + /** + * Extract Training data depending if input vector is provided + * \param imageList list of the image + * \param fileNames handler that contain filenames + * \param vectorFileList input vector file list (if provided + * \param rates + */ + void ExtractTrainData(FloatVectorImageListType *imageList, const TrainFileNamesHandler& fileNames, + std::vector<std::string> vectorFileList, + const SamplingRates& rates) + { +// if( !vectorFileList.empty() ) // Select and Extract samples for training with computed statistics and rates +// { + ComputePolygonStatistics( imageList, vectorFileList, fileNames.polyStatTrainOutputs ); + ComputeSamplingRate( fileNames.polyStatTrainOutputs, fileNames.rateTrainOut, rates.fmt ); + SelectAndExtractTrainSamples( fileNames, imageList, vectorFileList, SamplingStrategy::CLASS ); +// } +// else // Select training samples base on geometric sampling if no input vector is provided +// { +// SelectAndExtractTrainSamples( fileNames, imageList, vectorFileList, SamplingStrategy::GEOMETRIC, "fid" ); +// } + } + + + void DoExecute() + { + TrainFileNamesHandler fileNames; + std::vector<std::string> vectorFileList; + FloatVectorImageListType *imageList = GetParameterImageList( "io.il" ); + bool HasInputVector = IsParameterEnabled( "io.vd" ) && HasValue( "io.vd" ); + if(HasInputVector) + vectorFileList = GetParameterStringList( "io.vd" ); + + + unsigned long nbInputs = imageList->Size(); + + if( !HasInputVector ) { - polyStatTrainOutputs.push_back(outModel + "_stats_" + strIndex + ".xml"); - ratesTrainOutputs.push_back(outModel + "_rates_" + strIndex + ".csv"); - sampleOutputs.push_back(outModel + "_samples_" + strIndex + ".shp"); + otbAppLogFATAL( "Missing input vector data files" ); } - sampleTrainOutputs.push_back(outModel + "_samplesTrain_" + strIndex + ".shp"); - sampleValidOutputs.push_back(outModel + "_samplesValid_" + strIndex + ".shp"); - } - // --------------------------------------------------------------------------- - // Polygons stats - for (unsigned int i=0 ; i<nbInputs ; i++) - { - GetInternalApplication("polystat")->SetParameterInputImage("in",imageList->GetNthElement(i)); - GetInternalApplication("polystat")->SetParameterString("vec",vectorFileList[i], false); - GetInternalApplication("polystat")->SetParameterString("out",polyStatTrainOutputs[i], false); - ExecuteInternal("polystat"); - // analyse polygons given for validation - if (dedicatedValidation) + if( !vectorFileList.empty() && nbInputs > vectorFileList.size() ) { - GetInternalApplication("polystat")->SetParameterString("vec",validationVectorFileList[i], false); - GetInternalApplication("polystat")->SetParameterString("out",polyStatValidOutputs[i], false); - ExecuteInternal("polystat"); + otbAppLogFATAL( "Missing input vector data files to match number of images (" << nbInputs << ")." ); } - } - // --------------------------------------------------------------------------- - // Compute sampling rates - GetInternalApplication("rates")->SetParameterString("mim","proportional", false); - double vtr = GetParameterFloat("sample.vtr"); - long mt = GetParameterInt("sample.mt"); - long mv = GetParameterInt("sample.mv"); - // compute final maximum training and final maximum validation - // By default take all samples (-1 means all samples) - long fmt = -1; - long fmv = -1; - if (GetParameterInt("sample.bm") == 0) - { - if (dedicatedValidation) - { - // fmt and fmv will be used separately - fmt = mt; - fmv = mv; - if (mt > -1 && mv <= -1 && vtr < 0.99999) - { - fmv = static_cast<long>((double) mt * vtr / (1.0 - vtr)); - } - if (mt <= -1 && mv > -1 && vtr > 0.00001) - { - fmt = static_cast<long>((double) mv * (1.0 - vtr) / vtr); - } - } - else + // check if validation vectors are given + std::vector<std::string> validationVectorFileList; + bool dedicatedValidation = false; + if( IsParameterEnabled( "io.valid" ) && HasValue( "io.valid" ) ) { - // only fmt will be used for both training and validation samples - // So we try to compute the total number of samples given input - // parameters mt, mv and vtr. - if (mt > -1 && vtr < 0.99999) - { - fmt = static_cast<long>((double) mt / (1.0 - vtr)); - } - if (mv > -1 && vtr > 0.00001) + validationVectorFileList = GetParameterStringList( "io.valid" ); + if( nbInputs > validationVectorFileList.size() ) { - if (fmt > -1 ) - { - fmt = std::min(fmt, static_cast<long>((double) mv / vtr)); - } - else - { - fmt = static_cast<long>((double) mv / vtr); - } + otbAppLogFATAL( "Missing validation vector data files to match number of images (" << nbInputs << ")." ); } - } - } - // Sampling rates for training - GetInternalApplication("rates")->SetParameterStringList("il",polyStatTrainOutputs, false); - GetInternalApplication("rates")->SetParameterString("out",rateTrainOut, false); - if (GetParameterInt("sample.bm") != 0) - { - GetInternalApplication("rates")->SetParameterString("strategy","smallest", false); - } - else - { - if (fmt > -1) - { - std::ostringstream oss; - oss << fmt; - GetInternalApplication("rates")->SetParameterString("strategy","constant", false); - GetInternalApplication("rates")->SetParameterString("strategy.constant.nb",oss.str()); - } - else - { - GetInternalApplication("rates")->SetParameterString("strategy","all", false); + dedicatedValidation = true; } - } - ExecuteInternal("rates"); - // Sampling rates for validation - if (dedicatedValidation) - { - GetInternalApplication("rates")->SetParameterStringList("il",polyStatValidOutputs, false); - GetInternalApplication("rates")->SetParameterString("out",rateValidOut, false); - if (GetParameterInt("sample.bm") != 0) - { - GetInternalApplication("rates")->SetParameterString("strategy","smallest", false); - } - else - { - if (fmv > -1) - { - std::ostringstream oss; - oss << fmv; - GetInternalApplication("rates")->SetParameterString("strategy","constant", false); - GetInternalApplication("rates")->SetParameterString("strategy.constant.nb",oss.str()); - } - else - { - GetInternalApplication("rates")->SetParameterString("strategy","all", false); - } - } - ExecuteInternal("rates"); - } - // --------------------------------------------------------------------------- - // Select & extract samples - GetInternalApplication("select")->SetParameterString("sampler", "periodic", false); - GetInternalApplication("select")->SetParameterInt("sampler.periodic.jitter",50); - GetInternalApplication("select")->SetParameterString("strategy","byclass", false); - GetInternalApplication("extraction")->SetParameterString("outfield", "prefix", false); - GetInternalApplication("extraction")->SetParameterString("outfield.prefix.name","value_", false); - for (unsigned int i=0 ; i<nbInputs ; i++) - { - GetInternalApplication("select")->SetParameterInputImage("in",imageList->GetNthElement(i)); - GetInternalApplication("select")->SetParameterString("vec",vectorFileList[i], false); - GetInternalApplication("select")->SetParameterString("out",sampleOutputs[i], false); - GetInternalApplication("select")->SetParameterString("instats",polyStatTrainOutputs[i], false); - GetInternalApplication("select")->SetParameterString("strategy.byclass.in",ratesTrainOutputs[i], false); - // select sample positions - ExecuteInternal("select"); - // extract sample descriptors - ExecuteInternal("extraction"); + fileNames.CreateTemporaryFileNames( GetParameterString( "io.out" ), nbInputs, dedicatedValidation ); - if (dedicatedValidation) - { - GetInternalApplication("select")->SetParameterString("vec",validationVectorFileList[i], false); - GetInternalApplication("select")->SetParameterString("out",sampleValidOutputs[i], false); - GetInternalApplication("select")->SetParameterString("instats",polyStatValidOutputs[i], false); - GetInternalApplication("select")->SetParameterString("strategy.byclass.in",ratesValidOutputs[i], false); - // select sample positions - ExecuteInternal("select"); - // extract sample descriptors - ExecuteInternal("extraction"); - } - else - { - // Split between training and validation - ogr::DataSource::Pointer source = ogr::DataSource::New(sampleOutputs[i], ogr::DataSource::Modes::Read); - ogr::DataSource::Pointer destTrain = ogr::DataSource::New(sampleTrainOutputs[i], ogr::DataSource::Modes::Overwrite); - ogr::DataSource::Pointer destValid = ogr::DataSource::New(sampleValidOutputs[i], ogr::DataSource::Modes::Overwrite); - // read sampling rates from ratesTrainOutputs[i] - SamplingRateCalculator::Pointer rateCalculator = SamplingRateCalculator::New(); - rateCalculator->Read(ratesTrainOutputs[i]); - // Compute sampling rates for train and valid - const MapRateType &inputRates = rateCalculator->GetRatesByClass(); - MapRateType trainRates; - MapRateType validRates; - otb::SamplingRateCalculator::TripletType tpt; - for (MapRateType::const_iterator it = inputRates.begin() ; - it != inputRates.end() ; - ++it) - { - unsigned long total = std::min(it->second.Required,it->second.Tot ); - unsigned long neededValid = static_cast<unsigned long>((double) total * vtr ); - unsigned long neededTrain = total - neededValid; - tpt.Tot = total; - tpt.Required = neededTrain; - tpt.Rate = (1.0 - vtr); - trainRates[it->first] = tpt; - tpt.Tot = neededValid; - tpt.Required = neededValid; - tpt.Rate = 1.0; - validRates[it->first] = tpt; - } + // Compute final maximum sampling rates for both training and validation samples + SamplingRates rates = ComputeFinalMaximumSamplingRates( dedicatedValidation ); + + ExtractTrainData(imageList, fileNames, vectorFileList, rates); + ExtractValidationData(imageList, fileNames, validationVectorFileList, rates, HasInputVector); - // Use an otb::OGRDataToSamplePositionFilter with 2 outputs - PeriodicSamplerType::SamplerParameterType param; - param.Offset = 0; - param.MaxJitter = 0; - PeriodicSamplerType::Pointer splitter = PeriodicSamplerType::New(); - splitter->SetInput(imageList->GetNthElement(i)); - splitter->SetOGRData(source); - splitter->SetOutputPositionContainerAndRates(destTrain, trainRates, 0); - splitter->SetOutputPositionContainerAndRates(destValid, validRates, 1); - splitter->SetFieldName(this->GetParameterStringList("sample.vfn")[0]); - splitter->SetLayerIndex(0); - splitter->SetOriginFieldName(std::string("")); - splitter->SetSamplerParameters(param); - splitter->GetStreamer()->SetAutomaticTiledStreaming(this->GetParameterInt("ram")); - AddProcess(splitter->GetStreamer(),"Split samples between training and validation..."); - splitter->Update(); + // Then train the model with extracted samples + TrainModel( imageList, fileNames.sampleTrainOutputs, fileNames.sampleValidOutputs ); + + // cleanup + if( IsParameterEnabled( "cleanup" ) ) + { + otbAppLogINFO( <<"Final clean-up ..." ); + fileNames.clear(); } - } + } - // --------------------------------------------------------------------------- - // Train model - GetInternalApplication("training")->SetParameterStringList("io.vd",sampleTrainOutputs, false); - if( vtr!=0.0 && !sampleValidOutputs.empty() ) - GetInternalApplication("training")->SetParameterStringList("valid.vd",sampleValidOutputs, false); - UpdateInternalParameters("training"); - // set field names - FloatVectorImageType::Pointer image = imageList->GetNthElement(0); - unsigned int nbBands = image->GetNumberOfComponentsPerPixel(); - std::vector<std::string> selectedNames; - for (unsigned int i=0 ; i<nbBands ; i++) - { - std::ostringstream oss; - oss << i; - selectedNames.push_back("value_"+oss.str()); - } - GetInternalApplication("training")->SetParameterStringList("feat",selectedNames, false); - ExecuteInternal("training"); +private : - // cleanup - if(IsParameterEnabled("cleanup")) - { - otbAppLogINFO(<<"Final clean-up ..."); - for(unsigned int i=0 ; i<polyStatTrainOutputs.size() ; i++) - RemoveFile(polyStatTrainOutputs[i]); - for(unsigned int i=0 ; i<polyStatValidOutputs.size() ; i++) - RemoveFile(polyStatValidOutputs[i]); - for(unsigned int i=0 ; i<ratesTrainOutputs.size() ; i++) - RemoveFile(ratesTrainOutputs[i]); - for(unsigned int i=0 ; i<ratesValidOutputs.size() ; i++) - RemoveFile(ratesValidOutputs[i]); - for(unsigned int i=0 ; i<sampleOutputs.size() ; i++) - RemoveFile(sampleOutputs[i]); - for(unsigned int i=0 ; i<sampleTrainOutputs.size() ; i++) - RemoveFile(sampleTrainOutputs[i]); - for(unsigned int i=0 ; i<sampleValidOutputs.size() ; i++) - RemoveFile(sampleValidOutputs[i]); - } -} + void UpdatePolygonClassStatisticsParameters() + { + std::vector<std::string> vectorFileList = GetParameterStringList( "io.vd" ); + GetInternalApplication( "polystat" )->SetParameterString( "vec", vectorFileList[0], false ); + UpdateInternalParameters( "polystat" ); + } }; } // end namespace Wrapper } // end namespace otb -OTB_APPLICATION_EXPORT(otb::Wrapper::TrainImagesClassifier) +OTB_APPLICATION_EXPORT( otb::Wrapper::TrainImagesClassifier ) \ No newline at end of file diff --git a/Modules/Applications/AppClassification/app/otbTrainVectorClassifier.cxx b/Modules/Applications/AppClassification/app/otbTrainVectorClassifier.cxx index f9acb6fbe0cafd499c68c234d3a976fa223cd47a..b39c6fae197b4c1dddd0e08156b221668fb883a2 100644 --- a/Modules/Applications/AppClassification/app/otbTrainVectorClassifier.cxx +++ b/Modules/Applications/AppClassification/app/otbTrainVectorClassifier.cxx @@ -18,60 +18,30 @@ * limitations under the License. */ -#include "otbWrapperApplication.h" -#include "otbWrapperApplicationFactory.h" - -#include "otbLearningApplicationBase.h" - -#include "otbOGRDataSourceWrapper.h" -#include "otbOGRFeatureWrapper.h" -#include "otbStatisticsXMLFileWriter.h" - -#include "itkVariableLengthVector.h" -#include "otbStatisticsXMLFileReader.h" - -#include "itkListSample.h" -#include "otbShiftScaleSampleListFilter.h" +#include "otbTrainVectorBase.h" // Validation #include "otbConfusionMatrixCalculator.h" -#include <algorithm> -#include <locale> - namespace otb { namespace Wrapper { -/** Utility function to negate std::isalnum */ -bool IsNotAlphaNum(char c) - { - return !std::isalnum(c); - } - -class TrainVectorClassifier : public LearningApplicationBase<float,int> +class TrainVectorClassifier : public TrainVectorBase { public: typedef TrainVectorClassifier Self; - typedef LearningApplicationBase<float, int> Superclass; + typedef TrainVectorBase Superclass; typedef itk::SmartPointer<Self> Pointer; typedef itk::SmartPointer<const Self> ConstPointer; - itkNewMacro(Self) - - itkTypeMacro(Self, Superclass) - - typedef Superclass::SampleType SampleType; - typedef Superclass::ListSampleType ListSampleType; - typedef Superclass::TargetListSampleType TargetListSampleType; - typedef Superclass::SampleImageType SampleImageType; - - typedef double ValueType; - typedef itk::VariableLengthVector<ValueType> MeasurementType; + itkNewMacro( Self ) - typedef otb::StatisticsXMLFileReader<SampleType> StatisticsReader; + itkTypeMacro( Self, Superclass ) - typedef otb::Statistics::ShiftScaleSampleListFilter<ListSampleType, ListSampleType> ShiftScaleFilterType; + typedef Superclass::SampleType SampleType; + typedef Superclass::ListSampleType ListSampleType; + typedef Superclass::TargetListSampleType TargetListSampleType; // Estimate performance on validation sample typedef otb::ConfusionMatrixCalculator<TargetListSampleType, TargetListSampleType> ConfusionMatrixCalculatorType; @@ -79,503 +49,257 @@ public: typedef ConfusionMatrixCalculatorType::MapOfIndicesType MapOfIndicesType; typedef ConfusionMatrixCalculatorType::ClassLabelType ClassLabelType; -private: +protected: void DoInit() { - SetName("TrainVectorClassifier"); - SetDescription("Train a classifier based on labeled geometries and a list of features to consider."); - - SetDocName("Train Vector Classifier"); - SetDocLongDescription("This application trains a classifier based on " - "labeled geometries and a list of features to consider for classification."); - SetDocLimitations(" "); - SetDocAuthors("OTB Team"); - SetDocSeeAlso(" "); - - //Group IO - AddParameter(ParameterType_Group, "io", "Input and output data"); - SetParameterDescription("io", "This group of parameters allows setting input and output data."); - - AddParameter(ParameterType_InputVectorDataList, "io.vd", "Input Vector Data"); - SetParameterDescription("io.vd", "Input geometries used for training (note : all geometries from the layer will be used)"); - - AddParameter(ParameterType_InputFilename, "io.stats", "Input XML image statistics file"); - MandatoryOff("io.stats"); - SetParameterDescription("io.stats", "XML file containing mean and variance of each feature."); - - AddParameter(ParameterType_OutputFilename, "io.confmatout", "Output confusion matrix"); - SetParameterDescription("io.confmatout", "Output file containing the confusion matrix (.csv format)."); - MandatoryOff("io.confmatout"); - - AddParameter(ParameterType_OutputFilename, "io.out", "Output model"); - SetParameterDescription("io.out", "Output file containing the model estimated (.txt format)."); - - AddParameter(ParameterType_ListView, "feat", "Field names for training features."); - SetParameterDescription("feat","List of field names in the input vector data to be used as features for training."); - - AddParameter(ParameterType_ListView,"cfield","Field containing the class id for supervision"); - SetParameterDescription("cfield","Field containing the class id for supervision. " - "Only geometries with this field available will be taken into account."); - SetListViewSingleSelectionMode("cfield",true); - - AddParameter(ParameterType_Int, "layer", "Layer Index"); - SetParameterDescription("layer", "Index of the layer to use in the input vector file."); - MandatoryOff("layer"); - SetDefaultParameterInt("layer",0); - - AddParameter(ParameterType_Group, "valid", "Validation data"); - SetParameterDescription("valid", "This group of parameters defines validation data."); - - AddParameter(ParameterType_InputVectorDataList, "valid.vd", "Validation Vector Data"); - SetParameterDescription("valid.vd", "Geometries used for validation " - "(must contain the same fields used for training, all geometries from the layer will be used)"); - MandatoryOff("valid.vd"); - - AddParameter(ParameterType_Int, "valid.layer", "Layer Index"); - SetParameterDescription("valid.layer", "Index of the layer to use in the validation vector file."); - MandatoryOff("valid.layer"); - SetDefaultParameterInt("valid.layer",0); - - // Add parameters for the classifier choice - Superclass::DoInit(); + SetName( "TrainVectorClassifier" ); + SetDescription( "Train a classifier based on labeled geometries and a list of features to consider." ); + + SetDocName( "Train Vector Classifier" ); + SetDocLongDescription( "This application trains a classifier based on " + "labeled geometries and a list of features to consider for classification." ); + SetDocLimitations( " " ); + SetDocAuthors( "OTB Team" ); + SetDocSeeAlso( " " ); - AddRANDParameter(); - // Doc example parameter settings - SetDocExampleParameterValue("io.vd", "vectorData.shp"); - SetDocExampleParameterValue("io.stats", "meanVar.xml"); - SetDocExampleParameterValue("io.out", "svmModel.svm"); - SetDocExampleParameterValue("feat", "perimeter area width"); - SetDocExampleParameterValue("cfield", "predicted"); + Superclass::DoInit(); } void DoUpdateParameters() { - if ( HasValue("io.vd") ) + Superclass::DoUpdateParameters(); + } + + void DoExecute() + { + // Enforce the need of class field name in supervised mode + if (GetClassifierCategory() == Supervised) { - std::vector<std::string> vectorFileList = GetParameterStringList("io.vd"); - ogr::DataSource::Pointer ogrDS = - ogr::DataSource::New(vectorFileList[0], ogr::DataSource::Modes::Read); - ogr::Layer layer = ogrDS->GetLayer(this->GetParameterInt("layer")); - ogr::Feature feature = layer.ogr().GetNextFeature(); - - ClearChoices("feat"); - ClearChoices("cfield"); - - for(int iField=0; iField<feature.ogr().GetFieldCount(); iField++) + m_FeaturesInfo.SetClassFieldNames( GetChoiceNames( "cfield" ), GetSelectedItems( "cfield" ) ); + + if( m_FeaturesInfo.m_SelectedCFieldIdx.empty() ) { - 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 == OFTInteger || ogr::version_proxy::IsOFTInteger64(fieldType) || fieldType == OFTReal) - { - std::string tmpKey="feat."+key.substr(0, end - key.begin()); - AddChoice(tmpKey,item); - } - if(fieldType == OFTString || fieldType == OFTInteger || ogr::version_proxy::IsOFTInteger64(fieldType)) - { - std::string tmpKey="cfield."+key.substr(0, end - key.begin()); - AddChoice(tmpKey,item); - } + otbAppLogFATAL( << "No field has been selected for data labelling!" ); } } + + Superclass::DoExecute(); + + if (GetClassifierCategory() == Supervised) + { + ConfusionMatrixCalculatorType::Pointer confMatCalc = ComputeConfusionMatrix( m_PredictedList, + m_ClassificationSamplesWithLabel.labeledListSample ); + WriteConfusionMatrix( confMatCalc ); + } + else + { + // TODO Compute Contingency Table + } } -void LogConfusionMatrix(ConfusionMatrixCalculatorType* confMatCalc) -{ - ConfusionMatrixCalculatorType::ConfusionMatrixType matrix = confMatCalc->GetConfusionMatrix(); - // Compute minimal width - size_t minwidth = 0; + ConfusionMatrixCalculatorType::Pointer + ComputeConfusionMatrix(const TargetListSampleType::Pointer &predictedListSample, + const TargetListSampleType::Pointer &performanceLabeledListSample) + { + ConfusionMatrixCalculatorType::Pointer confMatCalc = ConfusionMatrixCalculatorType::New(); - for (unsigned int i = 0; i < matrix.Rows(); i++) - { - for (unsigned int j = 0; j < matrix.Cols(); j++) + otbAppLogINFO( "Predicted list size : " << predictedListSample->Size() ); + otbAppLogINFO( "ValidationLabeledListSample size : " << performanceLabeledListSample->Size() ); + confMatCalc->SetReferenceLabels( performanceLabeledListSample ); + confMatCalc->SetProducedLabels( predictedListSample ); + confMatCalc->Compute(); + + otbAppLogINFO( "training performances" ); + LogConfusionMatrix( confMatCalc ); + + for( unsigned int itClasses = 0; itClasses < confMatCalc->GetNumberOfClasses(); itClasses++ ) { - std::ostringstream os; - os << matrix(i, j); - size_t size = os.str().size(); + ConfusionMatrixCalculatorType::ClassLabelType classLabel = confMatCalc->GetMapOfIndices()[itClasses]; - if (size > minwidth) - { - minwidth = size; - } + otbAppLogINFO( "Precision of class [" << classLabel << "] vs all: " << confMatCalc->GetPrecisions()[itClasses] ); + otbAppLogINFO( "Recall of class [" << classLabel << "] vs all: " << confMatCalc->GetRecalls()[itClasses] ); + otbAppLogINFO( + "F-score of class [" << classLabel << "] vs all: " << confMatCalc->GetFScores()[itClasses] << "\n" ); } - } + otbAppLogINFO( "Global performance, Kappa index: " << confMatCalc->GetKappaIndex() ); + return confMatCalc; + } - MapOfIndicesType mapOfIndices = confMatCalc->GetMapOfIndices(); + /** + * Write the confidence matrix into a file if output is provided. + * \param confMatCalc the input matrix to write. + */ + void WriteConfusionMatrix(const ConfusionMatrixCalculatorType::Pointer &confMatCalc) + { + if( this->HasValue( "io.confmatout" ) ) + { + // Writing the confusion matrix in the output .CSV file - MapOfIndicesType::const_iterator it = mapOfIndices.begin(); - MapOfIndicesType::const_iterator end = mapOfIndices.end(); + MapOfIndicesType::iterator itMapOfIndicesValid, itMapOfIndicesPred; + ClassLabelType labelValid = 0; - for (; it != end; ++it) - { - std::ostringstream os; - os << "[" << it->second << "]"; + ConfusionMatrixType confusionMatrix = confMatCalc->GetConfusionMatrix(); + MapOfIndicesType mapOfIndicesValid = confMatCalc->GetMapOfIndices(); - size_t size = os.str().size(); - if (size > minwidth) - { - minwidth = size; - } - } + unsigned long nbClassesPred = mapOfIndicesValid.size(); - // Generate matrix string, with 'minwidth' as size specifier - std::ostringstream os; + ///////////////////////////////////////////// + // Filling the 2 headers for the output file + const std::string commentValidStr = "#Reference labels (rows):"; + const std::string commentPredStr = "#Produced labels (columns):"; + const char separatorChar = ','; + std::ostringstream ossHeaderValidLabels, ossHeaderPredLabels; - // Header line - for (size_t i = 0; i < minwidth; ++i) - os << " "; - os << " "; - - it = mapOfIndices.begin(); - end = mapOfIndices.end(); - for (; it != end; ++it) - { - os << "[" << it->second << "]" << " "; - } - - os << std::endl; - - // Each line of confusion matrix - for (unsigned int i = 0; i < matrix.Rows(); i++) - { - ConfusionMatrixCalculatorType::ClassLabelType label = mapOfIndices[i]; - os << "[" << std::setw(minwidth - 2) << label << "]" << " "; - for (unsigned int j = 0; j < matrix.Cols(); j++) - { - os << std::setw(minwidth) << matrix(i, j) << " "; - } - os << std::endl; - } + // Filling ossHeaderValidLabels and ossHeaderPredLabels for the output file + ossHeaderValidLabels << commentValidStr; + ossHeaderPredLabels << commentPredStr; - otbAppLogINFO("Confusion matrix (rows = reference labels, columns = produced labels):\n" << os.str()); -} + itMapOfIndicesValid = mapOfIndicesValid.begin(); + while( itMapOfIndicesValid != mapOfIndicesValid.end() ) + { + // labels labelValid of mapOfIndicesValid are already sorted in otbConfusionMatrixCalculator + labelValid = itMapOfIndicesValid->second; -void DoExecute() - { - typedef int LabelPixelType; - typedef itk::FixedArray<LabelPixelType,1> LabelSampleType; - typedef itk::Statistics::ListSample <LabelSampleType> LabelListSampleType; - - // Prepare selected field names (their position may change between two inputs) - std::vector<int> selectedIdx = GetSelectedItems("feat"); - std::vector<int> selectedCFieldIdx = GetSelectedItems("cfield"); - - if(selectedIdx.empty()) - { - otbAppLogFATAL(<<"No features have been selected to train the classifier on!"); - } - - if(selectedCFieldIdx.empty()) - { - otbAppLogFATAL(<<"No field has been selected for data labelling!"); - } - - const unsigned int nbFeatures = selectedIdx.size(); - std::vector<std::string> fieldNames = GetChoiceNames("feat"); - std::vector<std::string> cFieldNames = GetChoiceNames("cfield"); - std::vector<std::string> selectedNames(nbFeatures); - for (unsigned int i=0 ; i<nbFeatures ; i++) - { - selectedNames[i] = fieldNames[selectedIdx[i]]; - } - - std::string selectedCFieldName = cFieldNames[selectedCFieldIdx.front()]; - - std::vector<int> featureFieldIndex(nbFeatures, -1); - int cFieldIndex = -1; - - // Statistics for shift/scale - MeasurementType meanMeasurementVector; - MeasurementType stddevMeasurementVector; - if (HasValue("io.stats") && IsParameterEnabled("io.stats")) - { - StatisticsReader::Pointer statisticsReader = StatisticsReader::New(); - std::string XMLfile = GetParameterString("io.stats"); - statisticsReader->SetFileName(XMLfile); - meanMeasurementVector = statisticsReader->GetStatisticVectorByName("mean"); - stddevMeasurementVector = statisticsReader->GetStatisticVectorByName("stddev"); - } - else - { - meanMeasurementVector.SetSize(nbFeatures); - meanMeasurementVector.Fill(0.); - stddevMeasurementVector.SetSize(nbFeatures); - stddevMeasurementVector.Fill(1.); - } - - ListSampleType::Pointer input = ListSampleType::New(); - LabelListSampleType::Pointer target = LabelListSampleType::New(); - input->SetMeasurementVectorSize(nbFeatures); - - std::vector<std::string> vectorFileList = GetParameterStringList("io.vd"); - for (unsigned int k=0 ; k<vectorFileList.size() ; k++) - { - otbAppLogINFO("Reading input vector file "<<k+1<<"/"<<vectorFileList.size()); - ogr::DataSource::Pointer source = ogr::DataSource::New(vectorFileList[k], ogr::DataSource::Modes::Read); - ogr::Layer layer = source->GetLayer(this->GetParameterInt("layer")); - ogr::Feature feature = layer.ogr().GetNextFeature(); - bool goesOn = feature.addr() != 0; - if (!goesOn) - { - otbAppLogWARNING("The layer "<<GetParameterInt("layer")<<" of " - <<vectorFileList[k]<<" is empty, input is skipped."); - continue; - } + otbAppLogINFO( "mapOfIndicesValid[" << itMapOfIndicesValid->first << "] = " << labelValid ); - // Check all needed fields are present : - // - check class field - cFieldIndex = feature.ogr().GetFieldIndex(selectedCFieldName.c_str()); - if (cFieldIndex < 0) - otbAppLogFATAL("The field name for class label ("<<selectedCFieldName - <<") has not been found in the input vector file "<<vectorFileList[k]); - // - check feature fields - for (unsigned int i=0 ; i<nbFeatures ; i++) - { - featureFieldIndex[i] = feature.ogr().GetFieldIndex(selectedNames[i].c_str()); - if (featureFieldIndex[i] < 0) - otbAppLogFATAL("The field name for feature "<<selectedNames[i] - <<" has not been found in the input vector file "<<vectorFileList[k]); - } + ossHeaderValidLabels << labelValid; + ossHeaderPredLabels << labelValid; - while(goesOn) - { - if(feature.ogr().IsFieldSet(cFieldIndex)) - { - MeasurementType mv; - mv.SetSize(nbFeatures); - for(unsigned int idx=0; idx < nbFeatures; ++idx) - mv[idx] = feature.ogr().GetFieldAsDouble(featureFieldIndex[idx]); + ++itMapOfIndicesValid; - input->PushBack(mv); - target->PushBack(feature.ogr().GetFieldAsInteger(cFieldIndex)); - } - feature = layer.ogr().GetNextFeature(); - goesOn = feature.addr() != 0; - } - } - - ShiftScaleFilterType::Pointer trainingShiftScaleFilter = ShiftScaleFilterType::New(); - trainingShiftScaleFilter->SetInput(input); - trainingShiftScaleFilter->SetShifts(meanMeasurementVector); - trainingShiftScaleFilter->SetScales(stddevMeasurementVector); - trainingShiftScaleFilter->Update(); - - ListSampleType::Pointer trainingListSample= trainingShiftScaleFilter->GetOutput(); - TargetListSampleType::Pointer trainingLabeledListSample = target; - - //-------------------------- - // Estimate model - //-------------------------- - this->Train(trainingListSample,trainingLabeledListSample,GetParameterString("io.out")); - - //-------------------------- - // Performances estimation - //-------------------------- - ListSampleType::Pointer validationListSample=ListSampleType::New(); - TargetListSampleType::Pointer validationLabeledListSample = TargetListSampleType::New(); - - // Import validation data - if (HasValue("valid.vd") && IsParameterEnabled("valid.vd")) - { - input = ListSampleType::New(); - target = LabelListSampleType::New(); - input->SetMeasurementVectorSize(nbFeatures); - - std::vector<std::string> validFileList = this->GetParameterStringList("valid.vd"); - for (unsigned int k=0 ; k<validFileList.size() ; k++) - { - otbAppLogINFO("Reading validation vector file "<<k+1<<"/"<<validFileList.size()); - ogr::DataSource::Pointer source = ogr::DataSource::New(validFileList[k], ogr::DataSource::Modes::Read); - ogr::Layer layer = source->GetLayer(this->GetParameterInt("valid.layer")); - ogr::Feature feature = layer.ogr().GetNextFeature(); - bool goesOn = feature.addr() != 0; - if (!goesOn) - { - otbAppLogWARNING("The layer "<<GetParameterInt("valid.layer")<<" of " - <<validFileList[k]<<" is empty, input is skipped."); - continue; + if( itMapOfIndicesValid != mapOfIndicesValid.end() ) + { + ossHeaderValidLabels << separatorChar; + ossHeaderPredLabels << separatorChar; + } + else + { + ossHeaderValidLabels << std::endl; + ossHeaderPredLabels << std::endl; + } } - // Check all needed fields are present : - // - check class field - cFieldIndex = feature.ogr().GetFieldIndex(selectedCFieldName.c_str()); - if (cFieldIndex < 0) - otbAppLogFATAL("The field name for class label ("<<selectedCFieldName - <<") has not been found in the validation vector file "<<validFileList[k]); - // - check feature fields - for (unsigned int i=0 ; i<nbFeatures ; i++) - { - featureFieldIndex[i] = feature.ogr().GetFieldIndex(selectedNames[i].c_str()); - if (featureFieldIndex[i] < 0) - otbAppLogFATAL("The field name for feature "<<selectedNames[i] - <<" has not been found in the validation vector file "<<validFileList[k]); - } + std::ofstream outFile; + outFile.open( this->GetParameterString( "io.confmatout" ).c_str() ); + outFile << std::fixed; + outFile.precision( 10 ); + + ///////////////////////////////////// + // Writing the 2 headers + outFile << ossHeaderValidLabels.str(); + outFile << ossHeaderPredLabels.str(); + ///////////////////////////////////// + + unsigned int indexLabelValid = 0, indexLabelPred = 0; - while(goesOn) + for( itMapOfIndicesValid = mapOfIndicesValid.begin(); + itMapOfIndicesValid != mapOfIndicesValid.end(); ++itMapOfIndicesValid ) { - if(feature.ogr().IsFieldSet(cFieldIndex)) - { - MeasurementType mv; - mv.SetSize(nbFeatures); - for(unsigned int idx=0; idx < nbFeatures; ++idx) - mv[idx] = feature.ogr().GetFieldAsDouble(featureFieldIndex[idx]); + indexLabelPred = 0; - input->PushBack(mv); - target->PushBack(feature.ogr().GetFieldAsInteger(cFieldIndex)); + for( itMapOfIndicesPred = mapOfIndicesValid.begin(); + itMapOfIndicesPred != mapOfIndicesValid.end(); ++itMapOfIndicesPred ) + { + // Writing the confusion matrix (sorted in otbConfusionMatrixCalculator) in the output file + outFile << confusionMatrix( indexLabelValid, indexLabelPred ); + if( indexLabelPred < ( nbClassesPred - 1 ) ) + { + outFile << separatorChar; + } + else + { + outFile << std::endl; + } + ++indexLabelPred; } - feature = layer.ogr().GetNextFeature(); - goesOn = feature.addr() != 0; + + ++indexLabelValid; } + + outFile.close(); } + } + + /** + * Display the log of the confusion matrix computed with + * \param confMatCalc the input confusion matrix to display + */ + void LogConfusionMatrix(ConfusionMatrixCalculatorType *confMatCalc) + { + ConfusionMatrixCalculatorType::ConfusionMatrixType matrix = confMatCalc->GetConfusionMatrix(); + + // Compute minimal width + size_t minwidth = 0; - ShiftScaleFilterType::Pointer validShiftScaleFilter = ShiftScaleFilterType::New(); - validShiftScaleFilter->SetInput(input); - validShiftScaleFilter->SetShifts(meanMeasurementVector); - validShiftScaleFilter->SetScales(stddevMeasurementVector); - validShiftScaleFilter->Update(); - - validationListSample = validShiftScaleFilter->GetOutput(); - validationLabeledListSample = target; - } - - //Test the input validation set size - TargetListSampleType::Pointer predictedList = TargetListSampleType::New(); - ListSampleType::Pointer performanceListSample; - TargetListSampleType::Pointer performanceLabeledListSample; - if(validationLabeledListSample->Size() != 0) - { - performanceListSample = validationListSample; - performanceLabeledListSample = validationLabeledListSample; - } - else - { - otbAppLogWARNING("The validation set is empty. The performance estimation is done using the input training set in this case."); - performanceListSample = trainingListSample; - performanceLabeledListSample = trainingLabeledListSample; - } - - this->Classify(performanceListSample, predictedList, GetParameterString("io.out")); - - ConfusionMatrixCalculatorType::Pointer confMatCalc = ConfusionMatrixCalculatorType::New(); - - otbAppLogINFO("Predicted list size : " << predictedList->Size()); - otbAppLogINFO("ValidationLabeledListSample size : " << performanceLabeledListSample->Size()); - confMatCalc->SetReferenceLabels(performanceLabeledListSample); - confMatCalc->SetProducedLabels(predictedList); - confMatCalc->Compute(); - - otbAppLogINFO("training performances"); - LogConfusionMatrix(confMatCalc); - - for (unsigned int itClasses = 0; itClasses < confMatCalc->GetNumberOfClasses(); itClasses++) - { - ConfusionMatrixCalculatorType::ClassLabelType classLabel = confMatCalc->GetMapOfIndices()[itClasses]; - - otbAppLogINFO("Precision of class [" << classLabel << "] vs all: " << confMatCalc->GetPrecisions()[itClasses]); - otbAppLogINFO("Recall of class [" << classLabel << "] vs all: " << confMatCalc->GetRecalls()[itClasses]); - otbAppLogINFO( - "F-score of class [" << classLabel << "] vs all: " << confMatCalc->GetFScores()[itClasses] << "\n"); - } - otbAppLogINFO("Global performance, Kappa index: " << confMatCalc->GetKappaIndex()); - - - if (this->HasValue("io.confmatout")) - { - // Writing the confusion matrix in the output .CSV file - - MapOfIndicesType::iterator itMapOfIndicesValid, itMapOfIndicesPred; - ClassLabelType labelValid = 0; - - ConfusionMatrixType confusionMatrix = confMatCalc->GetConfusionMatrix(); - MapOfIndicesType mapOfIndicesValid = confMatCalc->GetMapOfIndices(); - - unsigned int nbClassesPred = mapOfIndicesValid.size(); - - ///////////////////////////////////////////// - // Filling the 2 headers for the output file - const std::string commentValidStr = "#Reference labels (rows):"; - const std::string commentPredStr = "#Produced labels (columns):"; - const char separatorChar = ','; - std::ostringstream ossHeaderValidLabels, ossHeaderPredLabels; - - // Filling ossHeaderValidLabels and ossHeaderPredLabels for the output file - ossHeaderValidLabels << commentValidStr; - ossHeaderPredLabels << commentPredStr; - - itMapOfIndicesValid = mapOfIndicesValid.begin(); - - while (itMapOfIndicesValid != mapOfIndicesValid.end()) + for( unsigned int i = 0; i < matrix.Rows(); i++ ) { - // labels labelValid of mapOfIndicesValid are already sorted in otbConfusionMatrixCalculator - labelValid = itMapOfIndicesValid->second; + for( unsigned int j = 0; j < matrix.Cols(); j++ ) + { + std::ostringstream os; + os << matrix( i, j ); + size_t size = os.str().size(); - otbAppLogINFO("mapOfIndicesValid[" << itMapOfIndicesValid->first << "] = " << labelValid); + if( size > minwidth ) + { + minwidth = size; + } + } + } - ossHeaderValidLabels << labelValid; - ossHeaderPredLabels << labelValid; + MapOfIndicesType mapOfIndices = confMatCalc->GetMapOfIndices(); - ++itMapOfIndicesValid; + MapOfIndicesType::const_iterator it = mapOfIndices.begin(); + MapOfIndicesType::const_iterator end = mapOfIndices.end(); - if (itMapOfIndicesValid != mapOfIndicesValid.end()) - { - ossHeaderValidLabels << separatorChar; - ossHeaderPredLabels << separatorChar; - } - else + for( ; it != end; ++it ) + { + std::ostringstream os; + os << "[" << it->second << "]"; + + size_t size = os.str().size(); + if( size > minwidth ) { - ossHeaderValidLabels << std::endl; - ossHeaderPredLabels << std::endl; + minwidth = size; } } - std::ofstream outFile; - outFile.open(this->GetParameterString("io.confmatout").c_str()); - outFile << std::fixed; - outFile.precision(10); - - ///////////////////////////////////// - // Writing the 2 headers - outFile << ossHeaderValidLabels.str(); - outFile << ossHeaderPredLabels.str(); - ///////////////////////////////////// + // Generate matrix string, with 'minwidth' as size specifier + std::ostringstream os; - unsigned int indexLabelValid = 0, indexLabelPred = 0; + // Header line + for( size_t i = 0; i < minwidth; ++i ) + os << " "; + os << " "; - for (itMapOfIndicesValid = mapOfIndicesValid.begin(); itMapOfIndicesValid != mapOfIndicesValid.end(); ++itMapOfIndicesValid) + it = mapOfIndices.begin(); + end = mapOfIndices.end(); + for( ; it != end; ++it ) { - indexLabelPred = 0; + os << "[" << it->second << "]" << " "; + } - for (itMapOfIndicesPred = mapOfIndicesValid.begin(); itMapOfIndicesPred != mapOfIndicesValid.end(); ++itMapOfIndicesPred) + os << std::endl; + + // Each line of confusion matrix + for( unsigned int i = 0; i < matrix.Rows(); i++ ) + { + ConfusionMatrixCalculatorType::ClassLabelType label = mapOfIndices[i]; + os << "[" << std::setw( minwidth - 2 ) << label << "]" << " "; + for( unsigned int j = 0; j < matrix.Cols(); j++ ) { - // Writing the confusion matrix (sorted in otbConfusionMatrixCalculator) in the output file - outFile << confusionMatrix(indexLabelValid, indexLabelPred); - if (indexLabelPred < (nbClassesPred - 1)) - { - outFile << separatorChar; - } - else - { - outFile << std::endl; - } - ++indexLabelPred; + os << std::setw( minwidth ) << matrix( i, j ) << " "; } - - ++indexLabelValid; + os << std::endl; } - outFile.close(); - } // END if (this->HasValue("io.confmatout")) + otbAppLogINFO( "Confusion matrix (rows = reference labels, columns = produced labels):\n" << os.str() ); } }; } } -OTB_APPLICATION_EXPORT(otb::Wrapper::TrainVectorClassifier) +OTB_APPLICATION_EXPORT( otb::Wrapper::TrainVectorClassifier ) diff --git a/Modules/Applications/AppClassification/include/otbLearningApplicationBase.h b/Modules/Applications/AppClassification/include/otbLearningApplicationBase.h index 79767a1c02509c581fe62e8fe5cb25eba89e19ba..991ee9aa892137f12ee07bdb3b89d15bdbb26d4a 100644 --- a/Modules/Applications/AppClassification/include/otbLearningApplicationBase.h +++ b/Modules/Applications/AppClassification/include/otbLearningApplicationBase.h @@ -102,7 +102,22 @@ public: typedef typename ModelType::TargetSampleType TargetSampleType; typedef typename ModelType::TargetListSampleType TargetListSampleType; typedef typename ModelType::TargetValueType TargetValueType; - + + itkGetConstReferenceMacro(SupervisedClassifier, std::vector<std::string>); + itkGetConstReferenceMacro(UnsupervisedClassifier, std::vector<std::string>); + + enum ClassifierCategory{ + Supervised, + Unsupervised + }; + + /** + * Retrieve the classifier category (supervisde or unsupervised) + * based on the select algorithm from the classifier choice. + * @return ClassifierCategory the classifier category + */ + ClassifierCategory GetClassifierCategory(); + protected: LearningApplicationBase(); @@ -120,15 +135,23 @@ protected: std::string modelPath); /** Init method that creates all the parameters for machine learning models */ - void DoInit(); + void DoInit() ITK_OVERRIDE; /** Flag to switch between classification and regression mode. * False by default, child classes may change it in their constructor */ bool m_RegressionFlag; private: - /** Specific Init and Train methods for each machine learning model */ + + /** Init Parameters for Supervised Classifier */ + void InitSupervisedClassifierParams(); + std::vector<std::string> m_SupervisedClassifier; + + /** Init Parameters for Unsupervised Classifier */ + void InitUnsupervisedClassifierParams(); + std::vector<std::string> m_UnsupervisedClassifier; + //@{ #ifdef OTB_USE_LIBSVM void InitLibSVMParams(); @@ -179,6 +202,10 @@ private: void TrainSharkRandomForests(typename ListSampleType::Pointer trainingListSample, typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath); + void InitSharkKMeansParams(); + void TrainSharkKMeans(typename ListSampleType::Pointer trainingListSample, + typename TargetListSampleType::Pointer trainingLabeledListSample, + std::string modelPath); #endif //@} }; @@ -203,6 +230,7 @@ private: #endif #ifdef OTB_USE_SHARK #include "otbTrainSharkRandomForests.txx" +#include "otbTrainSharkKMeans.txx" #endif #endif diff --git a/Modules/Applications/AppClassification/include/otbLearningApplicationBase.txx b/Modules/Applications/AppClassification/include/otbLearningApplicationBase.txx index c0a66443a8066cebc3bb906cdcb1f68d68981b0d..a40d0e505e3af53a3625976691aa402b1d59b827 100644 --- a/Modules/Applications/AppClassification/include/otbLearningApplicationBase.txx +++ b/Modules/Applications/AppClassification/include/otbLearningApplicationBase.txx @@ -54,8 +54,33 @@ LearningApplicationBase<TInputValue,TOutputValue> AddParameter(ParameterType_Choice, "classifier", "Classifier to use for the training"); SetParameterDescription("classifier", "Choice of the classifier to use for the training."); + InitSupervisedClassifierParams(); + m_SupervisedClassifier = GetChoiceKeys("classifier"); + + InitUnsupervisedClassifierParams(); + std::vector<std::string> allClassifier = GetChoiceKeys("classifier"); + m_UnsupervisedClassifier.assign(allClassifier.begin() + m_SupervisedClassifier.size(), allClassifier.end()); +} + +template <class TInputValue, class TOutputValue> +typename LearningApplicationBase<TInputValue,TOutputValue>::ClassifierCategory +LearningApplicationBase<TInputValue,TOutputValue> +::GetClassifierCategory() +{ + bool foundUnsupervised = + std::find(m_UnsupervisedClassifier.begin(), m_UnsupervisedClassifier.end(), + GetParameterString("classifier")) != m_UnsupervisedClassifier.end(); + return foundUnsupervised ? Unsupervised : Supervised; +} + +template <class TInputValue, class TOutputValue> +void +LearningApplicationBase<TInputValue,TOutputValue> +::InitSupervisedClassifierParams() +{ + //Group LibSVM -#ifdef OTB_USE_LIBSVM +#ifdef OTB_USE_LIBSVM InitLibSVMParams(); #endif @@ -81,7 +106,16 @@ LearningApplicationBase<TInputValue,TOutputValue> #ifdef OTB_USE_SHARK InitSharkRandomForestsParams(); #endif - +} + +template <class TInputValue, class TOutputValue> +void +LearningApplicationBase<TInputValue,TOutputValue> +::InitUnsupervisedClassifierParams() +{ +#ifdef OTB_USE_SHARK + InitSharkKMeansParams(); +#endif } template <class TInputValue, class TOutputValue> @@ -151,6 +185,14 @@ LearningApplicationBase<TInputValue,TOutputValue> otbAppLogFATAL("Module SharkLearning is not installed. You should consider turning OTB_USE_SHARK on during cmake configuration."); #endif } + else if(modelName == "sharkkm") + { + #ifdef OTB_USE_SHARK + TrainSharkKMeans( trainingListSample, trainingLabeledListSample, modelPath ); + #else + otbAppLogFATAL("Module SharkLearning is not installed. You should consider turning OTB_USE_SHARK on during cmake configuration."); + #endif + } else if (modelName == "svm") { #ifdef OTB_USE_OPENCV diff --git a/Modules/Applications/AppClassification/include/otbTrainImagesBase.h b/Modules/Applications/AppClassification/include/otbTrainImagesBase.h new file mode 100644 index 0000000000000000000000000000000000000000..a01eb6c430fffc3d588d109d0f41f1bf677783b5 --- /dev/null +++ b/Modules/Applications/AppClassification/include/otbTrainImagesBase.h @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2005-2017 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. + */ +#ifndef otbTrainImagesBase_h +#define otbTrainImagesBase_h + +#include "otbVectorDataFileWriter.h" +#include "otbWrapperCompositeApplication.h" +#include "otbWrapperApplicationFactory.h" + +#include "otbStatisticsXMLFileWriter.h" +#include "otbImageToEnvelopeVectorDataFilter.h" +#include "otbSamplingRateCalculator.h" +#include "otbOGRDataToSamplePositionFilter.h" + +namespace otb +{ +namespace Wrapper +{ + +/** \class TrainImagesBase + * \brief Base class for the TrainImagesClassifier + * + * This class intends to hold common input/output parameters and + * composite application connection for both supervised and unsupervised + * model training. + * + * \ingroup OTBAppClassification + */ +class TrainImagesBase : public CompositeApplication +{ +public: + /** Standard class typedefs. */ + typedef TrainImagesBase Self; + typedef CompositeApplication Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Standard macro */ + itkTypeMacro( TrainImagesBase, Superclass ) + + /** filters typedefs*/ + typedef otb::OGRDataToSamplePositionFilter<FloatVectorImageType, UInt8ImageType, otb::PeriodicSampler> PeriodicSamplerType; + + typedef otb::SamplingRateCalculator::MapRateType MapRateType; + +protected: + + enum SamplingStrategy + { + CLASS, GEOMETRIC + }; + struct SamplingRates; + class TrainFileNamesHandler; + + /** + * Initialize all the input and output parameter used for the train images + */ + void InitIO(); + + /** + * Initialize sampling related application and parameters + */ + void InitSampling(); + + void ShareSamplingParameters(); + void ConnectSamplingParameters(); + void InitClassification(); + void ShareClassificationParams(); + void ConnectClassificationParams(); + + /** + * Compute polygon statistics given provided strategy with PolygonClassStatistics class + * \param imageList list of input images + * \param vectorFileNames list of input vector file names + * \param statisticsFileNames list of out + */ + void ComputePolygonStatistics(FloatVectorImageListType *imageList, const std::vector<std::string> &vectorFileNames, + const std::vector<std::string> &statisticsFileNames); + + /** + * Compute final maximum training and validation + * \param dedicatedValidation + * \return SamplingRates final maximum training and final maximum validation + */ + SamplingRates ComputeFinalMaximumSamplingRates(bool dedicatedValidation); + + + /** + * Compute rates using MultiImageSamplingRate application + * \param statisticsFileNames + * \param ratesFileName + * \param maximum final maximum value computed by ComputeFinalMaximumSamplingRates + * \sa ComputeFinalMaximumSamplingRates + */ + void ComputeSamplingRate(const std::vector<std::string> &statisticsFileNames, + const std::string &ratesFileName, + long maximum); + /** + * Train the model with training and optional validation data samples + * \param imageList list of input images + * \param sampleTrainFileNames files names of the training samples + * \param sampleValidationFileNames file names of the validation sample + */ + void TrainModel(FloatVectorImageListType *imageList, const std::vector<std::string> &sampleTrainFileNames, + const std::vector<std::string> &sampleValidationFileNames); + + /** + * Select samples by class or by geographic strategy + * \param image + * \param vectorFileName + * \param sampleFileName + * \param statisticsFileName + * \param ratesFileName + * \param strategy + */ + void SelectAndExtractSamples(FloatVectorImageType *image, std::string vectorFileName, std::string sampleFileName, + std::string statisticsFileName, std::string ratesFileName, SamplingStrategy strategy, + std::string selectedField = ""); + /** + * Select and extract samples with the SampleSelection and SampleExtraction application. + * \param fileNames + * \param imageList + * \param vectorFileNames + * \param strategy the strategy used for selection (by class or with geometry) + * \param selectedFieldName + */ + void SelectAndExtractTrainSamples(const TrainFileNamesHandler &fileNames, FloatVectorImageListType *imageList, + std::vector<std::string> vectorFileNames, SamplingStrategy strategy, + std::string selectedFieldName = ""); + + + /** + * Function used to select validation samples based on a defined strategy (geometric in unsupervised mode) + * and extract them. With dedicated validation the 'by class' sampling strategy and statistics are used. + * Otherwise this function split training to validation samples corresponding to sample.vtr percentage. + * or do nothing if this percentage is == 0 + * \param fileNames + * \param imageList + * \param validationVectorFileList optional validation vector file for each images + */ + void SelectAndExtractValidationSamples(const TrainFileNamesHandler &fileNames, FloatVectorImageListType *imageList, + const std::vector<std::string> &validationVectorFileList = std::vector<std::string>()); + + /** + * Function used to split all training samples from all images in a set of training and validation. + * \param fileNames + * \param imageList + * \sa SplitTrainingAndValidationSamples + */ + void SplitTrainingToValidationSamples(const TrainFileNamesHandler &fileNames, FloatVectorImageListType *imageList); + +private: + + /** + * Function used to split training samples in set of training and validation. + * \param image input image + * \param sampleFileName the input sample file name + * \param sampleTrainFileName the input training file name + * \param sampleValidFileName the input validation file name + * \param ratesTrainFileName the rates file name + */ + void SplitTrainingAndValidationSamples(FloatVectorImageType *image, std::string sampleFileName, + std::string sampleTrainFileName, std::string sampleValidFileName, + std::string ratesTrainFileName); + + +protected: + + struct SamplingRates + { + long int fmt; + long int fmv; + }; + + /** + * \class TrainFileNamesHandler + * This class is used to store file names requires for the application's input and output. + * And to clear temporary files generated by the applications + * \ingroup OTBAppClassification + */ + class TrainFileNamesHandler + { + public : + void CreateTemporaryFileNames(std::string outModel, size_t nbInputs, bool dedicatedValidation) + { + + if( dedicatedValidation ) + { + rateTrainOut = outModel + "_ratesTrain.csv"; + } + else + { + rateTrainOut = outModel + "_rates.csv"; + } + + rateValidOut = outModel + "_ratesValid.csv"; + for( unsigned int i = 0; i < nbInputs; i++ ) + { + std::ostringstream oss; + oss << i + 1; + std::string strIndex( oss.str() ); + if( dedicatedValidation ) + { + polyStatTrainOutputs.push_back( outModel + "_statsTrain_" + strIndex + ".xml" ); + polyStatValidOutputs.push_back( outModel + "_statsValid_" + strIndex + ".xml" ); + ratesTrainOutputs.push_back( outModel + "_ratesTrain_" + strIndex + ".csv" ); + ratesValidOutputs.push_back( outModel + "_ratesValid_" + strIndex + ".csv" ); + sampleOutputs.push_back( outModel + "_samplesTrain_" + strIndex + ".shp" ); + } + else + { + polyStatTrainOutputs.push_back( outModel + "_stats_" + strIndex + ".xml" ); + ratesTrainOutputs.push_back( outModel + "_rates_" + strIndex + ".csv" ); + sampleOutputs.push_back( outModel + "_samples_" + strIndex + ".shp" ); + } + sampleTrainOutputs.push_back( outModel + "_samplesTrain_" + strIndex + ".shp" ); + sampleValidOutputs.push_back( outModel + "_samplesValid_" + strIndex + ".shp" ); + } + + } + + void clear() + { + for( unsigned int i = 0; i < polyStatTrainOutputs.size(); i++ ) + RemoveFile( polyStatTrainOutputs[i] ); + for( unsigned int i = 0; i < polyStatValidOutputs.size(); i++ ) + RemoveFile( polyStatValidOutputs[i] ); + for( unsigned int i = 0; i < ratesTrainOutputs.size(); i++ ) + RemoveFile( ratesTrainOutputs[i] ); + for( unsigned int i = 0; i < ratesValidOutputs.size(); i++ ) + RemoveFile( ratesValidOutputs[i] ); + for( unsigned int i = 0; i < sampleOutputs.size(); i++ ) + RemoveFile( sampleOutputs[i] ); + for( unsigned int i = 0; i < sampleTrainOutputs.size(); i++ ) + RemoveFile( sampleTrainOutputs[i] ); + for( unsigned int i = 0; i < sampleValidOutputs.size(); i++ ) + RemoveFile( sampleValidOutputs[i] ); + for( unsigned int i = 0; i < tmpVectorFileList.size(); i++ ) + RemoveFile( tmpVectorFileList[i] ); + } + + public: + std::vector<std::string> polyStatTrainOutputs; + std::vector<std::string> polyStatValidOutputs; + std::vector<std::string> ratesTrainOutputs; + std::vector<std::string> ratesValidOutputs; + std::vector<std::string> sampleOutputs; + std::vector<std::string> sampleTrainOutputs; + std::vector<std::string> sampleValidOutputs; + std::vector<std::string> tmpVectorFileList; + std::string rateValidOut; + std::string rateTrainOut; + + private: + bool RemoveFile(std::string &filePath) + { + bool res = true; + if( itksys::SystemTools::FileExists( filePath.c_str() ) ) + { + size_t posExt = filePath.rfind( '.' ); + if( posExt != std::string::npos && filePath.compare( posExt, std::string::npos, ".shp" ) == 0 ) + { + std::string shxPath = filePath.substr( 0, posExt ) + std::string( ".shx" ); + std::string dbfPath = filePath.substr( 0, posExt ) + std::string( ".dbf" ); + std::string prjPath = filePath.substr( 0, posExt ) + std::string( ".prj" ); + RemoveFile( shxPath ); + RemoveFile( dbfPath ); + RemoveFile( prjPath ); + } + res = itksys::SystemTools::RemoveFile( filePath.c_str() ); + if( !res ) + { + //otbAppLogINFO( <<"Unable to remove file "<<filePath ); + } + } + return res; + } + }; + +}; + +} // end namespace Wrapper +} // end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbTrainImagesBase.txx" +#endif + +#endif //otbTrainImagesBase_h diff --git a/Modules/Applications/AppClassification/include/otbTrainImagesBase.txx b/Modules/Applications/AppClassification/include/otbTrainImagesBase.txx new file mode 100644 index 0000000000000000000000000000000000000000..deb34bfc735224c66b64ac8a4d3d15d0b98ed7b3 --- /dev/null +++ b/Modules/Applications/AppClassification/include/otbTrainImagesBase.txx @@ -0,0 +1,407 @@ +/* + * Copyright (C) 2005-2017 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. + */ + +#ifndef otbTrainImagesBase_txx +#define otbTrainImagesBase_txx + +#include "otbTrainImagesBase.h" + +namespace otb +{ +namespace Wrapper +{ +void TrainImagesBase::InitIO() +{ + //Group IO + AddParameter( ParameterType_Group, "io", "Input and output data" ); + SetParameterDescription( "io", "This group of parameters allows setting input and output data." ); + + AddParameter( ParameterType_InputImageList, "io.il", "Input Image List" ); + SetParameterDescription( "io.il", "A list of input images." ); + 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" ); + + AddParameter( ParameterType_Empty, "cleanup", "Temporary files cleaning" ); + EnableParameter( "cleanup" ); + SetParameterDescription( "cleanup", + "If activated, the application will try to clean all temporary files it created" ); + MandatoryOff( "cleanup" ); +} + +void TrainImagesBase::InitSampling() +{ + AddApplication( "PolygonClassStatistics", "polystat", "Polygon analysis" ); + AddApplication( "MultiImageSamplingRate", "rates", "Sampling rates" ); + AddApplication( "SampleSelection", "select", "Sample selection" ); + AddApplication( "SampleExtraction", "extraction", "Sample extraction" ); + + // Sampling settings + AddParameter( ParameterType_Group, "sample", "Training and validation samples parameters" ); + SetParameterDescription( "sample", + "This group of parameters allows you to set training and validation sample lists parameters." ); + AddParameter( ParameterType_Int, "sample.mt", "Maximum training sample size per class" ); + SetDefaultParameterInt( "sample.mt", 1000 ); + SetParameterDescription( "sample.mt", "Maximum size per class (in pixels) of " + "the training sample list (default = 1000) (no limit = -1). If equal to -1," + " then the maximal size of the available training sample list per class " + "will be equal to the surface area of the smallest class multiplied by the" + " training sample ratio." ); + AddParameter( ParameterType_Int, "sample.mv", "Maximum validation sample size per class" ); + SetDefaultParameterInt( "sample.mv", 1000 ); + SetParameterDescription( "sample.mv", "Maximum size per class (in pixels) of " + "the validation sample list (default = 1000) (no limit = -1). If equal to -1," + " then the maximal size of the available validation sample list per class " + "will be equal to the surface area of the smallest class multiplied by the " + "validation sample ratio." ); + AddParameter( ParameterType_Int, "sample.bm", "Bound sample number by minimum" ); + SetDefaultParameterInt( "sample.bm", 1 ); + SetParameterDescription( "sample.bm", "Bound the number of samples for each " + "class by the number of available samples by the smaller class. Proportions " + "between training and validation are respected. Default is true (=1)." ); + AddParameter( ParameterType_Float, "sample.vtr", "Training and validation sample ratio" ); + SetParameterDescription( "sample.vtr", "Ratio between training and validation samples (0.0 = all training, 1.0 = " + "all validation) (default = 0.5)." ); + SetParameterFloat( "sample.vtr", 0.5, false ); + SetMaximumParameterFloatValue( "sample.vtr", 1.0 ); + SetMinimumParameterFloatValue( "sample.vtr", 0.0 ); + +// AddParameter( ParameterType_Float, "sample.percent", "Percentage of sample extract from images" ); +// SetParameterDescription( "sample.percent", "Percentage of sample extract from images for " +// "training and validation when only images are provided." ); +// SetDefaultParameterFloat( "sample.percent", 1.0 ); +// SetMinimumParameterFloatValue( "sample.percent", 0.0 ); +// SetMaximumParameterFloatValue( "sample.percent", 1.0 ); + + ShareSamplingParameters(); + ConnectSamplingParameters(); +} + +void TrainImagesBase::ShareSamplingParameters() +{ + // hide sampling parameters + //ShareParameter("sample.strategy","rates.strategy"); + //ShareParameter("sample.mim","rates.mim"); + ShareParameter( "ram", "polystat.ram" ); + ShareParameter( "elev", "polystat.elev" ); + ShareParameter( "sample.vfn", "polystat.field" ); +} + +void TrainImagesBase::ConnectSamplingParameters() +{ + Connect( "extraction.field", "polystat.field" ); + Connect( "extraction.layer", "polystat.layer" ); + + Connect( "select.ram", "polystat.ram" ); + Connect( "extraction.ram", "polystat.ram" ); + + Connect( "select.field", "polystat.field" ); + Connect( "select.layer", "polystat.layer" ); + Connect( "select.elev", "polystat.elev" ); + + Connect( "extraction.in", "select.in" ); + Connect( "extraction.vec", "select.out" ); +} + +void TrainImagesBase::InitClassification() +{ + AddApplication( "TrainVectorClassifier", "training", "Model training" ); + + AddParameter( ParameterType_InputVectorDataList, "io.valid", "Validation Vector Data List" ); + SetParameterDescription( "io.valid", "A list of vector data to select the training samples." ); + MandatoryOff( "io.valid" ); + + ShareClassificationParams(); + ConnectClassificationParams(); +}; + +void TrainImagesBase::ShareClassificationParams() +{ + ShareParameter( "io.imstat", "training.io.stats" ); + ShareParameter( "io.out", "training.io.out" ); + + ShareParameter( "classifier", "training.classifier" ); + ShareParameter( "rand", "training.rand" ); + + ShareParameter( "io.confmatout", "training.io.confmatout" ); +} + +void TrainImagesBase::ConnectClassificationParams() +{ + Connect( "training.cfield", "polystat.field" ); + Connect( "select.rand", "training.rand" ); +} + +void TrainImagesBase::ComputePolygonStatistics(FloatVectorImageListType *imageList, + const std::vector<std::string> &vectorFileNames, + const std::vector<std::string> &statisticsFileNames) +{ + unsigned int nbImages = static_cast<unsigned int>(imageList->Size()); + for( unsigned int i = 0; i < nbImages; i++ ) + { + GetInternalApplication( "polystat" )->SetParameterInputImage( "in", imageList->GetNthElement( i ) ); + GetInternalApplication( "polystat" )->SetParameterString( "vec", vectorFileNames[i], false ); + GetInternalApplication( "polystat" )->SetParameterString( "out", statisticsFileNames[i], false ); + ExecuteInternal( "polystat" ); + } +} + + +TrainImagesBase::SamplingRates TrainImagesBase::ComputeFinalMaximumSamplingRates(bool dedicatedValidation) +{ + SamplingRates rates; + GetInternalApplication( "rates" )->SetParameterString( "mim", "proportional", false ); + double vtr = GetParameterFloat( "sample.vtr" ); + long mt = GetParameterInt( "sample.mt" ); + long mv = GetParameterInt( "sample.mv" ); + // compute final maximum training and final maximum validation + // By default take all samples (-1 means all samples) + rates.fmt = -1; + rates.fmv = -1; + if( GetParameterInt( "sample.bm" ) == 0 ) + { + if( dedicatedValidation ) + { + // fmt and fmv will be used separately + rates.fmt = mt; + rates.fmv = mv; + if( mt > -1 && mv <= -1 && vtr < 0.99999 ) + { + rates.fmv = static_cast<long>(( double ) mt * vtr / ( 1.0 - vtr )); + } + if( mt <= -1 && mv > -1 && vtr > 0.00001 ) + { + rates.fmt = static_cast<long>(( double ) mv * ( 1.0 - vtr ) / vtr); + } + } + else + { + // only fmt will be used for both training and validation samples + // So we try to compute the total number of samples given input + // parameters mt, mv and vtr. + if( mt > -1 && vtr < 0.99999 ) + { + rates.fmt = static_cast<long>(( double ) mt / ( 1.0 - vtr )); + } + if( mv > -1 && vtr > 0.00001 ) + { + if( rates.fmt > -1 ) + { + rates.fmt = std::min( rates.fmt, static_cast<long>(( double ) mv / vtr) ); + } + else + { + rates.fmt = static_cast<long>(( double ) mv / vtr); + } + } + } + } + return rates; +} + + +void TrainImagesBase::ComputeSamplingRate(const std::vector<std::string> &statisticsFileNames, + const std::string &ratesFileName, long maximum) +{ + // Sampling rates + GetInternalApplication( "rates" )->SetParameterStringList( "il", statisticsFileNames, false ); + GetInternalApplication( "rates" )->SetParameterString( "out", ratesFileName, false ); + if( GetParameterInt( "sample.bm" ) != 0 ) + { + GetInternalApplication( "rates" )->SetParameterString( "strategy", "smallest", false ); + } + else + { + if( maximum > -1 ) + { + std::ostringstream oss; + oss << maximum; + GetInternalApplication( "rates" )->SetParameterString( "strategy", "constant", false ); + GetInternalApplication( "rates" )->SetParameterString( "strategy.constant.nb", oss.str(), false ); + } + else + { + GetInternalApplication( "rates" )->SetParameterString( "strategy", "all", false ); + } + } + ExecuteInternal( "rates" ); +} + +void +TrainImagesBase::TrainModel(FloatVectorImageListType *imageList, const std::vector<std::string> &sampleTrainFileNames, + const std::vector<std::string> &sampleValidationFileNames) +{ + GetInternalApplication( "training" )->SetParameterStringList( "io.vd", sampleTrainFileNames, false ); + if( !sampleValidationFileNames.empty() ) + GetInternalApplication( "training" )->SetParameterStringList( "valid.vd", sampleValidationFileNames, false ); + + UpdateInternalParameters( "training" ); + // set field names + FloatVectorImageType::Pointer image = imageList->GetNthElement( 0 ); + unsigned int nbBands = image->GetNumberOfComponentsPerPixel(); + std::vector<std::string> selectedNames; + for( unsigned int i = 0; i < nbBands; i++ ) + { + std::ostringstream oss; + oss << i; + selectedNames.push_back( "value_" + oss.str() ); + } + GetInternalApplication( "training" )->SetParameterStringList( "feat", selectedNames, false ); + ExecuteInternal( "training" ); +} + +void TrainImagesBase::SelectAndExtractSamples(FloatVectorImageType *image, std::string vectorFileName, + std::string sampleFileName, std::string statisticsFileName, + std::string ratesFileName, SamplingStrategy strategy, + std::string selectedField) +{ + GetInternalApplication( "select" )->SetParameterInputImage( "in", image ); + GetInternalApplication( "select" )->SetParameterString( "out", sampleFileName, false ); + + // Change the selection strategy based on selected sampling strategy + switch( strategy ) + { +// case GEOMETRIC: +// GetInternalApplication( "select" )->SetParameterString( "sampler", "random", false ); +// GetInternalApplication( "select" )->SetParameterString( "strategy", "percent", false ); +// GetInternalApplication( "select" )->SetParameterFloat( "strategy.percent.p", +// GetParameterFloat( "sample.percent" ), false ); +// break; + case CLASS: + default: + GetInternalApplication( "select" )->SetParameterString( "vec", vectorFileName, false ); + GetInternalApplication( "select" )->SetParameterString( "instats", statisticsFileName, false ); + GetInternalApplication( "select" )->SetParameterString( "sampler", "periodic", false ); + GetInternalApplication( "select" )->SetParameterInt( "sampler.periodic.jitter", 50 ); + GetInternalApplication( "select" )->SetParameterString( "strategy", "byclass", false ); + GetInternalApplication( "select" )->SetParameterString( "strategy.byclass.in", ratesFileName, false ); + break; + } + + // select sample positions + ExecuteInternal( "select" ); + + GetInternalApplication( "extraction" )->SetParameterString( "vec", sampleFileName, false ); + UpdateInternalParameters( "extraction" ); + if( !selectedField.empty() ) + GetInternalApplication( "extraction" )->SetParameterString( "field", selectedField, false ); + + GetInternalApplication( "extraction" )->SetParameterString( "outfield", "prefix", false ); + GetInternalApplication( "extraction" )->SetParameterString( "outfield.prefix.name", "value_", false ); + + // extract sample descriptors + ExecuteInternal( "extraction" ); +} + + +void TrainImagesBase::SelectAndExtractTrainSamples(const TrainFileNamesHandler &fileNames, + FloatVectorImageListType *imageList, + std::vector<std::string> vectorFileNames, SamplingStrategy strategy, + std::string selectedFieldName) +{ + + for( unsigned int i = 0; i < imageList->Size(); ++i ) + { + std::string vectorFileName = vectorFileNames.empty() ? "" : vectorFileNames[i]; + SelectAndExtractSamples( imageList->GetNthElement( i ), vectorFileName, fileNames.sampleOutputs[i], + fileNames.polyStatTrainOutputs[i], fileNames.ratesTrainOutputs[i], strategy, + selectedFieldName ); + } +} + + +void TrainImagesBase::SelectAndExtractValidationSamples(const TrainFileNamesHandler &fileNames, + FloatVectorImageListType *imageList, + const std::vector<std::string> &validationVectorFileList) +{ + for( unsigned int i = 0; i < imageList->Size(); ++i ) + { + SelectAndExtractSamples( imageList->GetNthElement( i ), validationVectorFileList[i], + fileNames.sampleValidOutputs[i], fileNames.polyStatValidOutputs[i], + fileNames.ratesValidOutputs[i], SamplingStrategy::CLASS ); + } +} + +void TrainImagesBase::SplitTrainingToValidationSamples(const TrainFileNamesHandler &fileNames, + FloatVectorImageListType *imageList) +{ + for( unsigned int i = 0; i < imageList->Size(); ++i ) + { + SplitTrainingAndValidationSamples( imageList->GetNthElement( i ), fileNames.sampleOutputs[i], + fileNames.sampleTrainOutputs[i], fileNames.sampleValidOutputs[i], + fileNames.ratesTrainOutputs[i] ); + } +} + +void TrainImagesBase::SplitTrainingAndValidationSamples(FloatVectorImageType *image, std::string sampleFileName, + std::string sampleTrainFileName, + std::string sampleValidFileName, + std::string ratesTrainFileName) + +{ + // Split between training and validation + ogr::DataSource::Pointer source = ogr::DataSource::New( sampleFileName, ogr::DataSource::Modes::Read ); + ogr::DataSource::Pointer destTrain = ogr::DataSource::New( sampleTrainFileName, ogr::DataSource::Modes::Overwrite ); + ogr::DataSource::Pointer destValid = ogr::DataSource::New( sampleValidFileName, ogr::DataSource::Modes::Overwrite ); + // read sampling rates from ratesTrainOutputs + SamplingRateCalculator::Pointer rateCalculator = SamplingRateCalculator::New(); + rateCalculator->Read( ratesTrainFileName ); + // Compute sampling rates for train and valid + const MapRateType &inputRates = rateCalculator->GetRatesByClass(); + MapRateType trainRates; + MapRateType validRates; + otb::SamplingRateCalculator::TripletType tpt; + for( MapRateType::const_iterator it = inputRates.begin(); it != inputRates.end(); ++it ) + { + double vtr = GetParameterFloat( "sample.vtr" ); + unsigned long total = std::min( it->second.Required, it->second.Tot ); + unsigned long neededValid = static_cast<unsigned long>(( double ) total * vtr ); + unsigned long neededTrain = total - neededValid; + tpt.Tot = total; + tpt.Required = neededTrain; + tpt.Rate = ( 1.0 - vtr ); + trainRates[it->first] = tpt; + tpt.Tot = neededValid; + tpt.Required = neededValid; + tpt.Rate = 1.0; + validRates[it->first] = tpt; + } + + // Use an otb::OGRDataToSamplePositionFilter with 2 outputs + PeriodicSamplerType::SamplerParameterType param; + param.Offset = 0; + param.MaxJitter = 0; + PeriodicSamplerType::Pointer splitter = PeriodicSamplerType::New(); + splitter->SetInput( image ); + splitter->SetOGRData( source ); + splitter->SetOutputPositionContainerAndRates( destTrain, trainRates, 0 ); + splitter->SetOutputPositionContainerAndRates( destValid, validRates, 1 ); + splitter->SetFieldName( this->GetParameterStringList( "sample.vfn" )[0] ); + splitter->SetLayerIndex( 0 ); + splitter->SetOriginFieldName( std::string( "" ) ); + splitter->SetSamplerParameters( param ); + splitter->GetStreamer()->SetAutomaticTiledStreaming( static_cast<unsigned int>(this->GetParameterInt( "ram" )) ); + AddProcess( splitter->GetStreamer(), "Split samples between training and validation..." ); + splitter->Update(); +} +} +} + +#endif diff --git a/Modules/Applications/AppClassification/include/otbTrainSharkKMeans.txx b/Modules/Applications/AppClassification/include/otbTrainSharkKMeans.txx new file mode 100644 index 0000000000000000000000000000000000000000..ca03ea33b2d8ee3b3085db3d0f112447eebaf77b --- /dev/null +++ b/Modules/Applications/AppClassification/include/otbTrainSharkKMeans.txx @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005-2017 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. + */ +#ifndef otbTrainSharkKMeans_txx +#define otbTrainSharkKMeans_txx + +#include "otbLearningApplicationBase.h" +#include "otbSharkKMeansMachineLearningModel.h" + +namespace otb +{ +namespace Wrapper +{ +template<class TInputValue, class TOutputValue> +void LearningApplicationBase<TInputValue, TOutputValue>::InitSharkKMeansParams() +{ + AddChoice( "classifier.sharkkm", "Shark kmeans classifier" ); + SetParameterDescription( "classifier.sharkkm", + "This group of parameters allows setting Shark kMeans classifier parameters. " + "See complete documentation here " + "\\url{http://image.diku.dk/shark/sphinx_pages/build/html/rest_sources/tutorials/algorithms/kmeans.html}.\n " ); + //MaxNumberOfIterations + AddParameter( ParameterType_Int, "classifier.sharkkm.maxiter", + "Maximum number of iteration for the kmeans algorithm." ); + SetParameterInt( "classifier.sharkkm.maxiter", 10 ); + SetMinimumParameterIntValue( "classifier.sharkkm.maxiter", 0 ); + SetParameterDescription( "classifier.sharkkm.maxiter", + "The maximum number of iteration for the kmeans algorithm. 0=unlimited" ); + + //MaxNumberOfIterations + AddParameter( ParameterType_Int, "classifier.sharkkm.k", "The number of class used for the kmeans algorithm." ); + SetParameterInt( "classifier.sharkkm.k", 2 ); + SetParameterDescription( "classifier.sharkkm.k", + "The number of class used for the kmeans algorithm. Default set to 2 class" ); + SetMinimumParameterIntValue( "classifier.sharkkm.k", 2 ); +} + +template<class TInputValue, class TOutputValue> +void LearningApplicationBase<TInputValue, TOutputValue>::TrainSharkKMeans( + typename ListSampleType::Pointer trainingListSample, + typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath) +{ + unsigned int nbMaxIter = static_cast<unsigned int>(abs( GetParameterInt( "classifier.sharkkm.maxiter" ) )); + unsigned int k = static_cast<unsigned int>(abs( GetParameterInt( "classifier.sharkkm.k" ) )); + + typedef otb::SharkKMeansMachineLearningModel<InputValueType, OutputValueType> SharkKMeansType; + typename SharkKMeansType::Pointer classifier = SharkKMeansType::New(); + classifier->SetRegressionMode( this->m_RegressionFlag ); + classifier->SetInputListSample( trainingListSample ); + classifier->SetTargetListSample( trainingLabeledListSample ); + classifier->SetK( k ); + classifier->SetMaximumNumberOfIterations( nbMaxIter ); + classifier->Train(); + classifier->Save( modelPath ); +} + +} //end namespace wrapper +} //end namespace otb + +#endif diff --git a/Modules/Applications/AppClassification/include/otbTrainVectorBase.h b/Modules/Applications/AppClassification/include/otbTrainVectorBase.h new file mode 100644 index 0000000000000000000000000000000000000000..3e1d27b94902a067dfc992a4aefd1f854ffa4177 --- /dev/null +++ b/Modules/Applications/AppClassification/include/otbTrainVectorBase.h @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2005-2017 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. + */ +#ifndef otbTrainVectorBase_h +#define otbTrainVectorBase_h + +#include "otbLearningApplicationBase.h" +#include "otbWrapperApplication.h" +#include "otbWrapperApplicationFactory.h" + +#include "otbOGRDataSourceWrapper.h" +#include "otbOGRFeatureWrapper.h" +#include "otbStatisticsXMLFileWriter.h" + +#include "itkVariableLengthVector.h" +#include "otbStatisticsXMLFileReader.h" + +#include "itkListSample.h" +#include "otbShiftScaleSampleListFilter.h" + +#include <algorithm> +#include <locale> + +namespace otb +{ +namespace Wrapper +{ + +/** Utility function to negate std::isalnum */ +bool IsNotAlphaNum(char c) +{ + return !std::isalnum( c ); +} + +class TrainVectorBase : public LearningApplicationBase<float, int> +{ +public: + /** Standard class typedefs. */ + typedef TrainVectorBase Self; + typedef LearningApplicationBase<float, int> Superclass; + typedef itk::SmartPointer <Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Standard macro */ + itkTypeMacro(Self, Superclass) + + typedef Superclass::SampleType SampleType; + typedef Superclass::ListSampleType ListSampleType; + typedef Superclass::TargetListSampleType TargetListSampleType; + + typedef double ValueType; + typedef itk::VariableLengthVector <ValueType> MeasurementType; + + typedef otb::StatisticsXMLFileReader<SampleType> StatisticsReader; + + typedef otb::Statistics::ShiftScaleSampleListFilter<ListSampleType, ListSampleType> ShiftScaleFilterType; + +protected: + + /** Class used to store statistics Measurment (mean/stddev) */ + class ShiftScaleParameters + { + public: + MeasurementType meanMeasurementVector; + MeasurementType stddevMeasurementVector; + }; + + /** Class used to store a list of sample and the corresponding label */ + class SamplesWithLabel + { + public: + ListSampleType::Pointer listSample; + TargetListSampleType::Pointer labeledListSample; + SamplesWithLabel() + { + listSample = ListSampleType::New(); + labeledListSample = TargetListSampleType::New(); + } + }; + + /** + * Features information class used to store informations + * about the field and class name/id of an input vector + */ + class FeaturesInfo + { + public: + /** Selected Index */ + std::vector<int> m_SelectedIdx; + /** Index for class field */ + std::vector<int> m_SelectedCFieldIdx; + /** Selected class field name */ + std::string m_SelectedCFieldName; + /** Selected names */ + std::vector <std::string> m_SelectedNames; + unsigned int m_NbFeatures; + + void SetFieldNames(std::vector <std::string> fieldNames, std::vector<int> selectedIdx) + { + m_SelectedIdx = selectedIdx; + m_NbFeatures = static_cast<unsigned int>(selectedIdx.size()); + m_SelectedNames = std::vector<std::string>( m_NbFeatures ); + for( unsigned int i = 0; i < m_NbFeatures; ++i ) + { + m_SelectedNames[i] = fieldNames[selectedIdx[i]]; + } + } + void SetClassFieldNames(std::vector<std::string> cFieldNames, std::vector<int> selectedCFieldIdx) + { + m_SelectedCFieldIdx = selectedCFieldIdx; + // Handle only one class field name, if several are provided only the first one is used. + m_SelectedCFieldName = cFieldNames[selectedCFieldIdx.front()]; + } + }; + + +protected: + + /** + * Function which extract and store all samples for Training and Classification. + * \param measurement statics measurement (mean/stddev) + * \param featuresInfo information about the features + */ + virtual void ExtractAllSamples(const ShiftScaleParameters &measurement); + + /** + * Extract the training sample list + * \param measurement statics measurement (mean/stddev) + * \param featuresInfo information about the features + * \return sample list used for training + */ + virtual SamplesWithLabel ExtractTrainingSamplesWithLabel(const ShiftScaleParameters &measurement); + + /** + * Extract classification the sample list + * \param measurement statics measurement (mean/stddev) + * \param featuresInfo information about the features + * \return sample list used for classification + */ + virtual SamplesWithLabel ExtractClassificationSamplesWithLabel(const ShiftScaleParameters &measurement); + + + /** Extract samples from input file for corresponding field name + * + * \param parameterName the name of the input file option in the input application parameters + * \param parameterLayer the name of the layer option in the input application parameters + * \param measurement statics measurement (mean/stddev) + * \param nbFeatures the number of features. + * \return the list of samples and their corresponding labels. + */ + SamplesWithLabel + ExtractSamplesWithLabel(std::string parameterName, std::string parameterLayer, const ShiftScaleParameters &measurement); + + + /** + * Retrieve statistics mean and standard deviation if input statistics are provided. + * Otherwise mean is set to 0 and standard deviation to 1 for each Features. + * \param nbFeatures + */ + ShiftScaleParameters GetStatistics(unsigned int nbFeatures); + + SamplesWithLabel m_TrainingSamplesWithLabel; + SamplesWithLabel m_ClassificationSamplesWithLabel; + TargetListSampleType::Pointer m_PredictedList; + FeaturesInfo m_FeaturesInfo; + + void DoInit() ITK_OVERRIDE; + void DoUpdateParameters() ITK_OVERRIDE; + void DoExecute() ITK_OVERRIDE; + +}; + +} +} + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbTrainVectorBase.txx" +#endif + +#endif diff --git a/Modules/Applications/AppClassification/include/otbTrainVectorBase.txx b/Modules/Applications/AppClassification/include/otbTrainVectorBase.txx new file mode 100644 index 0000000000000000000000000000000000000000..57554baccf5174c0ad084a1e80b99a0d93e5f56c --- /dev/null +++ b/Modules/Applications/AppClassification/include/otbTrainVectorBase.txx @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2005-2017 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. + */ +#ifndef otbTrainVectorBase_txx +#define otbTrainVectorBase_txx + +#include "otbTrainVectorBase.h" + +namespace otb +{ +namespace Wrapper +{ + +void TrainVectorBase::DoInit() +{ + // Common Parameters for all Learning Application + AddParameter( ParameterType_Group, "io", "Input and output data" ); + SetParameterDescription( "io", "This group of parameters allows setting input and output data." ); + + AddParameter( ParameterType_InputVectorDataList, "io.vd", "Input Vector Data" ); + SetParameterDescription( "io.vd", + "Input geometries used for training (note : all geometries from the layer will be used)" ); + + AddParameter( ParameterType_InputFilename, "io.stats", "Input XML image statistics file" ); + MandatoryOff( "io.stats" ); + SetParameterDescription( "io.stats", "XML file containing mean and variance of each feature." ); + + AddParameter( ParameterType_OutputFilename, "io.out", "Output model" ); + SetParameterDescription( "io.out", "Output file containing the model estimated (.txt format)." ); + + AddParameter( ParameterType_Int, "layer", "Layer Index" ); + SetParameterDescription( "layer", "Index of the layer to use in the input vector file." ); + MandatoryOff( "layer" ); + SetDefaultParameterInt( "layer", 0 ); + + AddParameter(ParameterType_ListView, "feat", "Field names for training features."); + SetParameterDescription("feat","List of field names in the input vector data to be used as features for training."); + + // Add validation data used to compute confusion matrix or contingency table + AddParameter( ParameterType_Group, "valid", "Validation data" ); + SetParameterDescription( "valid", "This group of parameters defines validation data." ); + + AddParameter( ParameterType_InputVectorDataList, "valid.vd", "Validation Vector Data" ); + SetParameterDescription( "valid.vd", "Geometries used for validation " + "(must contain the same fields used for training, all geometries from the layer will be used)" ); + MandatoryOff( "valid.vd" ); + + AddParameter( ParameterType_Int, "valid.layer", "Layer Index" ); + SetParameterDescription( "valid.layer", "Index of the layer to use in the validation vector file." ); + MandatoryOff( "valid.layer" ); + SetDefaultParameterInt( "valid.layer", 0 ); + + // Add class field if we used validation + AddParameter( ParameterType_ListView, "cfield", "Field containing the class id for supervision" ); + SetParameterDescription( "cfield", "Field containing the class id for supervision. " + "Only geometries with this field available will be taken into account." ); + SetListViewSingleSelectionMode( "cfield", true ); + + // Add a new parameter to compute confusion matrix / contingency table + AddParameter( ParameterType_OutputFilename, "io.confmatout", "Output confusion matrix or contingency table" ); + SetParameterDescription( "io.confmatout", "Output file containing the confusion matrix or contingency table (.csv format)." + "The contingency table is ouput when we unsupervised algorithms is used otherwise the confusion matrix is output." ); + MandatoryOff( "io.confmatout" ); + + + // Doc example parameter settings + SetDocExampleParameterValue( "io.vd", "vectorData.shp" ); + SetDocExampleParameterValue( "io.stats", "meanVar.xml" ); + SetDocExampleParameterValue( "io.out", "svmModel.svm" ); + SetDocExampleParameterValue( "feat", "perimeter area width" ); + SetDocExampleParameterValue( "cfield", "predicted" ); + + + // Add parameters for the classifier choice + Superclass::DoInit(); + + AddRANDParameter(); +} + +void TrainVectorBase::DoUpdateParameters() +{ + // if vector data is present and updated then reload fields + if( HasValue( "io.vd" ) ) + { + std::vector<std::string> vectorFileList = GetParameterStringList( "io.vd" ); + ogr::DataSource::Pointer ogrDS = ogr::DataSource::New( vectorFileList[0], ogr::DataSource::Modes::Read ); + ogr::Layer layer = ogrDS->GetLayer( static_cast<size_t>( this->GetParameterInt( "layer" ) ) ); + ogr::Feature feature = layer.ogr().GetNextFeature(); + + ClearChoices( "feat" ); + ClearChoices( "cfield" ); + + 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 == OFTInteger || ogr::version_proxy::IsOFTInteger64( fieldType ) || fieldType == OFTReal ) + { + std::string tmpKey = "feat." + key.substr( 0, static_cast<unsigned long>( end - key.begin() ) ); + AddChoice( tmpKey, item ); + } + if( fieldType == OFTString || fieldType == OFTInteger || ogr::version_proxy::IsOFTInteger64( fieldType ) ) + { + std::string tmpKey = "cfield." + key.substr( 0, static_cast<unsigned long>( end - key.begin() ) ); + AddChoice( tmpKey, item ); + } + } + } +} + +void TrainVectorBase::DoExecute() +{ + m_FeaturesInfo.SetFieldNames( GetChoiceNames( "feat" ), GetSelectedItems( "feat" )); + + // Check input parameters + if( m_FeaturesInfo.m_SelectedIdx.empty() ) + { + otbAppLogFATAL( << "No features have been selected to train the classifier on!" ); + } + + ShiftScaleParameters measurement = GetStatistics( m_FeaturesInfo.m_NbFeatures ); + ExtractAllSamples( measurement ); + + this->Train( m_TrainingSamplesWithLabel.listSample, m_TrainingSamplesWithLabel.labeledListSample, GetParameterString( "io.out" ) ); + + m_PredictedList = TargetListSampleType::New(); + this->Classify( m_ClassificationSamplesWithLabel.listSample, m_PredictedList, GetParameterString( "io.out" ) ); +} + + +void TrainVectorBase::ExtractAllSamples(const ShiftScaleParameters &measurement) +{ + m_TrainingSamplesWithLabel = ExtractTrainingSamplesWithLabel(measurement); + m_ClassificationSamplesWithLabel = ExtractClassificationSamplesWithLabel(measurement); +} + +TrainVectorBase::SamplesWithLabel +TrainVectorBase::ExtractTrainingSamplesWithLabel(const ShiftScaleParameters &measurement) +{ + return ExtractSamplesWithLabel( "io.vd", "layer", measurement); +} + +TrainVectorBase::SamplesWithLabel +TrainVectorBase::ExtractClassificationSamplesWithLabel(const ShiftScaleParameters &measurement) +{ + if(GetClassifierCategory() == Supervised) + { + SamplesWithLabel tmpSamplesWithLabel; + SamplesWithLabel validationSamplesWithLabel = ExtractSamplesWithLabel( "valid.vd", "valid.layer", measurement ); + //Test the input validation set size + if( validationSamplesWithLabel.labeledListSample->Size() != 0 ) + { + tmpSamplesWithLabel.listSample = validationSamplesWithLabel.listSample; + tmpSamplesWithLabel.labeledListSample = validationSamplesWithLabel.labeledListSample; + } + else + { + otbAppLogWARNING( + "The validation set is empty. The performance estimation is done using the input training set in this case." ); + tmpSamplesWithLabel.listSample = m_TrainingSamplesWithLabel.listSample; + tmpSamplesWithLabel.labeledListSample = m_TrainingSamplesWithLabel.labeledListSample; + } + + return tmpSamplesWithLabel; + } + else + { + return m_TrainingSamplesWithLabel; + } +} + + +TrainVectorBase::ShiftScaleParameters +TrainVectorBase::GetStatistics(unsigned int nbFeatures) +{ + ShiftScaleParameters measurement = ShiftScaleParameters(); + if( HasValue( "io.stats" ) && IsParameterEnabled( "io.stats" ) ) + { + StatisticsReader::Pointer statisticsReader = StatisticsReader::New(); + std::string XMLfile = GetParameterString( "io.stats" ); + statisticsReader->SetFileName( XMLfile.c_str() ); + measurement.meanMeasurementVector = statisticsReader->GetStatisticVectorByName( "mean" ); + measurement.stddevMeasurementVector = statisticsReader->GetStatisticVectorByName( "stddev" ); + } + else + { + measurement.meanMeasurementVector.SetSize( nbFeatures ); + measurement.meanMeasurementVector.Fill( 0. ); + measurement.stddevMeasurementVector.SetSize( nbFeatures ); + measurement.stddevMeasurementVector.Fill( 1. ); + } + return measurement; +} + + +TrainVectorBase::SamplesWithLabel +TrainVectorBase::ExtractSamplesWithLabel(std::string parameterName, std::string parameterLayer, + const ShiftScaleParameters &measurement) +{ + SamplesWithLabel samplesWithLabel; + if( HasValue( parameterName ) && IsParameterEnabled( parameterName ) ) + { + ListSampleType::Pointer input = ListSampleType::New(); + TargetListSampleType::Pointer target = TargetListSampleType::New(); + input->SetMeasurementVectorSize( m_FeaturesInfo.m_NbFeatures ); + + std::vector<std::string> fileList = this->GetParameterStringList( parameterName ); + for( unsigned int k = 0; k < fileList.size(); k++ ) + { + otbAppLogINFO( "Reading vector file " << k + 1 << "/" << fileList.size() ); + ogr::DataSource::Pointer source = ogr::DataSource::New( fileList[k], ogr::DataSource::Modes::Read ); + ogr::Layer layer = source->GetLayer( static_cast<size_t>(this->GetParameterInt( parameterLayer )) ); + ogr::Feature feature = layer.ogr().GetNextFeature(); + bool goesOn = feature.addr() != 0; + if( !goesOn ) + { + otbAppLogWARNING( "The layer " << GetParameterInt( parameterLayer ) << " of " << fileList[k] + << " is empty, input is skipped." ); + continue; + } + + // Check all needed fields are present : + // - check class field if we use supervised classification or if class field name is not empty + int cFieldIndex = feature.ogr().GetFieldIndex( m_FeaturesInfo.m_SelectedCFieldName.c_str() ); + if( cFieldIndex < 0 && !m_FeaturesInfo.m_SelectedCFieldName.empty()) + { + otbAppLogFATAL( "The field name for class label (" << m_FeaturesInfo.m_SelectedCFieldName + << ") has not been found in the vector file " + << fileList[k] ); + } + + // - check feature fields + std::vector<int> featureFieldIndex( m_FeaturesInfo.m_NbFeatures, -1 ); + for( unsigned int i = 0; i < m_FeaturesInfo.m_NbFeatures; i++ ) + { + featureFieldIndex[i] = feature.ogr().GetFieldIndex( m_FeaturesInfo.m_SelectedNames[i].c_str() ); + if( featureFieldIndex[i] < 0 ) + otbAppLogFATAL( "The field name for feature " << m_FeaturesInfo.m_SelectedNames[i] + << " has not been found in the vector file " + << fileList[k] ); + } + + + while( goesOn ) + { + // Retrieve all the features for each field in the ogr layer. + MeasurementType mv; + mv.SetSize( m_FeaturesInfo.m_NbFeatures ); + for( unsigned int idx = 0; idx < m_FeaturesInfo.m_NbFeatures; ++idx ) + mv[idx] = feature.ogr().GetFieldAsDouble( featureFieldIndex[idx] ); + + input->PushBack( mv ); + + if( feature.ogr().IsFieldSet( cFieldIndex ) && cFieldIndex != -1 ) + target->PushBack( feature.ogr().GetFieldAsInteger( cFieldIndex ) ); + else + target->PushBack( 0 ); + + feature = layer.ogr().GetNextFeature(); + goesOn = feature.addr() != 0; + } + } + + + + ShiftScaleFilterType::Pointer shiftScaleFilter = ShiftScaleFilterType::New(); + shiftScaleFilter->SetInput( input ); + shiftScaleFilter->SetShifts( measurement.meanMeasurementVector ); + shiftScaleFilter->SetScales( measurement.stddevMeasurementVector ); + shiftScaleFilter->Update(); + + samplesWithLabel.listSample = shiftScaleFilter->GetOutput(); + samplesWithLabel.labeledListSample = target; + samplesWithLabel.listSample->DisconnectPipeline(); + } + + return samplesWithLabel; +} + + +} +} + +#endif diff --git a/Modules/Applications/AppClassification/otb-module.cmake b/Modules/Applications/AppClassification/otb-module.cmake index 07b121f77de3512038be604d8f9e67f9ffa0985e..ca0c9281275d233b7dcb441d667fb295d5580755 100644 --- a/Modules/Applications/AppClassification/otb-module.cmake +++ b/Modules/Applications/AppClassification/otb-module.cmake @@ -31,7 +31,9 @@ otb_module(OTBAppClassification OTBMajorityVoting OTBVectorDataIO OTBSOM + OTBLearningBase OTBSupervised + OTBUnsupervised OTBApplicationEngine OTBIndices OTBMathParser diff --git a/Modules/Applications/AppClassification/test/CMakeLists.txt b/Modules/Applications/AppClassification/test/CMakeLists.txt index 3a340346d8e549420ba3904edbfe9b99377dee12..3b4e213470625f57238c635383b4bacf22e93e7c 100644 --- a/Modules/Applications/AppClassification/test/CMakeLists.txt +++ b/Modules/Applications/AppClassification/test/CMakeLists.txt @@ -21,46 +21,46 @@ otb_module_test() #----------- ComputeOGRLayersFeaturesStatistics TESTS ---------------- otb_test_application(NAME apTvClComputeOGRLayersFeaturesStatistics - APP ComputeOGRLayersFeaturesStatistics - OPTIONS -inshp ${INPUTDATA}/Classification/apTvClLabeledVector.shp - -feat meanB0 meanB1 meanB2 meanB3 varB0 varB1 varB2 varB3 - -outstats ${TEMP}/apTvClComputeOGRLayersFeaturesStatistics.xml - VALID --compare-ascii ${NOTOL} - ${OTBAPP_BASELINE_FILES}/apTvClComputeOGRLayersFeaturesStatistics.xml - ${TEMP}/apTvClComputeOGRLayersFeaturesStatistics.xml) + APP ComputeOGRLayersFeaturesStatistics + OPTIONS -inshp ${INPUTDATA}/Classification/apTvClLabeledVector.shp + -feat meanB0 meanB1 meanB2 meanB3 varB0 varB1 varB2 varB3 + -outstats ${TEMP}/apTvClComputeOGRLayersFeaturesStatistics.xml + VALID --compare-ascii ${NOTOL} + ${OTBAPP_BASELINE_FILES}/apTvClComputeOGRLayersFeaturesStatistics.xml + ${TEMP}/apTvClComputeOGRLayersFeaturesStatistics.xml) #----------- SOMClassification TESTS ---------------- otb_test_application(NAME apTvClSOMClassificationSmall - APP SOMClassification - OPTIONS -in ${INPUTDATA}/poupees_sub.png - -rand 121212 - -out ${TEMP}/apTvClSOMClassificationSmall.tif uint16 - VALID --compare-image ${NOTOL} - ${BASELINE}/apTvClSOMClassificationSmall.tif - ${TEMP}/apTvClSOMClassificationSmall.tif) + APP SOMClassification + OPTIONS -in ${INPUTDATA}/poupees_sub.png + -rand 121212 + -out ${TEMP}/apTvClSOMClassificationSmall.tif uint16 + VALID --compare-image ${NOTOL} + ${BASELINE}/apTvClSOMClassificationSmall.tif + ${TEMP}/apTvClSOMClassificationSmall.tif) otb_test_application(NAME apTvClSOMClassificationFull - APP SOMClassification - OPTIONS -in ${INPUTDATA}/poupees_sub.png - -out ${TEMP}/apTvClSOMClassificationFull.tif uint16 - -vm ${INPUTDATA}/poupees_sub_c1.png - -tp 0.8 - -ts 13000 - -som ${TEMP}/apTvClSOMClassificationMap.hdr - -sx 30 - -sy 30 - -nx 9 - -ny 9 - -ni 5 - -bi 1.0 - -bf 0.1 - -iv 0 - -rand 121212 - VALID --compare-n-images ${NOTOL} 2 - ${BASELINE}/apTvClSOMClassificationFull.tif - ${TEMP}/apTvClSOMClassificationFull.tif - ${BASELINE}/apTvClSOMClassificationMap.hdr - ${TEMP}/apTvClSOMClassificationMap.hdr) + APP SOMClassification + OPTIONS -in ${INPUTDATA}/poupees_sub.png + -out ${TEMP}/apTvClSOMClassificationFull.tif uint16 + -vm ${INPUTDATA}/poupees_sub_c1.png + -tp 0.8 + -ts 13000 + -som ${TEMP}/apTvClSOMClassificationMap.hdr + -sx 30 + -sy 30 + -nx 9 + -ny 9 + -ni 5 + -bi 1.0 + -bf 0.1 + -iv 0 + -rand 121212 + VALID --compare-n-images ${NOTOL} 2 + ${BASELINE}/apTvClSOMClassificationFull.tif + ${TEMP}/apTvClSOMClassificationFull.tif + ${BASELINE}/apTvClSOMClassificationMap.hdr + ${TEMP}/apTvClSOMClassificationMap.hdr) #----------- ImageClassifier TESTS ---------------- @@ -96,6 +96,7 @@ set(bayes_output_format ".bayes") set(rf_output_format ".rf") set(knn_output_format ".knn") set(sharkrf_output_format ".txt") +set(sharkkm_output_format ".txt") # Training algorithms parameters set(libsvm_parameters "-classifier.libsvm.opt" "true" "-classifier.libsvm.prob" "true") @@ -108,6 +109,7 @@ set(bayes_parameters "") set(rf_parameters "") set(knn_parameters "") set(sharkrf_parameters "") +set(sharkkm_parameters "") # Validation depending on mode set(ascii_comparison --compare-ascii ${EPSILON_6}) @@ -120,7 +122,7 @@ set(raster_ref_path ${OTBAPP_BASELINE}) set(classifierList) #if(OTB_USE_LIBSVM) - #list(APPEND classifierList "LIBSVM") +#list(APPEND classifierList "LIBSVM") #endif() if(OTB_USE_OPENCV) #list(APPEND classifierList "SVM" "BOOST" "DT" "GBT" "ANN" "BAYES" "RF" "KNN") @@ -130,14 +132,14 @@ if(OTB_USE_OPENCV) endif() endif() if(OTB_USE_SHARK) - list(APPEND classifierList "SHARKRF") + list(APPEND classifierList "SHARKRF" "SHARKKM") endif() set(classifier_with_confmap "LIBSVM" "BOOST" "KNN" "ANN" "RF") # This is a black list for classifier that can not have a baseline # because they are using randomness and seed can not be set -set(classifier_without_baseline "SHARKRF") +set(classifier_without_baseline "SHARKRF" "SHARKKM") # Loop on classifiers foreach(classifier ${classifierList}) @@ -154,21 +156,21 @@ foreach(classifier ${classifierList}) else() set(valid "") endif() - + otb_test_application( - NAME apTvClTrainMethod${classifier}ImagesClassifierQB1 - APP TrainImagesClassifier - OPTIONS -io.il ${INPUTDATA}/Classification/QB_1_ortho${raster_input_format} - -io.vd ${INPUTDATA}/Classification/VectorData_${${lclassifier}_input}QB1${vector_input_format} - -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1${stat_input_format} - -classifier ${lclassifier} - ${${lclassifier}_parameters} - -io.out ${TEMP}/${OUTMODELFILE} - -sample.vfn Class - -rand 121212 - - VALID ${valid} - ) + NAME apTvClTrainMethod${classifier}ImagesClassifierQB1 + APP TrainImagesClassifier + OPTIONS -io.il ${INPUTDATA}/Classification/QB_1_ortho${raster_input_format} + -io.vd ${INPUTDATA}/Classification/VectorData_${${lclassifier}_input}QB1${vector_input_format} + -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1${stat_input_format} + -classifier ${lclassifier} + ${${lclassifier}_parameters} + -io.out ${TEMP}/${OUTMODELFILE} + -sample.vfn Class + -rand 121212 + + VALID ${valid} + ) if(${_classifier_has_baseline} EQUAL -1) set(valid ${ascii_comparison} ${ascii_ref_path}/${OUTMODELFILE} ${TEMP}/OutXML1_${OUTMODELFILE}) @@ -177,20 +179,20 @@ foreach(classifier ${classifierList}) endif() otb_test_application( - NAME apTvClTrainMethod${classifier}ImagesClassifierQB1_OutXML1 - APP TrainImagesClassifier - OPTIONS -io.il ${INPUTDATA}/Classification/QB_1_ortho${raster_input_format} - -io.vd ${INPUTDATA}/Classification/VectorData_${${lclassifier}_input}QB1${vector_input_format} - -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1${stat_input_format} - -classifier ${lclassifier} - ${${lclassifier}_parameters} - -io.out ${TEMP}/OutXML1_${OUTMODELFILE} - -rand 121212 - -sample.vfn Class - -outxml ${TEMP}/cl${classifier}_OutXML1.xml - - VALID ${valid} - ) + NAME apTvClTrainMethod${classifier}ImagesClassifierQB1_OutXML1 + APP TrainImagesClassifier + OPTIONS -io.il ${INPUTDATA}/Classification/QB_1_ortho${raster_input_format} + -io.vd ${INPUTDATA}/Classification/VectorData_${${lclassifier}_input}QB1${vector_input_format} + -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1${stat_input_format} + -classifier ${lclassifier} + ${${lclassifier}_parameters} + -io.out ${TEMP}/OutXML1_${OUTMODELFILE} + -rand 121212 + -sample.vfn Class + -outxml ${TEMP}/cl${classifier}_OutXML1.xml + + VALID ${valid} + ) if(${_classifier_has_baseline} EQUAL -1) set(valid ${ascii_comparison} ${ascii_ref_path}/${OUTMODELFILE} ${TEMP}/OutXML2_${OUTMODELFILE}) @@ -199,744 +201,746 @@ foreach(classifier ${classifierList}) endif() otb_test_application( - NAME apTvClTrainMethod${classifier}ImagesClassifierQB1_InXML1 - APP TrainImagesClassifier - OPTIONS -inxml ${INPUTDATA}/cl${classifier}_OutXML1.xml - -io.il ${INPUTDATA}/Classification/QB_1_ortho${raster_input_format} - -io.vd ${INPUTDATA}/Classification/VectorData_${${lclassifier}_input}QB1${vector_input_format} - -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1${stat_input_format} - -io.out ${TEMP}/OutXML2_${OUTMODELFILE} - -sample.vfn Class - VALID ${valid} - ) - - #set_tests_properties(apTvClTrainMethod${classifier}ImagesClassifierQB1_InXML1 PROPERTIES DEPENDS apTvClTrainMethod${classifier}ImagesClassifierQB1_OutXML1) + NAME apTvClTrainMethod${classifier}ImagesClassifierQB1_InXML1 + APP TrainImagesClassifier + OPTIONS -inxml ${INPUTDATA}/cl${classifier}_OutXML1.xml + -io.il ${INPUTDATA}/Classification/QB_1_ortho${raster_input_format} + -io.vd ${INPUTDATA}/Classification/VectorData_${${lclassifier}_input}QB1${vector_input_format} + -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1${stat_input_format} + -io.out ${TEMP}/OutXML2_${OUTMODELFILE} + -sample.vfn Class + VALID ${valid} + ) + + #set_tests_properties(apTvClTrainMethod${classifier}ImagesClassifierQB1_InXML1 PROPERTIES DEPENDS apTvClTrainMethod${classifier}ImagesClassifierQB1_OutXML1) list(FIND classifier_with_confmap ${classifier} _classifier_has_confmap) if(${_classifier_has_confmap} EQUAL -1) otb_test_application( - NAME apTvClMethod${classifier}ImageClassifierQB1 - APP ImageClassifier - OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho${raster_input_format} - -model ${INPUTDATA}/Classification/${OUTMODELFILE} - -imstat ${INPUTDATA}/Classification/clImageStatisticsQB1${stat_input_format} - -out ${TEMP}/${OUTRASTER} ${raster_output_option} - - VALID ${raster_comparison} - ${raster_ref_path}/${OUTRASTER} - ${TEMP}/${OUTRASTER} - ) + NAME apTvClMethod${classifier}ImageClassifierQB1 + APP ImageClassifier + OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho${raster_input_format} + -model ${INPUTDATA}/Classification/${OUTMODELFILE} + -imstat ${INPUTDATA}/Classification/clImageStatisticsQB1${stat_input_format} + -out ${TEMP}/${OUTRASTER} ${raster_output_option} + + VALID ${raster_comparison} + ${raster_ref_path}/${OUTRASTER} + ${TEMP}/${OUTRASTER} + ) else() otb_test_application( - NAME apTvClMethod${classifier}ImageClassifierQB1 - APP ImageClassifier - OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho${raster_input_format} - -model ${INPUTDATA}/Classification/${OUTMODELFILE} - -imstat ${INPUTDATA}/Classification/clImageStatisticsQB1${stat_input_format} - -out ${TEMP}/${OUTRASTER} ${raster_output_option} - -confmap ${TEMP}/${OUTCONFMAP} - - VALID ${raster_comparison_two} - ${raster_ref_path}/${OUTRASTER} - ${TEMP}/${OUTRASTER} - ${raster_ref_path}/${OUTCONFMAP} - ${TEMP}/${OUTCONFMAP} - ) + NAME apTvClMethod${classifier}ImageClassifierQB1 + APP ImageClassifier + OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho${raster_input_format} + -model ${INPUTDATA}/Classification/${OUTMODELFILE} + -imstat ${INPUTDATA}/Classification/clImageStatisticsQB1${stat_input_format} + -out ${TEMP}/${OUTRASTER} ${raster_output_option} + -confmap ${TEMP}/${OUTCONFMAP} + + VALID ${raster_comparison_two} + ${raster_ref_path}/${OUTRASTER} + ${TEMP}/${OUTRASTER} + ${raster_ref_path}/${OUTCONFMAP} + ${TEMP}/${OUTCONFMAP} + ) endif() endforeach() +#----------- LIBSVM Classifier TESTS ---------------- + if(OTB_USE_LIBSVM) otb_test_application(NAME apTvClImageSVMClassifierQB2 - APP ImageClassifier - OPTIONS -in ${INPUTDATA}/Classification/QB_2_ortho.tif - -imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml - -model ${INPUTDATA}/Classification/clsvmModelQB1.svm - -out ${TEMP}/clLabeledImageQB2.tif - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/clLabeledImageQB2.tif - ${TEMP}/clLabeledImageQB2.tif) + APP ImageClassifier + OPTIONS -in ${INPUTDATA}/Classification/QB_2_ortho.tif + -imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml + -model ${INPUTDATA}/Classification/clsvmModelQB1.svm + -out ${TEMP}/clLabeledImageQB2.tif + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/clLabeledImageQB2.tif + ${TEMP}/clLabeledImageQB2.tif) otb_test_application(NAME apTvClImageSVMClassifierQB3 - APP ImageClassifier - OPTIONS -in ${INPUTDATA}/Classification/QB_3_ortho.tif - -imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml - -model ${INPUTDATA}/Classification/clsvmModelQB1.svm - -out ${TEMP}/clLabeledImageQB3.tif - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/clLabeledImageQB3.tif - ${TEMP}/clLabeledImageQB3.tif) + APP ImageClassifier + OPTIONS -in ${INPUTDATA}/Classification/QB_3_ortho.tif + -imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml + -model ${INPUTDATA}/Classification/clsvmModelQB1.svm + -out ${TEMP}/clLabeledImageQB3.tif + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/clLabeledImageQB3.tif + ${TEMP}/clLabeledImageQB3.tif) otb_test_application(NAME apTvClImageSVMClassifierQB1 - APP ImageClassifier - OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho.tif - -imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml - -model ${INPUTDATA}/Classification/clsvmModelQB1.svm - -out ${TEMP}/clLabeledImageQB1.tif - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/clLabeledImageQB1.tif - ${TEMP}/clLabeledImageQB1.tif) + APP ImageClassifier + OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho.tif + -imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml + -model ${INPUTDATA}/Classification/clsvmModelQB1.svm + -out ${TEMP}/clLabeledImageQB1.tif + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/clLabeledImageQB1.tif + ${TEMP}/clLabeledImageQB1.tif) otb_test_application(NAME apTvClImageSVMClassifierQB456_6 - APP ImageClassifier - OPTIONS -in ${INPUTDATA}/Classification/QB_6_extract.tif - -mask ${INPUTDATA}/Classification/QB_6_mask.tif - -imstat ${INPUTDATA}/Classification/clImageStatisticsQB456.xml - -model ${INPUTDATA}/Classification/clsvmModelQB456.svm - -out ${TEMP}/clLabeledImageQB456_6.tif - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/clLabeledImageQB456_6.tif - ${TEMP}/clLabeledImageQB456_6.tif) + APP ImageClassifier + OPTIONS -in ${INPUTDATA}/Classification/QB_6_extract.tif + -mask ${INPUTDATA}/Classification/QB_6_mask.tif + -imstat ${INPUTDATA}/Classification/clImageStatisticsQB456.xml + -model ${INPUTDATA}/Classification/clsvmModelQB456.svm + -out ${TEMP}/clLabeledImageQB456_6.tif + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/clLabeledImageQB456_6.tif + ${TEMP}/clLabeledImageQB456_6.tif) otb_test_application(NAME apTvClImageSVMClassifierQB456_4 - APP ImageClassifier - OPTIONS -in ${INPUTDATA}/Classification/QB_4_extract.tif - -imstat ${INPUTDATA}/Classification/clImageStatisticsQB456.xml - -model ${INPUTDATA}/Classification/clsvmModelQB456.svm - -out ${TEMP}/clLabeledImageQB456_4.tif - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/clLabeledImageQB456_4.tif - ${TEMP}/clLabeledImageQB456_4.tif) + APP ImageClassifier + OPTIONS -in ${INPUTDATA}/Classification/QB_4_extract.tif + -imstat ${INPUTDATA}/Classification/clImageStatisticsQB456.xml + -model ${INPUTDATA}/Classification/clsvmModelQB456.svm + -out ${TEMP}/clLabeledImageQB456_4.tif + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/clLabeledImageQB456_4.tif + ${TEMP}/clLabeledImageQB456_4.tif) otb_test_application(NAME apTvClImageSVMClassifierQB456_5 - APP ImageClassifier - OPTIONS -in ${INPUTDATA}/Classification/QB_5_extract.tif - -imstat ${INPUTDATA}/Classification/clImageStatisticsQB456.xml - -model ${INPUTDATA}/Classification/clsvmModelQB456.svm - -out ${TEMP}/clLabeledImageQB456_5.tif - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/clLabeledImageQB456_5.tif - ${TEMP}/clLabeledImageQB456_5.tif) + APP ImageClassifier + OPTIONS -in ${INPUTDATA}/Classification/QB_5_extract.tif + -imstat ${INPUTDATA}/Classification/clImageStatisticsQB456.xml + -model ${INPUTDATA}/Classification/clsvmModelQB456.svm + -out ${TEMP}/clLabeledImageQB456_5.tif + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/clLabeledImageQB456_5.tif + ${TEMP}/clLabeledImageQB456_5.tif) otb_test_application(NAME apTvClImageSVMClassifierQB123_6 - APP ImageClassifier - OPTIONS -in ${INPUTDATA}/Classification/QB_6_extract.tif - -imstat ${INPUTDATA}/Classification/clImageStatisticsQB123.xml - -model ${INPUTDATA}/Classification/clsvmModelQB123.svm - -out ${TEMP}/clLabeledImageQB123_6.tif - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/clLabeledImageQB123_6.tif - ${TEMP}/clLabeledImageQB123_6.tif) + APP ImageClassifier + OPTIONS -in ${INPUTDATA}/Classification/QB_6_extract.tif + -imstat ${INPUTDATA}/Classification/clImageStatisticsQB123.xml + -model ${INPUTDATA}/Classification/clsvmModelQB123.svm + -out ${TEMP}/clLabeledImageQB123_6.tif + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/clLabeledImageQB123_6.tif + ${TEMP}/clLabeledImageQB123_6.tif) otb_test_application(NAME apTvClImageSVMClassifierQB456_1 - APP ImageClassifier - OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho.tif - -imstat ${INPUTDATA}/Classification/clImageStatisticsQB456.xml - -model ${INPUTDATA}/Classification/clsvmModelQB456.svm - -out ${TEMP}/clLabeledImageQB456_1.tif - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/clLabeledImageQB456_1.tif - ${TEMP}/clLabeledImageQB456_1.tif) + APP ImageClassifier + OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho.tif + -imstat ${INPUTDATA}/Classification/clImageStatisticsQB456.xml + -model ${INPUTDATA}/Classification/clsvmModelQB456.svm + -out ${TEMP}/clLabeledImageQB456_1.tif + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/clLabeledImageQB456_1.tif + ${TEMP}/clLabeledImageQB456_1.tif) otb_test_application(NAME apTvClImageSVMClassifierQB123_3 - APP ImageClassifier - OPTIONS -in ${INPUTDATA}/Classification/QB_3_ortho.tif - -imstat ${INPUTDATA}/Classification/clImageStatisticsQB123.xml - -model ${INPUTDATA}/Classification/clsvmModelQB123.svm - -out ${TEMP}/clLabeledImageQB123_3.tif - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/clLabeledImageQB123_3.tif - ${TEMP}/clLabeledImageQB123_3.tif) + APP ImageClassifier + OPTIONS -in ${INPUTDATA}/Classification/QB_3_ortho.tif + -imstat ${INPUTDATA}/Classification/clImageStatisticsQB123.xml + -model ${INPUTDATA}/Classification/clsvmModelQB123.svm + -out ${TEMP}/clLabeledImageQB123_3.tif + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/clLabeledImageQB123_3.tif + ${TEMP}/clLabeledImageQB123_3.tif) otb_test_application(NAME apTvClImageSVMClassifierQB123_2 - APP ImageClassifier - OPTIONS -in ${INPUTDATA}/Classification/QB_2_ortho.tif - -imstat ${INPUTDATA}/Classification/clImageStatisticsQB123.xml - -model ${INPUTDATA}/Classification/clsvmModelQB123.svm - -out ${TEMP}/clLabeledImageQB123_2.tif - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/clLabeledImageQB123_2.tif - ${TEMP}/clLabeledImageQB123_2.tif) + APP ImageClassifier + OPTIONS -in ${INPUTDATA}/Classification/QB_2_ortho.tif + -imstat ${INPUTDATA}/Classification/clImageStatisticsQB123.xml + -model ${INPUTDATA}/Classification/clsvmModelQB123.svm + -out ${TEMP}/clLabeledImageQB123_2.tif + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/clLabeledImageQB123_2.tif + ${TEMP}/clLabeledImageQB123_2.tif) otb_test_application(NAME apTvClImageSVMClassifierQB123_1 - APP ImageClassifier - OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho.tif - -imstat ${INPUTDATA}/Classification/clImageStatisticsQB123.xml - -model ${INPUTDATA}/Classification/clsvmModelQB123.svm - -out ${TEMP}/clLabeledImageQB123_1.tif - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/clLabeledImageQB123_1.tif - ${TEMP}/clLabeledImageQB123_1.tif) + APP ImageClassifier + OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho.tif + -imstat ${INPUTDATA}/Classification/clImageStatisticsQB123.xml + -model ${INPUTDATA}/Classification/clsvmModelQB123.svm + -out ${TEMP}/clLabeledImageQB123_1.tif + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/clLabeledImageQB123_1.tif + ${TEMP}/clLabeledImageQB123_1.tif) endif() #----------- TrainOGRLayersClassifier TESTS ---------------- otb_test_application(NAME apTvClTrainOGRLayersClassifier - APP TrainOGRLayersClassifier - OPTIONS -inshp ${INPUTDATA}/Classification/apTvClLabeledVector.shp - -feat meanB0 meanB1 meanB2 meanB3 varB0 varB1 varB2 varB3 - -instats ${TEMP}/apTvClComputeOGRLayersFeaturesStatistics.xml - -outsvm ${TEMP}/apTvClModel.svm - VALID --compare-ascii ${NOTOL} - ${OTBAPP_BASELINE_FILES}/apTvClModel.svm - ${TEMP}/apTvClModel.svm) + APP TrainOGRLayersClassifier + OPTIONS -inshp ${INPUTDATA}/Classification/apTvClLabeledVector.shp + -feat meanB0 meanB1 meanB2 meanB3 varB0 varB1 varB2 varB3 + -instats ${TEMP}/apTvClComputeOGRLayersFeaturesStatistics.xml + -outsvm ${TEMP}/apTvClModel.svm + VALID --compare-ascii ${NOTOL} + ${OTBAPP_BASELINE_FILES}/apTvClModel.svm + ${TEMP}/apTvClModel.svm) set_tests_properties(apTvClTrainOGRLayersClassifier PROPERTIES DEPENDS apTvClComputeOGRLayersFeaturesStatistics) #----------- ComputeConfusionMatrix TESTS ---------------- otb_test_application(NAME apTvComputeConfusionMatrixV - APP ComputeConfusionMatrix - OPTIONS -in ${OTBAPP_BASELINE}/clLabeledImageQB123_1.tif - -ref vector - -ref.vector.in ${INPUTDATA}/Classification/VectorData_QB1_ter.shp - -ref.vector.field Class - -out ${TEMP}/apTvComputeConfusionMatrixTconfusionVOut.csv - VALID --compare-ascii ${NOTOL} - ${OTBAPP_BASELINE_FILES}/apTvComputeConfusionMatrixTconfusionVOut.csv - ${TEMP}/apTvComputeConfusionMatrixTconfusionVOut.csv) + APP ComputeConfusionMatrix + OPTIONS -in ${OTBAPP_BASELINE}/clLabeledImageQB123_1.tif + -ref vector + -ref.vector.in ${INPUTDATA}/Classification/VectorData_QB1_ter.shp + -ref.vector.field Class + -out ${TEMP}/apTvComputeConfusionMatrixTconfusionVOut.csv + VALID --compare-ascii ${NOTOL} + ${OTBAPP_BASELINE_FILES}/apTvComputeConfusionMatrixTconfusionVOut.csv + ${TEMP}/apTvComputeConfusionMatrixTconfusionVOut.csv) otb_test_application(NAME apTvComputeConfusionMatrixExtraReferenceLabelsV - APP ComputeConfusionMatrix - OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho_C7.tif - -ref vector - -ref.vector.in ${INPUTDATA}/Classification/VectorData_QB1_ter.shp - -ref.vector.field Class - -out ${TEMP}/apTvComputeConfusionMatrixExtraRefLabelsVOut.csv - VALID --compare-ascii ${NOTOL} - ${OTBAPP_BASELINE_FILES}/apTvComputeConfusionMatrixExtraRefLabelsVOut.csv - ${TEMP}/apTvComputeConfusionMatrixExtraRefLabelsVOut.csv) + APP ComputeConfusionMatrix + OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho_C7.tif + -ref vector + -ref.vector.in ${INPUTDATA}/Classification/VectorData_QB1_ter.shp + -ref.vector.field Class + -out ${TEMP}/apTvComputeConfusionMatrixExtraRefLabelsVOut.csv + VALID --compare-ascii ${NOTOL} + ${OTBAPP_BASELINE_FILES}/apTvComputeConfusionMatrixExtraRefLabelsVOut.csv + ${TEMP}/apTvComputeConfusionMatrixExtraRefLabelsVOut.csv) otb_test_application(NAME apTvComputeConfusionMatrixExtraReferenceLabelsR - APP ComputeConfusionMatrix - OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho_C7.tif - -ref raster - -ref.raster.in ${INPUTDATA}/Classification/clLabeledImageQB456_1_NoData_255.tif - -nodatalabel 255 - -out ${TEMP}/apTvComputeConfusionMatrixExtraRefLabelsROut.csv - VALID --compare-ascii ${NOTOL} - ${OTBAPP_BASELINE_FILES}/apTvComputeConfusionMatrixExtraRefLabelsROut.csv - ${TEMP}/apTvComputeConfusionMatrixExtraRefLabelsROut.csv) + APP ComputeConfusionMatrix + OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho_C7.tif + -ref raster + -ref.raster.in ${INPUTDATA}/Classification/clLabeledImageQB456_1_NoData_255.tif + -nodatalabel 255 + -out ${TEMP}/apTvComputeConfusionMatrixExtraRefLabelsROut.csv + VALID --compare-ascii ${NOTOL} + ${OTBAPP_BASELINE_FILES}/apTvComputeConfusionMatrixExtraRefLabelsROut.csv + ${TEMP}/apTvComputeConfusionMatrixExtraRefLabelsROut.csv) otb_test_application(NAME apTvComputeConfusionMatrixR - APP ComputeConfusionMatrix - OPTIONS -in ${OTBAPP_BASELINE}/clLabeledImageQB123_1.tif - -ref raster - -ref.raster.in ${INPUTDATA}/Classification/clLabeledImageQB456_1_NoData_255.tif - -nodatalabel 255 - -out ${TEMP}/apTvComputeConfusionMatrixTconfusionROut.csv - VALID --compare-ascii ${NOTOL} - ${OTBAPP_BASELINE_FILES}/apTvComputeConfusionMatrixTconfusionROut.csv - ${TEMP}/apTvComputeConfusionMatrixTconfusionROut.csv) + APP ComputeConfusionMatrix + OPTIONS -in ${OTBAPP_BASELINE}/clLabeledImageQB123_1.tif + -ref raster + -ref.raster.in ${INPUTDATA}/Classification/clLabeledImageQB456_1_NoData_255.tif + -nodatalabel 255 + -out ${TEMP}/apTvComputeConfusionMatrixTconfusionROut.csv + VALID --compare-ascii ${NOTOL} + ${OTBAPP_BASELINE_FILES}/apTvComputeConfusionMatrixTconfusionROut.csv + ${TEMP}/apTvComputeConfusionMatrixTconfusionROut.csv) otb_test_application(NAME apTvComputeConfusionMatrixExtraProducedLabelsR - APP ComputeConfusionMatrix - OPTIONS -in ${INPUTDATA}/Classification/clLabeledImageQB456_1_NoData_255.tif - -ref raster - -ref.raster.in ${INPUTDATA}/Classification/QB_1_ortho_C8.tif - -nodatalabel 255 - -out ${TEMP}/apTvComputeConfusionMatrixExtraProdLabelsROut.csv - VALID --compare-ascii ${NOTOL} - ${OTBAPP_BASELINE_FILES}/apTvComputeConfusionMatrixExtraProdLabelsROut.csv - ${TEMP}/apTvComputeConfusionMatrixExtraProdLabelsROut.csv) + APP ComputeConfusionMatrix + OPTIONS -in ${INPUTDATA}/Classification/clLabeledImageQB456_1_NoData_255.tif + -ref raster + -ref.raster.in ${INPUTDATA}/Classification/QB_1_ortho_C8.tif + -nodatalabel 255 + -out ${TEMP}/apTvComputeConfusionMatrixExtraProdLabelsROut.csv + VALID --compare-ascii ${NOTOL} + ${OTBAPP_BASELINE_FILES}/apTvComputeConfusionMatrixExtraProdLabelsROut.csv + ${TEMP}/apTvComputeConfusionMatrixExtraProdLabelsROut.csv) #----------- FusionOfClassifications TESTS ---------------- otb_test_application(NAME apTvFusionOfClassificationsDSPrecision6Inputs - APP FusionOfClassifications - OPTIONS -il ${INPUTDATA}/Classification/QB_1_ortho_C1.tif - ${INPUTDATA}/Classification/QB_1_ortho_C2.tif - ${INPUTDATA}/Classification/QB_1_ortho_C3.tif - ${INPUTDATA}/Classification/QB_1_ortho_C4.tif - ${INPUTDATA}/Classification/QB_1_ortho_C5.tif - ${INPUTDATA}/Classification/QB_1_ortho_C6.tif - -method dempstershafer - -method.dempstershafer.cmfl ${INPUTDATA}/Classification/QB_1_ortho_C1.csv - ${INPUTDATA}/Classification/QB_1_ortho_C2.csv - ${INPUTDATA}/Classification/QB_1_ortho_C3.csv - ${INPUTDATA}/Classification/QB_1_ortho_C4.csv - ${INPUTDATA}/Classification/QB_1_ortho_C5.csv - ${INPUTDATA}/Classification/QB_1_ortho_C6.csv - -method.dempstershafer.mob precision - -nodatalabel 10 - -undecidedlabel 7 - -out ${TEMP}/apTvFusionOfClassificationsDS6InputsPrecisionOutput.tif uint8 - VALID --compare-image ${NOTOL} - ${BASELINE}/QB_1_ortho_DS_FUSED_PRECISION.tif - ${TEMP}/apTvFusionOfClassificationsDS6InputsPrecisionOutput.tif) + APP FusionOfClassifications + OPTIONS -il ${INPUTDATA}/Classification/QB_1_ortho_C1.tif + ${INPUTDATA}/Classification/QB_1_ortho_C2.tif + ${INPUTDATA}/Classification/QB_1_ortho_C3.tif + ${INPUTDATA}/Classification/QB_1_ortho_C4.tif + ${INPUTDATA}/Classification/QB_1_ortho_C5.tif + ${INPUTDATA}/Classification/QB_1_ortho_C6.tif + -method dempstershafer + -method.dempstershafer.cmfl ${INPUTDATA}/Classification/QB_1_ortho_C1.csv + ${INPUTDATA}/Classification/QB_1_ortho_C2.csv + ${INPUTDATA}/Classification/QB_1_ortho_C3.csv + ${INPUTDATA}/Classification/QB_1_ortho_C4.csv + ${INPUTDATA}/Classification/QB_1_ortho_C5.csv + ${INPUTDATA}/Classification/QB_1_ortho_C6.csv + -method.dempstershafer.mob precision + -nodatalabel 10 + -undecidedlabel 7 + -out ${TEMP}/apTvFusionOfClassificationsDS6InputsPrecisionOutput.tif uint8 + VALID --compare-image ${NOTOL} + ${BASELINE}/QB_1_ortho_DS_FUSED_PRECISION.tif + ${TEMP}/apTvFusionOfClassificationsDS6InputsPrecisionOutput.tif) otb_test_application(NAME apTvFusionOfClassificationsMV3Inputs - APP FusionOfClassifications - OPTIONS -il ${INPUTDATA}/Classification/clLabeledImageQB123_1.tif - ${INPUTDATA}/Classification/clLabeledImageQB456_1.tif - ${INPUTDATA}/Classification/clLabeledImageQB1.tif - -method majorityvoting - -undecidedlabel 100 - -out ${TEMP}/apTvFusionOfClassificationsMV3InputsOutput.tif uint16 - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/apTvFusionOfClassifications3InputsOutput.tif - ${TEMP}/apTvFusionOfClassificationsMV3InputsOutput.tif) + APP FusionOfClassifications + OPTIONS -il ${INPUTDATA}/Classification/clLabeledImageQB123_1.tif + ${INPUTDATA}/Classification/clLabeledImageQB456_1.tif + ${INPUTDATA}/Classification/clLabeledImageQB1.tif + -method majorityvoting + -undecidedlabel 100 + -out ${TEMP}/apTvFusionOfClassificationsMV3InputsOutput.tif uint16 + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/apTvFusionOfClassifications3InputsOutput.tif + ${TEMP}/apTvFusionOfClassificationsMV3InputsOutput.tif) otb_test_application(NAME apTvFusionOfClassificationsDSKappa6Inputs - APP FusionOfClassifications - OPTIONS -il ${INPUTDATA}/Classification/QB_1_ortho_C1.tif - ${INPUTDATA}/Classification/QB_1_ortho_C2.tif - ${INPUTDATA}/Classification/QB_1_ortho_C3.tif - ${INPUTDATA}/Classification/QB_1_ortho_C4.tif - ${INPUTDATA}/Classification/QB_1_ortho_C5.tif - ${INPUTDATA}/Classification/QB_1_ortho_C6.tif - -method dempstershafer - -method.dempstershafer.cmfl ${INPUTDATA}/Classification/QB_1_ortho_C1.csv - ${INPUTDATA}/Classification/QB_1_ortho_C2.csv - ${INPUTDATA}/Classification/QB_1_ortho_C3.csv - ${INPUTDATA}/Classification/QB_1_ortho_C4.csv - ${INPUTDATA}/Classification/QB_1_ortho_C5.csv - ${INPUTDATA}/Classification/QB_1_ortho_C6.csv - -method.dempstershafer.mob kappa - -nodatalabel 10 - -undecidedlabel 7 - -out ${TEMP}/apTvFusionOfClassificationsDS6InputsKappaOutput.tif uint8 - VALID --compare-image ${NOTOL} - ${BASELINE}/QB_1_ortho_DS_FUSED_KAPPA.tif - ${TEMP}/apTvFusionOfClassificationsDS6InputsKappaOutput.tif) + APP FusionOfClassifications + OPTIONS -il ${INPUTDATA}/Classification/QB_1_ortho_C1.tif + ${INPUTDATA}/Classification/QB_1_ortho_C2.tif + ${INPUTDATA}/Classification/QB_1_ortho_C3.tif + ${INPUTDATA}/Classification/QB_1_ortho_C4.tif + ${INPUTDATA}/Classification/QB_1_ortho_C5.tif + ${INPUTDATA}/Classification/QB_1_ortho_C6.tif + -method dempstershafer + -method.dempstershafer.cmfl ${INPUTDATA}/Classification/QB_1_ortho_C1.csv + ${INPUTDATA}/Classification/QB_1_ortho_C2.csv + ${INPUTDATA}/Classification/QB_1_ortho_C3.csv + ${INPUTDATA}/Classification/QB_1_ortho_C4.csv + ${INPUTDATA}/Classification/QB_1_ortho_C5.csv + ${INPUTDATA}/Classification/QB_1_ortho_C6.csv + -method.dempstershafer.mob kappa + -nodatalabel 10 + -undecidedlabel 7 + -out ${TEMP}/apTvFusionOfClassificationsDS6InputsKappaOutput.tif uint8 + VALID --compare-image ${NOTOL} + ${BASELINE}/QB_1_ortho_DS_FUSED_KAPPA.tif + ${TEMP}/apTvFusionOfClassificationsDS6InputsKappaOutput.tif) otb_test_application(NAME apTvFusionOfClassificationsDSRecall6Inputs - APP FusionOfClassifications - OPTIONS -il ${INPUTDATA}/Classification/QB_1_ortho_C1.tif - ${INPUTDATA}/Classification/QB_1_ortho_C2.tif - ${INPUTDATA}/Classification/QB_1_ortho_C3.tif - ${INPUTDATA}/Classification/QB_1_ortho_C4.tif - ${INPUTDATA}/Classification/QB_1_ortho_C5.tif - ${INPUTDATA}/Classification/QB_1_ortho_C6.tif - -method dempstershafer - -method.dempstershafer.cmfl ${INPUTDATA}/Classification/QB_1_ortho_C1.csv - ${INPUTDATA}/Classification/QB_1_ortho_C2.csv - ${INPUTDATA}/Classification/QB_1_ortho_C3.csv - ${INPUTDATA}/Classification/QB_1_ortho_C4.csv - ${INPUTDATA}/Classification/QB_1_ortho_C5.csv - ${INPUTDATA}/Classification/QB_1_ortho_C6.csv - -method.dempstershafer.mob recall - -nodatalabel 10 - -undecidedlabel 7 - -out ${TEMP}/apTvFusionOfClassificationsDS6InputsRecallOutput.tif uint8 - VALID --compare-image ${NOTOL} - ${BASELINE}/QB_1_ortho_DS_FUSED_RECALL.tif - ${TEMP}/apTvFusionOfClassificationsDS6InputsRecallOutput.tif) + APP FusionOfClassifications + OPTIONS -il ${INPUTDATA}/Classification/QB_1_ortho_C1.tif + ${INPUTDATA}/Classification/QB_1_ortho_C2.tif + ${INPUTDATA}/Classification/QB_1_ortho_C3.tif + ${INPUTDATA}/Classification/QB_1_ortho_C4.tif + ${INPUTDATA}/Classification/QB_1_ortho_C5.tif + ${INPUTDATA}/Classification/QB_1_ortho_C6.tif + -method dempstershafer + -method.dempstershafer.cmfl ${INPUTDATA}/Classification/QB_1_ortho_C1.csv + ${INPUTDATA}/Classification/QB_1_ortho_C2.csv + ${INPUTDATA}/Classification/QB_1_ortho_C3.csv + ${INPUTDATA}/Classification/QB_1_ortho_C4.csv + ${INPUTDATA}/Classification/QB_1_ortho_C5.csv + ${INPUTDATA}/Classification/QB_1_ortho_C6.csv + -method.dempstershafer.mob recall + -nodatalabel 10 + -undecidedlabel 7 + -out ${TEMP}/apTvFusionOfClassificationsDS6InputsRecallOutput.tif uint8 + VALID --compare-image ${NOTOL} + ${BASELINE}/QB_1_ortho_DS_FUSED_RECALL.tif + ${TEMP}/apTvFusionOfClassificationsDS6InputsRecallOutput.tif) otb_test_application(NAME apTvFusionOfClassificationsDSAccuracy6Inputs - APP FusionOfClassifications - OPTIONS -il ${INPUTDATA}/Classification/QB_1_ortho_C1.tif - ${INPUTDATA}/Classification/QB_1_ortho_C2.tif - ${INPUTDATA}/Classification/QB_1_ortho_C3.tif - ${INPUTDATA}/Classification/QB_1_ortho_C4.tif - ${INPUTDATA}/Classification/QB_1_ortho_C5.tif - ${INPUTDATA}/Classification/QB_1_ortho_C6.tif - -method dempstershafer - -method.dempstershafer.cmfl ${INPUTDATA}/Classification/QB_1_ortho_C1.csv - ${INPUTDATA}/Classification/QB_1_ortho_C2.csv - ${INPUTDATA}/Classification/QB_1_ortho_C3.csv - ${INPUTDATA}/Classification/QB_1_ortho_C4.csv - ${INPUTDATA}/Classification/QB_1_ortho_C5.csv - ${INPUTDATA}/Classification/QB_1_ortho_C6.csv - -method.dempstershafer.mob accuracy - -nodatalabel 10 - -undecidedlabel 7 - -out ${TEMP}/apTvFusionOfClassificationsDS6InputsAccuracyOutput.tif uint8 - VALID --compare-image ${NOTOL} - ${BASELINE}/QB_1_ortho_DS_FUSED_ACCURACY.tif - ${TEMP}/apTvFusionOfClassificationsDS6InputsAccuracyOutput.tif) + APP FusionOfClassifications + OPTIONS -il ${INPUTDATA}/Classification/QB_1_ortho_C1.tif + ${INPUTDATA}/Classification/QB_1_ortho_C2.tif + ${INPUTDATA}/Classification/QB_1_ortho_C3.tif + ${INPUTDATA}/Classification/QB_1_ortho_C4.tif + ${INPUTDATA}/Classification/QB_1_ortho_C5.tif + ${INPUTDATA}/Classification/QB_1_ortho_C6.tif + -method dempstershafer + -method.dempstershafer.cmfl ${INPUTDATA}/Classification/QB_1_ortho_C1.csv + ${INPUTDATA}/Classification/QB_1_ortho_C2.csv + ${INPUTDATA}/Classification/QB_1_ortho_C3.csv + ${INPUTDATA}/Classification/QB_1_ortho_C4.csv + ${INPUTDATA}/Classification/QB_1_ortho_C5.csv + ${INPUTDATA}/Classification/QB_1_ortho_C6.csv + -method.dempstershafer.mob accuracy + -nodatalabel 10 + -undecidedlabel 7 + -out ${TEMP}/apTvFusionOfClassificationsDS6InputsAccuracyOutput.tif uint8 + VALID --compare-image ${NOTOL} + ${BASELINE}/QB_1_ortho_DS_FUSED_ACCURACY.tif + ${TEMP}/apTvFusionOfClassificationsDS6InputsAccuracyOutput.tif) otb_test_application(NAME apTvFusionOfClassificationsMV2Inputs - APP FusionOfClassifications - OPTIONS -il ${INPUTDATA}/Classification/clLabeledImageQB123_1.tif - ${INPUTDATA}/Classification/clLabeledImageQB456_1.tif - -method majorityvoting - -undecidedlabel 100 - -out ${TEMP}/apTvFusionOfClassificationsMV2InputsOutput.tif uint16 - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/apTvFusionOfClassifications2InputsOutput.tif - ${TEMP}/apTvFusionOfClassificationsMV2InputsOutput.tif) + APP FusionOfClassifications + OPTIONS -il ${INPUTDATA}/Classification/clLabeledImageQB123_1.tif + ${INPUTDATA}/Classification/clLabeledImageQB456_1.tif + -method majorityvoting + -undecidedlabel 100 + -out ${TEMP}/apTvFusionOfClassificationsMV2InputsOutput.tif uint16 + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/apTvFusionOfClassifications2InputsOutput.tif + ${TEMP}/apTvFusionOfClassificationsMV2InputsOutput.tif) #----------- ComputePolylineFeatureFromImage TESTS ---------------- otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_wr - APP ComputePolylineFeatureFromImage - OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/NDVI.TIF} - -vd LARGEINPUT{DEMPSTER-SHAFER/wrongroads.shp} - -expr "(b1 > 0.4)" - -field "NONDVI" - -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_wr.shp) + APP ComputePolylineFeatureFromImage + OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/NDVI.TIF} + -vd LARGEINPUT{DEMPSTER-SHAFER/wrongroads.shp} + -expr "(b1 > 0.4)" + -field "NONDVI" + -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_wr.shp) # FIXME cascade dependencies to largeinput repository if(OTB_DATA_USE_LARGEINPUT) -otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_RoadExtractionApplication - APP ComputePolylineFeatureFromImage - OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/SpectralAngleRoad.TIF} - -vd ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_RoadExtractionApplication.shp - -expr "(b1 > 0.25)" - -field "ROADSA" - -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_RoadExtractionApplication.shp) - -set_tests_properties(apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_RoadExtractionApplication PROPERTIES DEPENDS apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_RoadExtractionApplication) - -otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_wr - APP ComputePolylineFeatureFromImage - OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/SpectralAngleRoad.TIF} - -vd ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_wr.shp - -expr "(b1 > 0.25)" - -field "ROADSA" - -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_wr.shp) - -set_tests_properties(apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_wr PROPERTIES DEPENDS apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_wr) - -otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_wr - APP ComputePolylineFeatureFromImage - OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/BUILDINGS.TIF} - -vd ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_wr.shp - -expr "(b1 == 0)" - -field "NOBUIL" - -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_wr.shp - VALID --compare-ogr 0.0 - ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_wr.shp - ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_wr.shp) - -set_tests_properties(apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_wr PROPERTIES DEPENDS apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_wr) - -otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_RoadExtractionApplication - APP ComputePolylineFeatureFromImage - OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/NDVI.TIF} - -vd LARGEINPUT{DEMPSTER-SHAFER/road_extraction.shp} - -expr "(b1 > 0.4)" - -field "NONDVI" - -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_RoadExtractionApplication.shp) - -otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_gt - APP ComputePolylineFeatureFromImage - OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/NDVI.TIF} - -vd LARGEINPUT{DEMPSTER-SHAFER/roads_ground_truth.shp} - -expr "(b1 > 0.4)" - -field NONDVI - -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage.shp) - -otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_gt - APP ComputePolylineFeatureFromImage - OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/SpectralAngleRoad.TIF} - -vd ${TEMP}/apTvCdbComputePolylineFeatureFromImage.shp - -expr "(b1 > 0.25)" - -field "ROADSA" - -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_gt.shp) - -set_tests_properties(apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_gt PROPERTIES DEPENDS apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_gt) - -otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_gt - APP ComputePolylineFeatureFromImage - OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/BUILDINGS.TIF} - -vd ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_gt.shp - -expr "(b1 == 0)" - -field "NOBUIL" - -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_gt.shp - VALID --compare-ogr 0.0 - ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_gt.shp - ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_gt.shp) - -set_tests_properties(apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_gt PROPERTIES DEPENDS apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_gt) - -otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_RoadExtractionApplication - APP ComputePolylineFeatureFromImage - OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/BUILDINGS.TIF} - -vd ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_RoadExtractionApplication.shp - -expr "(b1 == 0)" - -field "NOBUIL" - -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_RoadExtractionApplication.shp - VALID --compare-ogr 0.0 - ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_RoadExtractionApplication.shp - ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_RoadExtractionApplication.shp) - -set_tests_properties(apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_RoadExtractionApplication PROPERTIES DEPENDS apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_RoadExtractionApplication) + otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_RoadExtractionApplication + APP ComputePolylineFeatureFromImage + OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/SpectralAngleRoad.TIF} + -vd ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_RoadExtractionApplication.shp + -expr "(b1 > 0.25)" + -field "ROADSA" + -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_RoadExtractionApplication.shp) + + set_tests_properties(apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_RoadExtractionApplication PROPERTIES DEPENDS apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_RoadExtractionApplication) + + otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_wr + APP ComputePolylineFeatureFromImage + OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/SpectralAngleRoad.TIF} + -vd ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_wr.shp + -expr "(b1 > 0.25)" + -field "ROADSA" + -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_wr.shp) + + set_tests_properties(apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_wr PROPERTIES DEPENDS apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_wr) + + otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_wr + APP ComputePolylineFeatureFromImage + OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/BUILDINGS.TIF} + -vd ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_wr.shp + -expr "(b1 == 0)" + -field "NOBUIL" + -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_wr.shp + VALID --compare-ogr 0.0 + ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_wr.shp + ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_wr.shp) + + set_tests_properties(apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_wr PROPERTIES DEPENDS apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_wr) + + otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_RoadExtractionApplication + APP ComputePolylineFeatureFromImage + OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/NDVI.TIF} + -vd LARGEINPUT{DEMPSTER-SHAFER/road_extraction.shp} + -expr "(b1 > 0.4)" + -field "NONDVI" + -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_RoadExtractionApplication.shp) + + otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_gt + APP ComputePolylineFeatureFromImage + OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/NDVI.TIF} + -vd LARGEINPUT{DEMPSTER-SHAFER/roads_ground_truth.shp} + -expr "(b1 > 0.4)" + -field NONDVI + -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage.shp) + + otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_gt + APP ComputePolylineFeatureFromImage + OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/SpectralAngleRoad.TIF} + -vd ${TEMP}/apTvCdbComputePolylineFeatureFromImage.shp + -expr "(b1 > 0.25)" + -field "ROADSA" + -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_gt.shp) + + set_tests_properties(apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_gt PROPERTIES DEPENDS apTvCdbComputePolylineFeatureFromImage_LI_NONDVI_gt) + + otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_gt + APP ComputePolylineFeatureFromImage + OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/BUILDINGS.TIF} + -vd ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_gt.shp + -expr "(b1 == 0)" + -field "NOBUIL" + -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_gt.shp + VALID --compare-ogr 0.0 + ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_gt.shp + ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_gt.shp) + + set_tests_properties(apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_gt PROPERTIES DEPENDS apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_gt) + + otb_test_application(NAME apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_RoadExtractionApplication + APP ComputePolylineFeatureFromImage + OPTIONS -in LARGEINPUT{DEMPSTER-SHAFER/BUILDINGS.TIF} + -vd ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_RoadExtractionApplication.shp + -expr "(b1 == 0)" + -field "NOBUIL" + -out ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_RoadExtractionApplication.shp + VALID --compare-ogr 0.0 + ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_RoadExtractionApplication.shp + ${TEMP}/apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_RoadExtractionApplication.shp) + + set_tests_properties(apTvCdbComputePolylineFeatureFromImage_LI_NOBUIL_RoadExtractionApplication PROPERTIES DEPENDS apTvCdbComputePolylineFeatureFromImage_LI_ROADSA_RoadExtractionApplication) endif() #----------- KMeansClassification TESTS ---------------- otb_test_application(NAME apTvClKMeansImageClassification - APP KMeansClassification - OPTIONS -in ${INPUTDATA}/qb_RoadExtract.img - -vm ${INPUTDATA}/qb_RoadExtract_mask.png - -ts 30000 - -nc 5 - -maxit 10000 - -ct 0.0000001 - -rand 121212 - -out ${TEMP}/apTvClKMeansImageClassificationFilterOutput.tif - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/apTvClKMeansImageClassificationFilterOutput.tif - ${TEMP}/apTvClKMeansImageClassificationFilterOutput.tif ) + APP KMeansClassification + OPTIONS -in ${INPUTDATA}/qb_RoadExtract.img + -vm ${INPUTDATA}/qb_RoadExtract_mask.png + -ts 30000 + -nc 5 + -maxit 10000 + -ct 0.0000001 + -rand 121212 + -out ${TEMP}/apTvClKMeansImageClassificationFilterOutput.tif + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/apTvClKMeansImageClassificationFilterOutput.tif + ${TEMP}/apTvClKMeansImageClassificationFilterOutput.tif ) #----------- TrainImagesClassifier TESTS ---------------- if(OTB_USE_LIBSVM) -otb_test_application(NAME apTvClTrainSVMImagesClassifierQB1_allOpt_InXML - APP TrainImagesClassifier - OPTIONS - -inxml ${INPUTDATA}/clsvmModelQB1_OutXML.xml - -io.il ${INPUTDATA}/Classification/QB_1_ortho.tif - -io.vd ${INPUTDATA}/Classification/VectorData_QB1.shp - -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml - -sample.mv 100 - -sample.mt 100 - -sample.vtr 0.5 - -sample.vfn Class - -classifier.libsvm.opt true - -rand 121212 - -io.out ${TEMP}/clsvmModelQB1_allOpt_InXML.svm - VALID ${ascii_comparison} - ${OTBAPP_BASELINE_FILES}/clsvmModelQB1.svm - ${TEMP}/clsvmModelQB1_allOpt_InXML.svm) - -otb_test_application(NAME apTvClTrainSVMImagesClassifierQB1_OutXML - APP TrainImagesClassifier - OPTIONS -io.il ${INPUTDATA}/Classification/QB_1_ortho.tif - -io.vd ${INPUTDATA}/Classification/VectorData_QB1.shp - -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml - -sample.vfn Class - -classifier libsvm - -classifier.libsvm.opt true - -io.out ${TEMP}/clsvmModelQB1_OutXML.svm - -rand 121212 - -outxml ${TEMP}/clsvmModelQB1_OutXML.xml - VALID ${ascii_comparison} - ${OTBAPP_BASELINE_FILES}/clsvmModelQB1.svm - ${TEMP}/clsvmModelQB1_OutXML.svm) + otb_test_application(NAME apTvClTrainSVMImagesClassifierQB1_allOpt_InXML + APP TrainImagesClassifier + OPTIONS + -inxml ${INPUTDATA}/clsvmModelQB1_OutXML.xml + -io.il ${INPUTDATA}/Classification/QB_1_ortho.tif + -io.vd ${INPUTDATA}/Classification/VectorData_QB1.shp + -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml + -sample.mv 100 + -sample.mt 100 + -sample.vtr 0.5 + -sample.vfn Class + -classifier.libsvm.opt true + -rand 121212 + -io.out ${TEMP}/clsvmModelQB1_allOpt_InXML.svm + VALID ${ascii_comparison} + ${OTBAPP_BASELINE_FILES}/clsvmModelQB1.svm + ${TEMP}/clsvmModelQB1_allOpt_InXML.svm) + + otb_test_application(NAME apTvClTrainSVMImagesClassifierQB1_OutXML + APP TrainImagesClassifier + OPTIONS -io.il ${INPUTDATA}/Classification/QB_1_ortho.tif + -io.vd ${INPUTDATA}/Classification/VectorData_QB1.shp + -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml + -sample.vfn Class + -classifier libsvm + -classifier.libsvm.opt true + -io.out ${TEMP}/clsvmModelQB1_OutXML.svm + -rand 121212 + -outxml ${TEMP}/clsvmModelQB1_OutXML.xml + VALID ${ascii_comparison} + ${OTBAPP_BASELINE_FILES}/clsvmModelQB1.svm + ${TEMP}/clsvmModelQB1_OutXML.svm) otb_test_application(NAME apTvClTrainSVMImagesClassifierQB123 - APP TrainImagesClassifier - OPTIONS -io.il ${INPUTDATA}/Classification/QB_1_ortho.tif - ${INPUTDATA}/Classification/QB_2_ortho.tif - ${INPUTDATA}/Classification/QB_3_ortho.tif - -io.vd ${INPUTDATA}/Classification/VectorData_QB1.shp - ${INPUTDATA}/Classification/VectorData_QB2.shp - ${INPUTDATA}/Classification/VectorData_QB3.shp - -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB123.xml - -sample.vfn Class - -classifier libsvm - -classifier.libsvm.opt true - -io.out ${TEMP}/clsvmModelQB123.svm - -rand 121212) -# RK: 09/2016. same reason explained for leTvSVMImageModelEstimatorTrainWithOptimization test -# VALID --compare-ascii ${NOTOL} -# ${OTBAPP_BASELINE_FILES}/clsvmModelQB123.svm -# ${TEMP}/clsvmModelQB123.svm - -otb_test_application(NAME apTvClTrainSVMImagesClassifierQB1 - APP TrainImagesClassifier - OPTIONS -io.il ${INPUTDATA}/Classification/QB_1_ortho.tif - -io.vd ${INPUTDATA}/Classification/VectorData_QB1.shp - -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml - -classifier libsvm - -classifier.libsvm.opt true - -sample.vfn Class - -io.out ${TEMP}/clsvmModelQB1.svm - -rand 121212 - VALID ${ascii_comparison} - ${OTBAPP_BASELINE_FILES}/clsvmModelQB1.svm - ${TEMP}/clsvmModelQB1.svm) + APP TrainImagesClassifier + OPTIONS -io.il ${INPUTDATA}/Classification/QB_1_ortho.tif + ${INPUTDATA}/Classification/QB_2_ortho.tif + ${INPUTDATA}/Classification/QB_3_ortho.tif + -io.vd ${INPUTDATA}/Classification/VectorData_QB1.shp + ${INPUTDATA}/Classification/VectorData_QB2.shp + ${INPUTDATA}/Classification/VectorData_QB3.shp + -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB123.xml + -sample.vfn Class + -classifier libsvm + -classifier.libsvm.opt true + -io.out ${TEMP}/clsvmModelQB123.svm + -rand 121212) + # RK: 09/2016. same reason explained for leTvSVMImageModelEstimatorTrainWithOptimization test + # VALID --compare-ascii ${NOTOL} + # ${OTBAPP_BASELINE_FILES}/clsvmModelQB123.svm + # ${TEMP}/clsvmModelQB123.svm + + otb_test_application(NAME apTvClTrainSVMImagesClassifierQB1 + APP TrainImagesClassifier + OPTIONS -io.il ${INPUTDATA}/Classification/QB_1_ortho.tif + -io.vd ${INPUTDATA}/Classification/VectorData_QB1.shp + -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml + -classifier libsvm + -classifier.libsvm.opt true + -sample.vfn Class + -io.out ${TEMP}/clsvmModelQB1.svm + -rand 121212 + VALID ${ascii_comparison} + ${OTBAPP_BASELINE_FILES}/clsvmModelQB1.svm + ${TEMP}/clsvmModelQB1.svm) otb_test_application(NAME apTvClTrainSVMImagesClassifierQB456 - APP TrainImagesClassifier - OPTIONS -io.il ${INPUTDATA}/Classification/QB_4_extract.tif - ${INPUTDATA}/Classification/QB_5_extract.tif - ${INPUTDATA}/Classification/QB_6_extract.tif - -io.vd ${INPUTDATA}/Classification/VectorData_QB4.shp - ${INPUTDATA}/Classification/VectorData_QB5.shp - ${INPUTDATA}/Classification/VectorData_QB6.shp - -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB456.xml - -sample.vfn Class - -classifier libsvm - -classifier.libsvm.opt true - -io.out ${TEMP}/clsvmModelQB456.svm - -rand 121212) - -# RK: 09/2016. same reason explained for leTvSVMImageModelEstimatorTrainWithOptimization test -# VALID --compare-ascii ${NOTOL} -# ${OTBAPP_BASELINE_FILES}/clsvmModelQB456.svm -# ${TEMP}/clsvmModelQB456.svm - -otb_test_application(NAME apTvClTrainSVMImagesClassifierQB1_allOpt - APP TrainImagesClassifier - OPTIONS -io.il ${INPUTDATA}/Classification/QB_1_ortho.tif - -io.vd ${INPUTDATA}/Classification/VectorData_QB1.shp - -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml - -classifier libsvm - -sample.mv 100 - -sample.mt 100 - -sample.vtr 0.5 - -sample.vfn Class - -classifier.libsvm.opt true - -rand 121212 - -io.out ${TEMP}/clsvmModelQB1_allOpt.svm - VALID ${ascii_comparison} - ${OTBAPP_BASELINE_FILES}/clsvmModelQB1.svm - ${TEMP}/clsvmModelQB1_allOpt.svm) + APP TrainImagesClassifier + OPTIONS -io.il ${INPUTDATA}/Classification/QB_4_extract.tif + ${INPUTDATA}/Classification/QB_5_extract.tif + ${INPUTDATA}/Classification/QB_6_extract.tif + -io.vd ${INPUTDATA}/Classification/VectorData_QB4.shp + ${INPUTDATA}/Classification/VectorData_QB5.shp + ${INPUTDATA}/Classification/VectorData_QB6.shp + -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB456.xml + -sample.vfn Class + -classifier libsvm + -classifier.libsvm.opt true + -io.out ${TEMP}/clsvmModelQB456.svm + -rand 121212) + + # RK: 09/2016. same reason explained for leTvSVMImageModelEstimatorTrainWithOptimization test + # VALID --compare-ascii ${NOTOL} + # ${OTBAPP_BASELINE_FILES}/clsvmModelQB456.svm + # ${TEMP}/clsvmModelQB456.svm + + otb_test_application(NAME apTvClTrainSVMImagesClassifierQB1_allOpt + APP TrainImagesClassifier + OPTIONS -io.il ${INPUTDATA}/Classification/QB_1_ortho.tif + -io.vd ${INPUTDATA}/Classification/VectorData_QB1.shp + -io.imstat ${INPUTDATA}/Classification/clImageStatisticsQB1.xml + -classifier libsvm + -sample.mv 100 + -sample.mt 100 + -sample.vtr 0.5 + -sample.vfn Class + -classifier.libsvm.opt true + -rand 121212 + -io.out ${TEMP}/clsvmModelQB1_allOpt.svm + VALID ${ascii_comparison} + ${OTBAPP_BASELINE_FILES}/clsvmModelQB1.svm + ${TEMP}/clsvmModelQB1_allOpt.svm) endif() #----------- DSFuzzyModelEstimation TESTS ---------------- otb_test_application(NAME apTvCdbDSFuzzyModelEstimation_LI_autoInit - APP DSFuzzyModelEstimation - OPTIONS -psin ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_gt.shp - -nsin ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_wr.shp - -belsup "ROADSA" - -plasup "NONDVI" "ROADSA" "NOBUIL" - -desclist "NONDVI" "ROADSA" "NOBUIL" - -maxnbit 4 - -optobs true - -out ${TEMP}/apTvCdbDSFuzzyModelEstimatorOutput_LI_autoInit.xml) + APP DSFuzzyModelEstimation + OPTIONS -psin ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_gt.shp + -nsin ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_wr.shp + -belsup "ROADSA" + -plasup "NONDVI" "ROADSA" "NOBUIL" + -desclist "NONDVI" "ROADSA" "NOBUIL" + -maxnbit 4 + -optobs true + -out ${TEMP}/apTvCdbDSFuzzyModelEstimatorOutput_LI_autoInit.xml) otb_test_application(NAME apTvCdbDSFuzzyModelEstimation_LI - APP DSFuzzyModelEstimation - OPTIONS -psin ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_gt.shp - -nsin ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_wr.shp - -belsup "ROADSA" - -plasup "NONDVI" "ROADSA" "NOBUIL" - -initmod ${OTB_DATA_ROOT}/Input/Dempster-Shafer/DSFuzzyModel_Init.xml - -maxnbit 4 - -optobs true - -out ${TEMP}/apTvCdbDSFuzzyModelEstimatorOutput_LI.xml) + APP DSFuzzyModelEstimation + OPTIONS -psin ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_gt.shp + -nsin ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_wr.shp + -belsup "ROADSA" + -plasup "NONDVI" "ROADSA" "NOBUIL" + -initmod ${OTB_DATA_ROOT}/Input/Dempster-Shafer/DSFuzzyModel_Init.xml + -maxnbit 4 + -optobs true + -out ${TEMP}/apTvCdbDSFuzzyModelEstimatorOutput_LI.xml) #----------- ClassificationMapRegularization TESTS ---------------- otb_test_application(NAME apTvClassificationMapRegularization - APP ClassificationMapRegularization - OPTIONS -io.in ${OTBAPP_BASELINE}/clLabeledImageQB123_1.tif - -io.out ${TEMP}/clLabeledImageQB123_1_CMR_r2_nodl_10_undl_7.tif - -ip.radius 2 - -ip.suvbool true - -ip.nodatalabel 10 - -ip.undecidedlabel 7 - VALID --compare-image ${NOTOL} - ${OTBAPP_BASELINE}/clLabeledImageQB123_1_CMR_r2_nodl_10_undl_7.tif - ${TEMP}/clLabeledImageQB123_1_CMR_r2_nodl_10_undl_7.tif) + APP ClassificationMapRegularization + OPTIONS -io.in ${OTBAPP_BASELINE}/clLabeledImageQB123_1.tif + -io.out ${TEMP}/clLabeledImageQB123_1_CMR_r2_nodl_10_undl_7.tif + -ip.radius 2 + -ip.suvbool true + -ip.nodatalabel 10 + -ip.undecidedlabel 7 + VALID --compare-image ${NOTOL} + ${OTBAPP_BASELINE}/clLabeledImageQB123_1_CMR_r2_nodl_10_undl_7.tif + ${TEMP}/clLabeledImageQB123_1_CMR_r2_nodl_10_undl_7.tif) #----------- OGRLayerClassifier TESTS ---------------- #----------- ComputeImagesStatistics TESTS ---------------- otb_test_application(NAME apTvClComputeImagesStatisticsQB1 - APP ComputeImagesStatistics - OPTIONS -il ${INPUTDATA}/Classification/QB_1_ortho.tif - -out ${TEMP}/apTvClEstimateImageStatisticsQB1.xml - VALID --compare-ascii ${NOTOL} - ${OTBAPP_BASELINE_FILES}/clImageStatisticsQB1.xml - ${TEMP}/apTvClEstimateImageStatisticsQB1.xml) + APP ComputeImagesStatistics + OPTIONS -il ${INPUTDATA}/Classification/QB_1_ortho.tif + -out ${TEMP}/apTvClEstimateImageStatisticsQB1.xml + VALID --compare-ascii ${NOTOL} + ${OTBAPP_BASELINE_FILES}/clImageStatisticsQB1.xml + ${TEMP}/apTvClEstimateImageStatisticsQB1.xml) otb_test_application(NAME apTvClComputeImagesStatisticsQB456 - APP ComputeImagesStatistics - OPTIONS -il ${INPUTDATA}/Classification/QB_4_extract.tif - ${INPUTDATA}/Classification/QB_5_extract.tif - ${INPUTDATA}/Classification/QB_6_extract.tif - -out ${TEMP}/apTvClEstimateImageStatisticsQB456.xml - VALID --compare-ascii ${NOTOL} - ${OTBAPP_BASELINE_FILES}/clImageStatisticsQB456.xml - ${TEMP}/apTvClEstimateImageStatisticsQB456.xml) + APP ComputeImagesStatistics + OPTIONS -il ${INPUTDATA}/Classification/QB_4_extract.tif + ${INPUTDATA}/Classification/QB_5_extract.tif + ${INPUTDATA}/Classification/QB_6_extract.tif + -out ${TEMP}/apTvClEstimateImageStatisticsQB456.xml + VALID --compare-ascii ${NOTOL} + ${OTBAPP_BASELINE_FILES}/clImageStatisticsQB456.xml + ${TEMP}/apTvClEstimateImageStatisticsQB456.xml) otb_test_application(NAME apTvClComputeImagesStatisticsQB123 - APP ComputeImagesStatistics - OPTIONS -il ${INPUTDATA}/Classification/QB_1_ortho.tif - ${INPUTDATA}/Classification/QB_2_ortho.tif - ${INPUTDATA}/Classification/QB_3_ortho.tif - -out ${TEMP}/apTvClEstimateImageStatisticsQB123.xml - VALID --compare-ascii ${NOTOL} - ${OTBAPP_BASELINE_FILES}/clImageStatisticsQB123.xml - ${TEMP}/apTvClEstimateImageStatisticsQB123.xml) + APP ComputeImagesStatistics + OPTIONS -il ${INPUTDATA}/Classification/QB_1_ortho.tif + ${INPUTDATA}/Classification/QB_2_ortho.tif + ${INPUTDATA}/Classification/QB_3_ortho.tif + -out ${TEMP}/apTvClEstimateImageStatisticsQB123.xml + VALID --compare-ascii ${NOTOL} + ${OTBAPP_BASELINE_FILES}/clImageStatisticsQB123.xml + ${TEMP}/apTvClEstimateImageStatisticsQB123.xml) #----------- VectorDataDSValidation TESTS ---------------- otb_test_application(NAME cdbTvVectorDataDSValidationGroundTruth_LI - APP VectorDataDSValidation - OPTIONS -in ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_gt.shp - -belsup "ROADSA" - -plasup "NONDVI" "ROADSA" "NOBUIL" - -descmod ${OTB_DATA_ROOT}/Input/Dempster-Shafer/DSFuzzyModel.xml - -out ${TEMP}/cdbTvVectorDataDSValidationOutpout_LI_gt.shp - VALID --compare-ogr 0.0 - ${OTBAPP_BASELINE_FILES}/cdbTvVectorDataDSValidationOutpout_LI_gt.shp - ${TEMP}/cdbTvVectorDataDSValidationOutpout_LI_gt.shp) + APP VectorDataDSValidation + OPTIONS -in ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_gt.shp + -belsup "ROADSA" + -plasup "NONDVI" "ROADSA" "NOBUIL" + -descmod ${OTB_DATA_ROOT}/Input/Dempster-Shafer/DSFuzzyModel.xml + -out ${TEMP}/cdbTvVectorDataDSValidationOutpout_LI_gt.shp + VALID --compare-ogr 0.0 + ${OTBAPP_BASELINE_FILES}/cdbTvVectorDataDSValidationOutpout_LI_gt.shp + ${TEMP}/cdbTvVectorDataDSValidationOutpout_LI_gt.shp) otb_test_application(NAME apTvCdbVectorDataDSValidationRoadExtractionApplication_LI - APP VectorDataDSValidation - OPTIONS -in ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_RoadExtractionApplication.shp - -belsup "ROADSA" - -plasup "NONDVI" "ROADSA" "NOBUIL" - -descmod ${OTB_DATA_ROOT}/Input/Dempster-Shafer/DSFuzzyModel.xml - -out ${TEMP}/apTvCdbVectorDataDSValidationOutpout_LI_RoadExtractionApplication.shp) + APP VectorDataDSValidation + OPTIONS -in ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_RoadExtractionApplication.shp + -belsup "ROADSA" + -plasup "NONDVI" "ROADSA" "NOBUIL" + -descmod ${OTB_DATA_ROOT}/Input/Dempster-Shafer/DSFuzzyModel.xml + -out ${TEMP}/apTvCdbVectorDataDSValidationOutpout_LI_RoadExtractionApplication.shp) otb_test_application(NAME cdbTvVectorDataDSValidationWrongRoads_LI - APP VectorDataDSValidation - OPTIONS -in ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_wr.shp - -belsup "ROADSA" - -plasup "NONDVI" "ROADSA" "NOBUIL" - -descmod ${OTB_DATA_ROOT}/Input/Dempster-Shafer/DSFuzzyModel.xml - -out ${TEMP}/cdbTvVectorDataDSValidationOutpout_LI_wr.shp - VALID --compare-ogr 0.0 - ${OTBAPP_BASELINE_FILES}/cdbTvVectorDataDSValidationOutpout_LI_wr.shp - ${TEMP}/cdbTvVectorDataDSValidationOutpout_LI_wr.shp) + APP VectorDataDSValidation + OPTIONS -in ${OTBAPP_BASELINE_FILES}/cdbTvComputePolylineFeatureFromImage_LI_NOBUIL_wr.shp + -belsup "ROADSA" + -plasup "NONDVI" "ROADSA" "NOBUIL" + -descmod ${OTB_DATA_ROOT}/Input/Dempster-Shafer/DSFuzzyModel.xml + -out ${TEMP}/cdbTvVectorDataDSValidationOutpout_LI_wr.shp + VALID --compare-ogr 0.0 + ${OTBAPP_BASELINE_FILES}/cdbTvVectorDataDSValidationOutpout_LI_wr.shp + ${TEMP}/cdbTvVectorDataDSValidationOutpout_LI_wr.shp) if(OTB_USE_OPENCV) -#----------- TrainRegression TESTS ---------------- -# y = 0.01*x^2 + 1.5*x - 300 -otb_test_application(NAME apTvClTrainRegressionTest_monovar - APP TrainRegression - OPTIONS -io.il ${INPUTDATA}/QB_Toulouse_Ortho_regression.tif - -io.imstat ${INPUTDATA}/QB_Toulouse_Ortho_regression.xml - -io.out ${TEMP}/apTvClTrainRegressionTest_monovar.rf - -sample.mt 20000 - -sample.mv 20000 - -sample.vtr 0.5 - -rand 121212 - -classifier rf - -classifier.rf.ra 0.0001 - -classifier.rf.max 6 - -classifier.rf.acc 0.0005 - VALID ${ascii_comparison} - ${OTBAPP_BASELINE_FILES}/apTvClTrainRegressionTest_monovar.rf - ${TEMP}/apTvClTrainRegressionTest_monovar.rf) - -#----------- PredictRegression TESTS ---------------- -otb_test_application(NAME apTvClPredictRegressionTest_monovar - APP PredictRegression - 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 - VALID --compare-image 1 - ${OTBAPP_BASELINE}/apTvClPredictRegressionTest_monovar.tif - ${TEMP}/apTvClPredictRegressionTest_monovar.tif) + #----------- TrainRegression TESTS ---------------- + # y = 0.01*x^2 + 1.5*x - 300 + otb_test_application(NAME apTvClTrainRegressionTest_monovar + APP TrainRegression + OPTIONS -io.il ${INPUTDATA}/QB_Toulouse_Ortho_regression.tif + -io.imstat ${INPUTDATA}/QB_Toulouse_Ortho_regression.xml + -io.out ${TEMP}/apTvClTrainRegressionTest_monovar.rf + -sample.mt 20000 + -sample.mv 20000 + -sample.vtr 0.5 + -rand 121212 + -classifier rf + -classifier.rf.ra 0.0001 + -classifier.rf.max 6 + -classifier.rf.acc 0.0005 + VALID ${ascii_comparison} + ${OTBAPP_BASELINE_FILES}/apTvClTrainRegressionTest_monovar.rf + ${TEMP}/apTvClTrainRegressionTest_monovar.rf) + + #----------- PredictRegression TESTS ---------------- + otb_test_application(NAME apTvClPredictRegressionTest_monovar + APP PredictRegression + 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 + VALID --compare-image 1 + ${OTBAPP_BASELINE}/apTvClPredictRegressionTest_monovar.tif + ${TEMP}/apTvClPredictRegressionTest_monovar.tif) endif() #----------- PolygonClassStatistics TESTS ---------------- otb_test_application(NAME apTvClPolygonClassStatisticsTest - APP PolygonClassStatistics - OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho.tif - -vec ${INPUTDATA}/Classification/VectorData_QB1.shp - -field Class - -out ${TEMP}/apTvClPolygonClassStatisticsOut.xml - VALID --compare-ascii ${NOTOL} - ${OTBAPP_BASELINE_FILES}/apTvClPolygonClassStatisticsOut.xml - ${TEMP}/apTvClPolygonClassStatisticsOut.xml) + APP PolygonClassStatistics + OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho.tif + -vec ${INPUTDATA}/Classification/VectorData_QB1.shp + -field Class + -out ${TEMP}/apTvClPolygonClassStatisticsOut.xml + VALID --compare-ascii ${NOTOL} + ${OTBAPP_BASELINE_FILES}/apTvClPolygonClassStatisticsOut.xml + ${TEMP}/apTvClPolygonClassStatisticsOut.xml) #----------- SampleSelection TESTS ----------------------- otb_test_application(NAME apTvClSampleSelection - APP SampleSelection - OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho.tif - -vec ${INPUTDATA}/Classification/VectorData_QB1.shp - -field Class - -out ${TEMP}/apTvClSampleSelectionOut.sqlite - -instats ${OTBAPP_BASELINE_FILES}/apTvClPolygonClassStatisticsOut.xml - -outrates ${TEMP}/apTvClSampleSelectionOutRates.txt - -strategy byclass - -strategy.byclass.in ${INPUTDATA}/Classification/sampling_required.csv - -sampler periodic - VALID --compare-ogr ${NOTOL} - ${OTBAPP_BASELINE_FILES}/apTvClSampleSelectionOut.sqlite - ${TEMP}/apTvClSampleSelectionOut.sqlite) + APP SampleSelection + OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho.tif + -vec ${INPUTDATA}/Classification/VectorData_QB1.shp + -field Class + -out ${TEMP}/apTvClSampleSelectionOut.sqlite + -instats ${OTBAPP_BASELINE_FILES}/apTvClPolygonClassStatisticsOut.xml + -outrates ${TEMP}/apTvClSampleSelectionOutRates.txt + -strategy byclass + -strategy.byclass.in ${INPUTDATA}/Classification/sampling_required.csv + -sampler periodic + VALID --compare-ogr ${NOTOL} + ${OTBAPP_BASELINE_FILES}/apTvClSampleSelectionOut.sqlite + ${TEMP}/apTvClSampleSelectionOut.sqlite) #----------- SampleExtraction TESTS ----------------------- otb_test_application(NAME apTvClSampleExtraction - APP SampleExtraction - OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho.tif - -vec ${INPUTDATA}/Classification/apTvClSampleSelectionOut.sqlite - -field class - -out ${TEMP}/apTvClSampleExtractionOut.sqlite - VALID --compare-ogr ${NOTOL} - ${OTBAPP_BASELINE_FILES}/apTvClSampleExtractionOut.sqlite - ${TEMP}/apTvClSampleExtractionOut.sqlite) + APP SampleExtraction + OPTIONS -in ${INPUTDATA}/Classification/QB_1_ortho.tif + -vec ${INPUTDATA}/Classification/apTvClSampleSelectionOut.sqlite + -field class + -out ${TEMP}/apTvClSampleExtractionOut.sqlite + VALID --compare-ogr ${NOTOL} + ${OTBAPP_BASELINE_FILES}/apTvClSampleExtractionOut.sqlite + ${TEMP}/apTvClSampleExtractionOut.sqlite) #----------- TrainVectorClassifier TESTS ---------------- if(OTB_USE_OPENCV) @@ -953,6 +957,24 @@ if(OTB_USE_OPENCV) ${TEMP}/apTvClTrainVectorClassifierModel.rf) endif() +#----------- TrainVectorClassifier unsupervised TESTS ---------------- +if(OTB_USE_SHARK) + otb_test_application(NAME apTvClTrainVectorUnsupervised + APP TrainVectorClassifier + OPTIONS -io.vd ${INPUTDATA}/Classification/apTvClSampleExtractionOut.sqlite + -feat value_0 value_1 value_2 value_3 + -classifier sharkkm + -io.out ${TEMP}/apTvClTrainVectorClusteringModel.txt) + + otb_test_application(NAME apTvClTrainVectorUnsupervisedWithClass + APP TrainVectorClassifier + OPTIONS -io.vd ${INPUTDATA}/Classification/apTvClSampleExtractionOut.sqlite + -feat value_0 value_1 value_2 value_3 + -cfield class + -classifier sharkkm + -io.out ${TEMP}/apTvClTrainVectorClusteringModelWithClass.txt) +endif() + #------------ MultiImageSamplingRate TESTS ---------------- otb_test_application( NAME apTvClMultiImageSamplingRate @@ -971,4 +993,4 @@ otb_test_application( ${TEMP}/apTvClMultiImageSamplingRate_out_2.csv ${OTBAPP_BASELINE_FILES}/apTvClMultiImageSamplingRate_out_3.csv ${TEMP}/apTvClMultiImageSamplingRate_out_3.csv - ) +) diff --git a/Modules/Learning/Supervised/include/otbImageClassificationFilter.h b/Modules/Learning/LearningBase/include/otbImageClassificationFilter.h similarity index 99% rename from Modules/Learning/Supervised/include/otbImageClassificationFilter.h rename to Modules/Learning/LearningBase/include/otbImageClassificationFilter.h index 35804bc535ab0ce0d2607f2cb14ec5a806a8ae42..620177e5af42420b3a58a0bced7db1abfe82b4ac 100644 --- a/Modules/Learning/Supervised/include/otbImageClassificationFilter.h +++ b/Modules/Learning/LearningBase/include/otbImageClassificationFilter.h @@ -37,7 +37,7 @@ namespace otb * \ingroup Streamed * \ingroup Threaded * - * \ingroup OTBSupervised + * \ingroup OTBLearningBase */ template <class TInputImage, class TOutputImage, class TMaskImage = TOutputImage> class ITK_EXPORT ImageClassificationFilter @@ -90,7 +90,7 @@ public: itkSetMacro(BatchMode, bool); itkGetMacro(BatchMode, bool); itkBooleanMacro(BatchMode); - + /** * If set, only pixels within the mask will be classified. * All pixels with a value greater than 0 in the mask, will be classified. diff --git a/Modules/Learning/Supervised/include/otbImageClassificationFilter.txx b/Modules/Learning/LearningBase/include/otbImageClassificationFilter.txx similarity index 100% rename from Modules/Learning/Supervised/include/otbImageClassificationFilter.txx rename to Modules/Learning/LearningBase/include/otbImageClassificationFilter.txx diff --git a/Modules/Learning/Supervised/include/otbMachineLearningModel.h b/Modules/Learning/LearningBase/include/otbMachineLearningModel.h similarity index 98% rename from Modules/Learning/Supervised/include/otbMachineLearningModel.h rename to Modules/Learning/LearningBase/include/otbMachineLearningModel.h index a71d819eff893cee01c60d411b1116c2351aa6df..12e0e4dbf924b15a02c17a302443edb5855d9205 100644 --- a/Modules/Learning/Supervised/include/otbMachineLearningModel.h +++ b/Modules/Learning/LearningBase/include/otbMachineLearningModel.h @@ -60,10 +60,11 @@ namespace otb * \sa NormalBayesMachineLearningModel * \sa NeuralNetworkMachineLearningModel * \sa SharkRandomForestsMachineLearningModel + * \sa SharkKMeansMachineLearningModel * \sa ImageClassificationFilter * * - * \ingroup OTBSupervised + * \ingroup OTBLearningBase */ template <class TInputValue, class TTargetValue, class TConfidenceValue = double > class ITK_EXPORT MachineLearningModel @@ -93,7 +94,7 @@ public: //@} /**\name Confidence value typedef */ - typedef TConfidenceValue ConfidenceValueType; + typedef TConfidenceValue ConfidenceValueType; typedef itk::FixedArray<ConfidenceValueType,1> ConfidenceSampleType; typedef itk::Statistics::ListSample<ConfidenceSampleType> ConfidenceListSampleType; diff --git a/Modules/Learning/Supervised/include/otbMachineLearningModel.txx b/Modules/Learning/LearningBase/include/otbMachineLearningModel.txx similarity index 100% rename from Modules/Learning/Supervised/include/otbMachineLearningModel.txx rename to Modules/Learning/LearningBase/include/otbMachineLearningModel.txx diff --git a/Modules/Learning/Supervised/include/otbMachineLearningModelFactoryBase.h b/Modules/Learning/LearningBase/include/otbMachineLearningModelFactoryBase.h similarity index 98% rename from Modules/Learning/Supervised/include/otbMachineLearningModelFactoryBase.h rename to Modules/Learning/LearningBase/include/otbMachineLearningModelFactoryBase.h index 029b73d49787f4f339843c066c64781626ff6f25..0ca61f2c37483d0735c146f9355b4a4a8d4c5d35 100644 --- a/Modules/Learning/Supervised/include/otbMachineLearningModelFactoryBase.h +++ b/Modules/Learning/LearningBase/include/otbMachineLearningModelFactoryBase.h @@ -32,8 +32,7 @@ namespace otb * This class intends to hold the static attributes that can not be * part of a template class (ld error). * - * - * \ingroup OTBSupervised + * \ingroup OTBLearningBase */ class OTBSupervised_EXPORT MachineLearningModelFactoryBase : public itk::Object { diff --git a/Modules/Learning/Supervised/include/otbSharkUtils.h b/Modules/Learning/LearningBase/include/otbSharkUtils.h similarity index 96% rename from Modules/Learning/Supervised/include/otbSharkUtils.h rename to Modules/Learning/LearningBase/include/otbSharkUtils.h index 4774965cfa581ec8d733d1e04aa33857e021b159..9efcf948bdbbfd7e9a672068677f029ac10c7d39 100644 --- a/Modules/Learning/Supervised/include/otbSharkUtils.h +++ b/Modules/Learning/LearningBase/include/otbSharkUtils.h @@ -21,14 +21,16 @@ #ifndef otbSharkUtils_h #define otbSharkUtils_h -#include "otb_shark.h" #include "itkMacro.h" #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wsign-compare" #endif -#include <shark/Data/Dataset.h> +#include "otb_shark.h" +#include "shark/Data/Dataset.h" #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic pop #endif diff --git a/Modules/Learning/LearningBase/otb-module.cmake b/Modules/Learning/LearningBase/otb-module.cmake index 6a94a9a00add529b41d2597acf248457356ea233..b4fab23bbaec200852575ff64dbb2424475542c6 100644 --- a/Modules/Learning/LearningBase/otb-module.cmake +++ b/Modules/Learning/LearningBase/otb-module.cmake @@ -25,6 +25,11 @@ otb_module(OTBLearningBase DEPENDS OTBCommon OTBITK + OTBImageIO + OTBImageBase + + OPTIONAL_DEPENDS + OTBShark TEST_DEPENDS OTBTestKernel diff --git a/Modules/Learning/Supervised/include/otbKNearestNeighborsMachineLearningModel.txx b/Modules/Learning/Supervised/include/otbKNearestNeighborsMachineLearningModel.txx index 9ed1a25ddd076191852388ad7624036f74c77991..3b6dc52a25674819aff7ddb715e2be4b964c0c38 100644 --- a/Modules/Learning/Supervised/include/otbKNearestNeighborsMachineLearningModel.txx +++ b/Modules/Learning/Supervised/include/otbKNearestNeighborsMachineLearningModel.txx @@ -243,11 +243,21 @@ KNearestNeighborsMachineLearningModel<TInputValue,TTargetValue> //first line is the K parameter of this algorithm. std::string line; std::getline(ifs, line); + std::istringstream iss(line); + if( line.find( "K" ) == std::string::npos ) + { + itkExceptionMacro( <<"Could not read file "<<filename ); + } std::string::size_type pos = line.find_first_of("=", 0); std::string::size_type nextpos = line.find_first_of(" \n\r", pos+1); this->SetK(boost::lexical_cast<int>(line.substr(pos+1, nextpos-pos-1))); + //second line is the IsRegression parameter std::getline(ifs, line); + if( line.find( "IsRegression" ) == std::string::npos ) + { + itkExceptionMacro( <<"Could not read file "<<filename ); + } pos = line.find_first_of("=", 0); nextpos = line.find_first_of(" \n\r", pos+1); this->SetRegressionMode(boost::lexical_cast<bool>(line.substr(pos+1, nextpos-pos-1))); diff --git a/Modules/Learning/Supervised/include/otbMachineLearningModelFactory.txx b/Modules/Learning/Supervised/include/otbMachineLearningModelFactory.txx index 51d136a1ea3b8ad021c13ad04f7df1fa3cf83da0..760096feafeada28f0328d8a6fced9e3a7cf9397 100644 --- a/Modules/Learning/Supervised/include/otbMachineLearningModelFactory.txx +++ b/Modules/Learning/Supervised/include/otbMachineLearningModelFactory.txx @@ -43,6 +43,7 @@ #ifdef OTB_USE_SHARK #include "otbSharkRandomForestsMachineLearningModelFactory.h" +#include "otbSharkKMeansMachineLearningModelFactory.h" #endif #include "itkMutexLockHolder.h" @@ -110,6 +111,7 @@ MachineLearningModelFactory<TInputValue,TOutputValue> #ifdef OTB_USE_SHARK RegisterFactory(SharkRandomForestsMachineLearningModelFactory<TInputValue,TOutputValue>::New()); + RegisterFactory(SharkKMeansMachineLearningModelFactory<TInputValue,TOutputValue>::New()); #endif #ifdef OTB_USE_OPENCV @@ -168,6 +170,14 @@ MachineLearningModelFactory<TInputValue,TOutputValue> itk::ObjectFactoryBase::UnRegisterFactory(sharkRFFactory); continue; } + + SharkKMeansMachineLearningModelFactory<TInputValue,TOutputValue> *sharkKMeansFactory = + dynamic_cast<SharkKMeansMachineLearningModelFactory<TInputValue,TOutputValue> *>(*itFac); + if (sharkKMeansFactory) + { + itk::ObjectFactoryBase::UnRegisterFactory(sharkKMeansFactory); + continue; + } #endif #ifdef OTB_USE_OPENCV diff --git a/Modules/Learning/Supervised/include/otbSharkRandomForestsMachineLearningModel.h b/Modules/Learning/Supervised/include/otbSharkRandomForestsMachineLearningModel.h index 6efe3ecdf7d19220966904e7205115f52599382e..8d2c0c81233c5e5486ec8068f86298a2f7053ab8 100644 --- a/Modules/Learning/Supervised/include/otbSharkRandomForestsMachineLearningModel.h +++ b/Modules/Learning/Supervised/include/otbSharkRandomForestsMachineLearningModel.h @@ -21,8 +21,6 @@ #ifndef otbSharkRandomForestsMachineLearningModel_h #define otbSharkRandomForestsMachineLearningModel_h -#include "otb_shark.h" - #include "itkLightObject.h" #include "otbMachineLearningModel.h" @@ -36,6 +34,7 @@ #pragma GCC diagnostic ignored "-Wcast-align" #pragma GCC diagnostic ignored "-Wunknown-pragmas" #endif +#include "otb_shark.h" #include "shark/Algorithms/Trainers/RFTrainer.h" #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic pop diff --git a/Modules/Learning/Supervised/include/otbSharkRandomForestsMachineLearningModel.txx b/Modules/Learning/Supervised/include/otbSharkRandomForestsMachineLearningModel.txx index 6c90b26f3614398d5b567ad9be5df335722afca8..207f1abdd77e4b5cfffd9bc5d104c4b40232f853 100644 --- a/Modules/Learning/Supervised/include/otbSharkRandomForestsMachineLearningModel.txx +++ b/Modules/Learning/Supervised/include/otbSharkRandomForestsMachineLearningModel.txx @@ -198,6 +198,8 @@ SharkRandomForestsMachineLearningModel<TInputValue,TOutputValue> { itkExceptionMacro(<< "Error opening " << filename.c_str() ); } + // Add comment with model file name + ofs << "#" << m_RFModel.name() << std::endl; shark::TextOutArchive oa(ofs); m_RFModel.save(oa,0); } @@ -208,8 +210,25 @@ SharkRandomForestsMachineLearningModel<TInputValue,TOutputValue> ::Load(const std::string & filename, const std::string & itkNotUsed(name)) { std::ifstream ifs(filename.c_str()); - shark::TextInArchive ia(ifs); - m_RFModel.load(ia,0); + if( ifs.good() ) + { + // Check if the first line is a comment and verify the name of the model in this case. + std::string line; + getline( ifs, line ); + if( line.at( 0 ) == '#' ) + { + if( line.find( m_RFModel.name() ) == std::string::npos ) + itkExceptionMacro( "The model file : " + filename + " cannot be read." ); + } + else + { + // rewind if first line is not a comment + ifs.clear(); + ifs.seekg( 0, std::ios::beg ); + } + shark::TextInArchive ia( ifs ); + m_RFModel.load( ia, 0 ); + } } template <class TInputValue, class TOutputValue> diff --git a/Modules/Learning/Supervised/otb-module.cmake b/Modules/Learning/Supervised/otb-module.cmake index 32afd5841aeeb097608f5fc4ab3b4e772dac7c17..2c7c4ae51189889628694c0269c7a469a6d3205f 100644 --- a/Modules/Learning/Supervised/otb-module.cmake +++ b/Modules/Learning/Supervised/otb-module.cmake @@ -29,12 +29,14 @@ ENABLE_SHARED OTBCommon OTBITK OTBImageBase + OTBLearningBase + OTBUnsupervised OPTIONAL_DEPENDS OTBOpenCV OTBSVMLearning OTBShark - + TEST_DEPENDS OTBTestKernel OTBImageIO diff --git a/Modules/Learning/Supervised/test/otbMachineLearningModelCanRead.cxx b/Modules/Learning/Supervised/test/otbMachineLearningModelCanRead.cxx index df1eccdec10194e71256d0b5a3eb843b2f5eb7c8..49faadbebe6a450d48c1bf8c4e958f4b508fa65a 100644 --- a/Modules/Learning/Supervised/test/otbMachineLearningModelCanRead.cxx +++ b/Modules/Learning/Supervised/test/otbMachineLearningModelCanRead.cxx @@ -322,4 +322,5 @@ int otbSharkRFMachineLearningModelCanRead(int argc, char* argv[]) return EXIT_SUCCESS; } + #endif diff --git a/Modules/Learning/Supervised/test/otbSupervisedTestDriver.cxx b/Modules/Learning/Supervised/test/otbSupervisedTestDriver.cxx index 7ba47e427e27a004f7a94b00fa4ebd311592d087..d96021c156c46b0e7d72ccac06f0d9006c0eb8b5 100644 --- a/Modules/Learning/Supervised/test/otbSupervisedTestDriver.cxx +++ b/Modules/Learning/Supervised/test/otbSupervisedTestDriver.cxx @@ -92,7 +92,7 @@ void RegisterTests() REGISTER_TEST(otbSharkRFMachineLearningModelCanRead); REGISTER_TEST(otbSharkImageClassificationFilter); #endif - + REGISTER_TEST(otbImageClassificationFilterNew); REGISTER_TEST(otbImageClassificationFilter); } diff --git a/Modules/Learning/Supervised/test/otbTrainMachineLearningModel.cxx b/Modules/Learning/Supervised/test/otbTrainMachineLearningModel.cxx index 5fc1f79f1de5c6af752e37edad080555ae7e58e2..590fae174907817e0ed525cda4d56c1d3e78e2d0 100644 --- a/Modules/Learning/Supervised/test/otbTrainMachineLearningModel.cxx +++ b/Modules/Learning/Supervised/test/otbTrainMachineLearningModel.cxx @@ -1290,4 +1290,5 @@ int otbSharkRFMachineLearningModel(int argc, char * argv[]) return EXIT_SUCCESS; } + #endif diff --git a/Modules/Learning/Supervised/test/tests-shark.cmake b/Modules/Learning/Supervised/test/tests-shark.cmake index 2f7d6906c74b1be51e7f22260ef68bbb6309fd35..eeda8fff3f9f1413dcffe868c3fb5f8cb4f8f6d0 100644 --- a/Modules/Learning/Supervised/test/tests-shark.cmake +++ b/Modules/Learning/Supervised/test/tests-shark.cmake @@ -34,17 +34,17 @@ otb_add_test(NAME leTvSharkRFMachineLearningModelCanRead COMMAND otbSupervisedTe otb_add_test(NAME leTvSharkRFMachineLearningModelCanReadFail COMMAND otbSupervisedTestDriver otbSharkRFMachineLearningModelCanRead - ${INPUTDATA}/ROI_QB_MUL_4_svmModel.txt + ${INPUTDATA}/Classification/otbSharkImageClassificationFilter_KMeansmodel.txt ) set_property(TEST leTvSharkRFMachineLearningModelCanReadFail PROPERTY WILL_FAIL true) otb_add_test(NAME leTvImageClassificationFilterSharkFast COMMAND otbSupervisedTestDriver - --compare-n-images ${NOTOL} 2 + --compare-n-images ${NOTOL} 2 ${BASELINE}/leSharkImageClassificationFilterOutput.tif ${TEMP}/leSharkImageClassificationFilterOutput.tif ${BASELINE}/leSharkImageClassificationFilterConfidence.tif - ${TEMP}/leSharkImageClassificationFilterConfidence.tif + ${TEMP}/leSharkImageClassificationFilterConfidence.tif otbSharkImageClassificationFilter ${INPUTDATA}/Classification/QB_1_ortho.tif ${TEMP}/leSharkImageClassificationFilterOutput.tif @@ -66,11 +66,11 @@ otb_add_test(NAME leTvImageClassificationFilterSharkFast COMMAND otbSupervisedT # ) otb_add_test(NAME leTvImageClassificationFilterSharkFastMask COMMAND otbSupervisedTestDriver - --compare-n-images ${NOTOL} 2 + --compare-n-images ${NOTOL} 2 ${BASELINE}/leSharkImageClassificationFilterWithMaskOutput.tif ${TEMP}/leSharkImageClassificationFilterWithMaskOutput.tif ${BASELINE}/leSharkImageClassificationFilterWithMaskConfidence.tif - ${TEMP}/leSharkImageClassificationFilterWithMaskConfidence.tif + ${TEMP}/leSharkImageClassificationFilterWithMaskConfidence.tif otbSharkImageClassificationFilter ${INPUTDATA}/Classification/QB_1_ortho.tif ${TEMP}/leSharkImageClassificationFilterWithMaskOutput.tif @@ -79,3 +79,4 @@ otb_add_test(NAME leTvImageClassificationFilterSharkFastMask COMMAND otbSupervi ${INPUTDATA}/Classification/otbSharkImageClassificationFilter_RFmodel.txt ${INPUTDATA}/Classification/QB_1_ortho_mask.tif ) + diff --git a/Modules/Learning/Unsupervised/CMakeLists.txt b/Modules/Learning/Unsupervised/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e83c272cd617b09367dce57c8ed038757904d14c --- /dev/null +++ b/Modules/Learning/Unsupervised/CMakeLists.txt @@ -0,0 +1,4 @@ +project(OTBUnsupervised) + + +otb_module_impl() diff --git a/Modules/Learning/Unsupervised/include/otbSharkKMeansMachineLearningModel.h b/Modules/Learning/Unsupervised/include/otbSharkKMeansMachineLearningModel.h new file mode 100644 index 0000000000000000000000000000000000000000..3084b2503e8680fe36b60c0cf70b979bc7656cc9 --- /dev/null +++ b/Modules/Learning/Unsupervised/include/otbSharkKMeansMachineLearningModel.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2005-2017 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. + */ +#ifndef otbSharkKMeansMachineLearningModel_h +#define otbSharkKMeansMachineLearningModel_h + +#include "itkLightObject.h" +#include "otbMachineLearningModel.h" + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Woverloaded-virtual" +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wcast-align" +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#endif + +#include "otb_shark.h" +#include "shark/Models/Clustering/HardClusteringModel.h" +#include "shark/Models/Clustering/SoftClusteringModel.h" +#include "shark/Models/Clustering/Centroids.h" +#include "shark/Models/Clustering/ClusteringModel.h" +#include "shark/Algorithms/KMeans.h" + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +/** \class SharkKMeansMachineLearningModel + * \brief Shark version of Random Forests algorithm + * + * This is a specialization of MachineLearningModel class allowing to + * use Shark implementation of the Random Forests algorithm. + * + * It is noteworthy that training step is parallel. + * + * For more information, see + * http://image.diku.dk/shark/sphinx_pages/build/html/rest_sources/tutorials/algorithms/kmeans.html + * + * \ingroup OTBUnsupervised + */ +namespace otb +{ +template<class TInputValue, class TTargetValue> +class ITK_EXPORT SharkKMeansMachineLearningModel : public MachineLearningModel<TInputValue, TTargetValue> +{ +public: + /** Standard class typedefs. */ + typedef SharkKMeansMachineLearningModel Self; + typedef MachineLearningModel<TInputValue, TTargetValue> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + typedef typename Superclass::InputValueType InputValueType; + typedef typename Superclass::InputSampleType InputSampleType; + typedef typename Superclass::InputListSampleType InputListSampleType; + typedef typename Superclass::TargetValueType TargetValueType; + typedef typename Superclass::TargetSampleType TargetSampleType; + typedef typename Superclass::TargetListSampleType TargetListSampleType; + typedef typename Superclass::ConfidenceValueType ConfidenceValueType; + typedef typename Superclass::ConfidenceSampleType ConfidenceSampleType; + typedef typename Superclass::ConfidenceListSampleType ConfidenceListSampleType; + + + typedef shark::HardClusteringModel<shark::RealVector> ClusteringModelType; + typedef ClusteringModelType::OutputType ClusteringOutputType; + + /** Run-time type information (and related methods). */ + itkNewMacro( Self ); + itkTypeMacro( SharkKMeansMachineLearningModel, MachineLearningModel ); + + /** Train the machine learning model */ + virtual void Train() ITK_OVERRIDE; + + /** Save the model to file */ + virtual void Save(const std::string &filename, const std::string &name = "") ITK_OVERRIDE; + + /** Load the model from file */ + virtual void Load(const std::string &filename, const std::string &name = "") ITK_OVERRIDE; + + /**\name Classification model file compatibility tests */ + //@{ + /** Is the input model file readable and compatible with the corresponding classifier ? */ + virtual bool CanReadFile(const std::string &) ITK_OVERRIDE; + + /** Is the input model file writable and compatible with the corresponding classifier ? */ + virtual bool CanWriteFile(const std::string &) ITK_OVERRIDE; + //@} + + /** Get the maximum number of iteration for the kMeans algorithm.*/ + itkGetMacro( MaximumNumberOfIterations, unsigned ); + /** Set the maximum number of iteration for the kMeans algorithm.*/ + itkSetMacro( MaximumNumberOfIterations, unsigned ); + + /** Get the number of class for the kMeans algorithm.*/ + itkGetMacro( K, unsigned ); + /** Set the number of class for the kMeans algorithm.*/ + itkSetMacro( K, unsigned ); + + /** If true, normalized input data sample list */ + itkGetMacro( Normalized, bool ); + itkSetMacro( Normalized, bool ); + +protected: + /** Constructor */ + SharkKMeansMachineLearningModel(); + + /** Destructor */ + virtual ~SharkKMeansMachineLearningModel(); + + /** Predict values using the model */ + virtual TargetSampleType + DoPredict(const InputSampleType &input, ConfidenceValueType *quality = ITK_NULLPTR) const ITK_OVERRIDE; + + + virtual void DoPredictBatch(const InputListSampleType *, const unsigned int &startIndex, const unsigned int &size, + TargetListSampleType *, ConfidenceListSampleType * = ITK_NULLPTR) const ITK_OVERRIDE; + + template<typename DataType> + DataType NormalizeData(const DataType &data) const; + + /** PrintSelf method */ + void PrintSelf(std::ostream &os, itk::Indent indent) const; + +private: + SharkKMeansMachineLearningModel(const Self &); //purposely not implemented + void operator=(const Self &); //purposely not implemented + + // Parameters set by the user + bool m_Normalized; + unsigned int m_K; + unsigned int m_MaximumNumberOfIterations; + bool m_CanRead; + + + /** Centroids results form kMeans */ + shark::Centroids m_Centroids; + + + /** shark Model could be SoftClusteringModel or HardClusteringModel */ + boost::shared_ptr<ClusteringModelType> m_ClusteringModel; + +}; +} // end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION + +#include "otbSharkKMeansMachineLearningModel.txx" + +#endif + +#endif diff --git a/Modules/Learning/Unsupervised/include/otbSharkKMeansMachineLearningModel.txx b/Modules/Learning/Unsupervised/include/otbSharkKMeansMachineLearningModel.txx new file mode 100644 index 0000000000000000000000000000000000000000..267a676ae668a863928be6087146a1ca7dd61d6e --- /dev/null +++ b/Modules/Learning/Unsupervised/include/otbSharkKMeansMachineLearningModel.txx @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2005-2017 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. + */ +#ifndef otbSharkKMeansMachineLearningModel_txx +#define otbSharkKMeansMachineLearningModel_txx + +#include <fstream> +#include "itkMacro.h" +#include "otbSharkKMeansMachineLearningModel.h" + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Woverloaded-virtual" +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#endif + +#include "otb_shark.h" +#include "otbSharkUtils.h" +#include "shark/Algorithms/Trainers/NormalizeComponentsUnitVariance.h" //normalize +#include "shark/Algorithms/KMeans.h" //k-means algorithm +#include "shark/Models/Clustering/HardClusteringModel.h" +#include "shark/Models/Clustering/SoftClusteringModel.h" +#include "shark/Algorithms/Trainers/NormalizeComponentsUnitVariance.h" + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + + + +namespace otb +{ +template<class TInputValue, class TOutputValue> +SharkKMeansMachineLearningModel<TInputValue, TOutputValue> +::SharkKMeansMachineLearningModel() : + m_Normalized( false ), m_K(2), m_MaximumNumberOfIterations( 10 ) +{ + // Default set HardClusteringModel + m_ClusteringModel = boost::shared_ptr<ClusteringModelType>(new ClusteringModelType( &m_Centroids )); +} + + +template<class TInputValue, class TOutputValue> +SharkKMeansMachineLearningModel<TInputValue, TOutputValue> +::~SharkKMeansMachineLearningModel() +{ +} + +/** Train the machine learning model */ +template<class TInputValue, class TOutputValue> +void +SharkKMeansMachineLearningModel<TInputValue, TOutputValue> +::Train() +{ + // Parse input data and convert to Shark Data + std::vector<shark::RealVector> vector_data; + otb::Shark::ListSampleToSharkVector( this->GetInputListSample(), vector_data ); + shark::Data<shark::RealVector> data = shark::createDataFromRange( vector_data ); + + // Normalized input value if necessary + if( m_Normalized ) + data = NormalizeData( data ); + + // Use a Hard Clustering Model for classification + shark::kMeans( data, m_K, m_Centroids, m_MaximumNumberOfIterations ); + m_ClusteringModel = boost::shared_ptr<ClusteringModelType>(new ClusteringModelType( &m_Centroids )); +} + +template<class TInputValue, class TOutputValue> +template<typename DataType> +DataType +SharkKMeansMachineLearningModel<TInputValue, TOutputValue> +::NormalizeData(const DataType &data) const +{ + shark::Normalizer<> normalizer; + shark::NormalizeComponentsUnitVariance<> normalizingTrainer( true );//zero mean + normalizingTrainer.train( normalizer, data ); + return normalizer( data ); +} + +template<class TInputValue, class TOutputValue> +typename SharkKMeansMachineLearningModel<TInputValue, TOutputValue> +::TargetSampleType +SharkKMeansMachineLearningModel<TInputValue, TOutputValue> +::DoPredict(const InputSampleType &value, ConfidenceValueType *quality) const +{ + shark::RealVector data( value.Size()); + for( size_t i = 0; i < value.Size(); i++ ) + { + data.push_back( value[i] ); + } + + // Change quality measurement only if SoftClustering or other clustering method is used. + if( quality != ITK_NULLPTR ) + { + //unsigned int probas = (*m_ClusteringModel)( data ); + ( *quality ) = ConfidenceValueType( 1.); + } + + TargetSampleType target; + ClusteringOutputType predictedValue = (*m_ClusteringModel)( data ); + target[0] = static_cast<TOutputValue>(predictedValue); + return target; +} + +template<class TInputValue, class TOutputValue> +void +SharkKMeansMachineLearningModel<TInputValue, TOutputValue> +::DoPredictBatch(const InputListSampleType *input, + const unsigned int &startIndex, + const unsigned int &size, + TargetListSampleType *targets, + ConfidenceListSampleType *quality) const +{ + + // Perform check on input values + assert( input != ITK_NULLPTR ); + assert( targets != ITK_NULLPTR ); + + // input list sample and target list sample should be initialized and without + assert( input->Size() == targets->Size() && "Input sample list and target label list do not have the same size." ); + assert( ( ( quality == ITK_NULLPTR ) || ( quality->Size() == input->Size() ) ) && + "Quality samples list is not null and does not have the same size as input samples list" ); + if( startIndex + size > input->Size() ) + { + itkExceptionMacro( + <<"requested range ["<<startIndex<<", "<<startIndex+size<<"[ partially outside input sample list range.[0,"<<input->Size()<<"[" ); + } + + // Convert input list of features to shark data format + std::vector<shark::RealVector> features; + otb::Shark::ListSampleRangeToSharkVector( input, features, startIndex, size ); + shark::Data<shark::RealVector> inputSamples = shark::createDataFromRange( features ); + + shark::Data<ClusteringOutputType> clusters; + try + { + clusters = ( *m_ClusteringModel )( inputSamples ); + } + catch( ... ) + { + itkExceptionMacro( "Failed to run clustering classification. " + "The number of features of input samples and the model could differ."); + } + + unsigned int id = startIndex; + for( const auto &p : clusters.elements() ) + { + TargetSampleType target; + target[0] = static_cast<TOutputValue>(p); + targets->SetMeasurementVector( id, target ); + ++id; + } + + // Change quality measurement only if SoftClustering or other clustering method is used. + if( quality != ITK_NULLPTR ) + { + for( unsigned int qid = startIndex; qid < size; ++qid ) + { + quality->SetMeasurementVector( qid, static_cast<ConfidenceValueType>(1.) ); + } + } +} + + +template<class TInputValue, class TOutputValue> +void +SharkKMeansMachineLearningModel<TInputValue, TOutputValue> +::Save(const std::string &filename, const std::string & itkNotUsed( name )) +{ + std::ofstream ofs( filename.c_str()); + if( !ofs ) + { + itkExceptionMacro( << "Error opening " << filename.c_str()); + } + ofs << "#" << m_ClusteringModel->name() << std::endl; + shark::TextOutArchive oa( ofs ); + m_ClusteringModel->save( oa, 1 ); +} + +template<class TInputValue, class TOutputValue> +void +SharkKMeansMachineLearningModel<TInputValue, TOutputValue> +::Load(const std::string &filename, const std::string & itkNotUsed( name )) +{ + m_CanRead = false; + std::ifstream ifs( filename.c_str()); + if(ifs.good()) + { + // Check if first line contains model name + std::string line; + std::getline(ifs, line); + m_CanRead = line.find(m_ClusteringModel->name()) != std::string::npos; + } + + if(!m_CanRead) + return; + + shark::TextInArchive ia( ifs ); + m_ClusteringModel->load( ia, 0 ); + ifs.close(); +} + +template<class TInputValue, class TOutputValue> +bool +SharkKMeansMachineLearningModel<TInputValue, TOutputValue> +::CanReadFile(const std::string &file) +{ + try + { + m_CanRead = true; + this->Load( file ); + } + catch( ... ) + { + return false; + } + return m_CanRead; +} + +template<class TInputValue, class TOutputValue> +bool +SharkKMeansMachineLearningModel<TInputValue, TOutputValue> +::CanWriteFile(const std::string & itkNotUsed( file )) +{ + return true; +} + +template<class TInputValue, class TOutputValue> +void +SharkKMeansMachineLearningModel<TInputValue, TOutputValue> +::PrintSelf(std::ostream &os, itk::Indent indent) const +{ + // Call superclass implementation + Superclass::PrintSelf( os, indent ); +} +} //end namespace otb + +#endif diff --git a/Modules/Learning/Unsupervised/include/otbSharkKMeansMachineLearningModelFactory.h b/Modules/Learning/Unsupervised/include/otbSharkKMeansMachineLearningModelFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..a072d5d71921f24cc483e0193d3f0d04a4ab41d2 --- /dev/null +++ b/Modules/Learning/Unsupervised/include/otbSharkKMeansMachineLearningModelFactory.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005-2017 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. + */ +#ifndef otbSharkKMeansMachineLearningModelFactory_h +#define otbSharkKMeansMachineLearningModelFactory_h + +#include "itkObjectFactoryBase.h" +#include "itkImageIOBase.h" + +namespace otb +{ +/** \class SharkKMeansMachineLearningModelFactory + * \brief Creation of an instance of a SharkKMeansMachineLearningModel object using the object factory + * + * \ingroup OTBUnsupervised + */ +template <class TInputValue, class TTargetValue> +class ITK_EXPORT SharkKMeansMachineLearningModelFactory : public itk::ObjectFactoryBase +{ +public: + /** Standard class typedefs. */ + typedef SharkKMeansMachineLearningModelFactory Self; + typedef itk::ObjectFactoryBase Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Class methods used to interface with the registered factories. */ + virtual const char* GetITKSourceVersion(void) const; + virtual const char* GetDescription(void) const; + + /** Method for class instantiation. */ + itkFactorylessNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(SharkKMeansMachineLearningModelFactory, itk::ObjectFactoryBase); + + /** Register one factory of this type */ + static void RegisterOneFactory(void) + { + Pointer KMeansFactory = SharkKMeansMachineLearningModelFactory::New(); + itk::ObjectFactoryBase::RegisterFactory(KMeansFactory); + } + +protected: + SharkKMeansMachineLearningModelFactory(); + virtual ~SharkKMeansMachineLearningModelFactory(); + +private: + SharkKMeansMachineLearningModelFactory(const Self &); //purposely not implemented + void operator =(const Self&); //purposely not implemented + +}; + +} // end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbSharkKMeansMachineLearningModelFactory.txx" +#endif + +#endif diff --git a/Modules/Learning/Unsupervised/include/otbSharkKMeansMachineLearningModelFactory.txx b/Modules/Learning/Unsupervised/include/otbSharkKMeansMachineLearningModelFactory.txx new file mode 100644 index 0000000000000000000000000000000000000000..a4fe5584e04249875de1193e365fd888a43cfa07 --- /dev/null +++ b/Modules/Learning/Unsupervised/include/otbSharkKMeansMachineLearningModelFactory.txx @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2005-2017 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. + */ +#ifndef otbSharkKMeansMachineLearningModelFactory_txx +#define otbSharkKMeansMachineLearningModelFactory_txx + +#include "otbSharkKMeansMachineLearningModelFactory.h" + +#include "itkCreateObjectFunction.h" +#include "otbSharkKMeansMachineLearningModel.h" +#include "itkVersion.h" + +namespace otb +{ + +template <class TInputValue, class TOutputValue> +SharkKMeansMachineLearningModelFactory<TInputValue,TOutputValue> +::SharkKMeansMachineLearningModelFactory() +{ + + std::string classOverride = std::string("otbMachineLearningModel"); + std::string subclass = std::string("otbSharkKMeansMachineLearningModel"); + + this->RegisterOverride(classOverride.c_str(), + subclass.c_str(), + "Shark KMeans Machine Learning Model", + 1, + itk::CreateObjectFunction<SharkKMeansMachineLearningModel<TInputValue,TOutputValue> >::New()); +} + +template <class TInputValue, class TOutputValue> +SharkKMeansMachineLearningModelFactory<TInputValue,TOutputValue> +::~SharkKMeansMachineLearningModelFactory() +{ +} + +template <class TInputValue, class TOutputValue> +const char* +SharkKMeansMachineLearningModelFactory<TInputValue,TOutputValue> +::GetITKSourceVersion(void) const +{ + return ITK_SOURCE_VERSION; +} + +template <class TInputValue, class TOutputValue> +const char* +SharkKMeansMachineLearningModelFactory<TInputValue,TOutputValue> +::GetDescription() const +{ + return "Shark KMeans unsupervised machine learning model factory"; +} + +} // end namespace otb + +#endif diff --git a/Modules/Learning/Unsupervised/otb-module.cmake b/Modules/Learning/Unsupervised/otb-module.cmake new file mode 100644 index 0000000000000000000000000000000000000000..edaf52212e6bd849bf0b385bd3657bbc27b072c6 --- /dev/null +++ b/Modules/Learning/Unsupervised/otb-module.cmake @@ -0,0 +1,21 @@ +set(DOCUMENTATION "This module provides the Orfeo Toolbox unsupervised +classification and regression framework, currently based on Shark") + +otb_module(OTBUnsupervised + DEPENDS + OTBCommon + OTBITK + OTBImageBase + OTBLearningBase + + OPTIONAL_DEPENDS + OTBShark + + TEST_DEPENDS + OTBTestKernel + OTBImageIO + OTBImageBase + + DESCRIPTION + "${DOCUMENTATION}" + ) diff --git a/Modules/Learning/Unsupervised/test/CMakeLists.txt b/Modules/Learning/Unsupervised/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..57cdb01bd6d73755758b1ec3ba1110e93a2adc36 --- /dev/null +++ b/Modules/Learning/Unsupervised/test/CMakeLists.txt @@ -0,0 +1,17 @@ +otb_module_test() +set(OTBUnsupervisedTests + otbUnsupervisedTestDriver.cxx + otbMachineLearningUnsupervisedModelCanRead.cxx + otbTrainMachineLearningUnsupervisedModel.cxx + ) + +# Tests Declaration + +if(OTB_USE_SHARK) + set(OTBUnsupervisedTests ${OTBUnsupervisedTests} otbSharkUnsupervisedImageClassificationFilter.cxx) + include(tests-shark.cmake) +endif() + +add_executable(otbUnsupervisedTestDriver ${OTBUnsupervisedTests}) +target_link_libraries(otbUnsupervisedTestDriver ${OTBUnsupervised-Test_LIBRARIES}) +otb_module_target_label(otbUnsupervisedTestDriver) diff --git a/Modules/Learning/Unsupervised/test/otbMachineLearningUnsupervisedModelCanRead.cxx b/Modules/Learning/Unsupervised/test/otbMachineLearningUnsupervisedModelCanRead.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6856f0d0728327c26df9873af3afa016789c6d10 --- /dev/null +++ b/Modules/Learning/Unsupervised/test/otbMachineLearningUnsupervisedModelCanRead.cxx @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2005-2017 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 <iostream> + +#include <otbConfigure.h> +#include <otbMachineLearningModel.h> + +typedef otb::MachineLearningModel<float,short> MachineLearningModelType; +typedef MachineLearningModelType::InputValueType InputValueType; +typedef MachineLearningModelType::InputSampleType InputSampleType; +typedef MachineLearningModelType::InputListSampleType InputListSampleType; +typedef MachineLearningModelType::TargetValueType TargetValueType; +typedef MachineLearningModelType::TargetSampleType TargetSampleType; +typedef MachineLearningModelType::TargetListSampleType TargetListSampleType; + +#ifdef OTB_USE_SHARK + +#include "otbSharkKMeansMachineLearningModel.h" + +int otbSharkKMeansMachineLearningModelCanRead(int argc, char *argv[]) +{ + if( argc != 2 ) + { + std::cerr << "Usage: " << argv[0] << "<model>" << std::endl; + std::cerr << "Called here with " << argc << " arguments\n"; + for( int i = 1; i < argc; ++i ) + { + std::cerr << " - " << argv[i] << "\n"; + } + return EXIT_FAILURE; + } + std::string filename( argv[1] ); + typedef otb::SharkKMeansMachineLearningModel<InputValueType, TargetValueType> KMType; + KMType::Pointer classifier = KMType::New(); + bool lCanRead = classifier->CanReadFile( filename ); + if( !lCanRead ) + { + std::cerr << "Error otb::SharkKMeansMachineLearningModel : impossible to open the file " << filename << "." + << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +#endif diff --git a/Modules/Learning/Unsupervised/test/otbSharkUnsupervisedImageClassificationFilter.cxx b/Modules/Learning/Unsupervised/test/otbSharkUnsupervisedImageClassificationFilter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..7c101f7e2eb4ab7b6ec1d083c793b84523d4b25e --- /dev/null +++ b/Modules/Learning/Unsupervised/test/otbSharkUnsupervisedImageClassificationFilter.cxx @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2005-2017 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 "otbVectorImage.h" +#include "otbImageFileReader.h" +#include "otbImageFileWriter.h" +#include "otbImageClassificationFilter.h" +#include "otbSharkKMeansMachineLearningModelFactory.h" + +#include <random> +#include <chrono> + + +const unsigned int Dimension = 2; +typedef float PixelType; +typedef unsigned short LabeledPixelType; + +typedef otb::VectorImage<PixelType, Dimension> ImageType; +typedef otb::Image<LabeledPixelType, Dimension> LabeledImageType; +typedef otb::ImageClassificationFilter<ImageType, LabeledImageType> ClassificationFilterType; +typedef ClassificationFilterType::ModelType ModelType; +typedef ClassificationFilterType::ValueType ValueType; +typedef ClassificationFilterType::LabelType LabelType; +typedef otb::SharkKMeansMachineLearningModelFactory<ValueType, LabelType> MachineLearningModelFactoryType; +typedef otb::ImageFileReader<ImageType> ReaderType; +typedef otb::ImageFileReader<LabeledImageType> MaskReaderType; +typedef otb::ImageFileWriter<LabeledImageType> WriterType; + +typedef otb::SharkKMeansMachineLearningModel<PixelType,short unsigned int> MachineLearningModelType; +typedef MachineLearningModelType::InputValueType LocalInputValueType; +typedef MachineLearningModelType::InputSampleType LocalInputSampleType; +typedef MachineLearningModelType::InputListSampleType LocalInputListSampleType; +typedef MachineLearningModelType::TargetValueType LocalTargetValueType; +typedef MachineLearningModelType::TargetSampleType LocalTargetSampleType; +typedef MachineLearningModelType::TargetListSampleType LocalTargetListSampleType; + +void generateSamples(unsigned int num_classes, unsigned int num_samples, + unsigned int num_features, + LocalInputListSampleType * samples, + LocalTargetListSampleType * labels) +{ + std::default_random_engine randomEngine; + std::uniform_int_distribution<int> label_distribution(1,num_classes); + std::uniform_int_distribution<int> feat_distribution(0,256); + for(size_t scount=0; scount<num_samples; ++scount) + { + LabeledPixelType label = label_distribution(randomEngine); + LocalInputSampleType sample(num_features); + for(unsigned int i=0; i<num_features; ++i) + sample[i]= feat_distribution(randomEngine); + samples->SetMeasurementVectorSize(num_features); + samples->PushBack(sample); + labels->PushBack(label); + } +} + +void buildModel(unsigned int num_classes, unsigned int num_samples, + unsigned int num_features, std::string modelfname) +{ + LocalInputListSampleType::Pointer samples = LocalInputListSampleType::New(); + LocalTargetListSampleType::Pointer labels = LocalTargetListSampleType::New(); + + std::cout << "Sample generation\n"; + generateSamples(num_classes, num_samples, num_features, samples, labels); + + MachineLearningModelType::Pointer classifier = MachineLearningModelType::New(); + classifier->SetInputListSample(samples); + classifier->SetTargetListSample(labels); + classifier->SetRegressionMode(false); + classifier->SetK(3); + + std::cout << "Training\n"; + using TimeT = std::chrono::milliseconds; + auto start = std::chrono::system_clock::now(); + classifier->Train(); + auto duration = std::chrono::duration_cast< TimeT> + (std::chrono::system_clock::now() - start); + auto elapsed = duration.count(); + std::cout << "Training took " << elapsed << " ms\n"; + classifier->Save(modelfname); +} + +int otbSharkUnsupervisedImageClassificationFilter(int argc, char * argv[]) +{ + if(argc<5 || argc>7) + { + std::cout << "Usage: input_image output_image output_confidence batchmode [in_model_name] [mask_name]\n"; + } + std::string imfname = argv[1]; + std::string outfname = argv[2]; + std::string conffname = argv[3]; + bool batch = (std::string(argv[4])=="1"); + std::string modelfname = "/tmp/rf_model.txt"; + std::string maskfname{}; + + MaskReaderType::Pointer mask_reader = MaskReaderType::New(); + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(imfname); + reader->UpdateOutputInformation(); + + auto num_features = reader->GetOutput()->GetNumberOfComponentsPerPixel(); + + std::cout << "Image has " << num_features << " bands\n"; + + if(argc>5) + { + modelfname = argv[5]; + } + else + { + buildModel(3, 1000, num_features, modelfname); + } + + ClassificationFilterType::Pointer filter = ClassificationFilterType::New(); + + MachineLearningModelType::Pointer model = MachineLearningModelType::New(); + if(!model->CanReadFile(modelfname)) + { + std::cerr << "Unable to read the model : " << modelfname << "\n"; + return EXIT_FAILURE; + } + + filter->SetModel(model); + filter->SetInput(reader->GetOutput()); + if(argc==7) + { + maskfname = argv[6]; + mask_reader->SetFileName(maskfname); + filter->SetInputMask(mask_reader->GetOutput()); + } + + WriterType::Pointer writer = WriterType::New(); + writer->SetInput(filter->GetOutput()); + writer->SetFileName(outfname); + std::cout << "Classification\n"; + filter->SetBatchMode(batch); + filter->SetUseConfidenceMap(true); + using TimeT = std::chrono::milliseconds; + auto start = std::chrono::system_clock::now(); + writer->Update(); + auto duration = std::chrono::duration_cast< TimeT> + (std::chrono::system_clock::now() - start); + auto elapsed = duration.count(); + std::cout << "Classification took " << elapsed << " ms\n"; + + auto confWriter = otb::ImageFileWriter<ClassificationFilterType::ConfidenceImageType>::New(); + confWriter->SetInput(filter->GetOutputConfidence()); + confWriter->SetFileName(conffname); + confWriter->Update(); + + return EXIT_SUCCESS; +} diff --git a/Modules/Learning/Unsupervised/test/otbTrainMachineLearningUnsupervisedModel.cxx b/Modules/Learning/Unsupervised/test/otbTrainMachineLearningUnsupervisedModel.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a0805c29fb38defb049a9588a26e10167cb5920b --- /dev/null +++ b/Modules/Learning/Unsupervised/test/otbTrainMachineLearningUnsupervisedModel.cxx @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2005-2017 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 <iostream> + +#include <otbConfigure.h> +#include <otbMachineLearningModel.h> + +typedef otb::MachineLearningModel<float,short> MachineLearningModelType; +typedef MachineLearningModelType::InputValueType InputValueType; +typedef MachineLearningModelType::InputSampleType InputSampleType; +typedef MachineLearningModelType::InputListSampleType InputListSampleType; +typedef MachineLearningModelType::TargetValueType TargetValueType; +typedef MachineLearningModelType::TargetSampleType TargetSampleType; +typedef MachineLearningModelType::TargetListSampleType TargetListSampleType; + +typedef otb::MachineLearningModel<float,float> MachineLearningModelRegressionType; +typedef MachineLearningModelRegressionType::InputValueType InputValueRegressionType; +typedef MachineLearningModelRegressionType::InputSampleType InputSampleRegressionType; +typedef MachineLearningModelRegressionType::InputListSampleType InputListSampleRegressionType; +typedef MachineLearningModelRegressionType::TargetValueType TargetValueRegressionType; +typedef MachineLearningModelRegressionType::TargetSampleType TargetSampleRegressionType; +typedef MachineLearningModelRegressionType::TargetListSampleType TargetListSampleRegressionType; + + +#ifdef OTB_USE_SHARK +#include "otbSharkKMeansMachineLearningModel.h" +#include "otb_boost_string_header.h" +#include <chrono> + +bool SharkReadDataFile(const std::string & infname, InputListSampleType * samples, TargetListSampleType * labels) +{ + std::ifstream ifs(infname.c_str()); + + if(!ifs) + { + std::cout<<"Could not read file "<<infname<<std::endl; + return false; + } + + unsigned int nbfeatures = 0; + + std::string line; + while (std::getline(ifs, line)) + { + boost::algorithm::trim(line); + + if(nbfeatures == 0) + { + nbfeatures = std::count(line.begin(),line.end(),' '); + } + + if(line.size()>1) + { + InputSampleType sample(nbfeatures); + sample.Fill(0); + + std::string::size_type pos = line.find_first_of(" ", 0); + + // Parse label + TargetSampleType label; + label[0] = std::stoi(line.substr(0, pos).c_str()); + + bool endOfLine = false; + unsigned int id = 0; + + while(!endOfLine) + { + std::string::size_type nextpos = line.find_first_of(" ", pos+1); + + if(pos == std::string::npos) + { + endOfLine = true; + nextpos = line.size()-1; + } + else + { + std::string feature = line.substr(pos,nextpos-pos); + std::string::size_type semicolonpos = feature.find_first_of(":"); + id = std::stoi(feature.substr(0,semicolonpos).c_str()); + sample[id - 1] = atof(feature.substr(semicolonpos+1,feature.size()-semicolonpos).c_str()); + pos = nextpos; + } + + } + samples->SetMeasurementVectorSize(itk::NumericTraits<InputSampleType>::GetLength(sample)); + samples->PushBack(sample); + labels->PushBack(label); + } + } + + //std::cout<<"Retrieved "<<samples->Size()<<" samples"<<std::endl; + ifs.close(); + return true; +} + + +int otbSharkKMeansMachineLearningModelNew(int itkNotUsed( argc ), char *itkNotUsed( argv )[]) +{ + typedef otb::SharkKMeansMachineLearningModel<InputValueType, TargetValueType> SharkRFType; + SharkRFType::Pointer classifier = SharkRFType::New(); + return EXIT_SUCCESS; +} + +int otbSharkKMeansMachineLearningModelTrain(int argc, char *argv[]) +{ + if( argc != 3 ) + { + std::cout << "Wrong number of arguments " << std::endl; + std::cout << "Usage : sample file, output file " << std::endl; + return EXIT_FAILURE; + } + + typedef otb::SharkKMeansMachineLearningModel<InputValueType, TargetValueType> KMeansType; + InputListSampleType::Pointer samples = InputListSampleType::New(); + TargetListSampleType::Pointer labels = TargetListSampleType::New(); + + if( !SharkReadDataFile( argv[1], samples, labels ) ) + { + std::cout << "Failed to read samples file " << argv[1] << std::endl; + return EXIT_FAILURE; + } + + KMeansType::Pointer classifier = KMeansType::New(); + classifier->SetInputListSample( samples ); + classifier->SetTargetListSample( labels ); + classifier->SetRegressionMode( false ); + classifier->SetK( 3 ); + classifier->SetMaximumNumberOfIterations( 0 ); + std::cout << "Train\n"; + classifier->Train(); + std::cout << "Save\n"; + classifier->Save( argv[2] ); + + return EXIT_SUCCESS; +} + + +int otbSharkKMeansMachineLearningModelPredict(int argc, char *argv[]) +{ + if( argc != 3 ) + { + std::cout << "Wrong number of arguments " << std::endl; + std::cout << "Usage : sample file, input model file " << std::endl; + return EXIT_FAILURE; + } + + typedef otb::SharkKMeansMachineLearningModel<InputValueType, TargetValueType> KMeansType; + InputListSampleType::Pointer samples = InputListSampleType::New(); + TargetListSampleType::Pointer labels = TargetListSampleType::New(); + + if( !SharkReadDataFile( argv[1], samples, labels ) ) + { + std::cout << "Failed to read samples file " << argv[1] << std::endl; + return EXIT_FAILURE; + } + + KMeansType::Pointer classifier = KMeansType::New(); + std::cout << "Load\n"; + if(!classifier->CanReadFile(argv[2])) + { + std::cerr << "Unable to read model file : " << argv[2] << std::endl; + return EXIT_FAILURE; + } + classifier->Load( argv[2] ); + auto start = std::chrono::system_clock::now(); + classifier->SetInputListSample( samples ); + classifier->SetTargetListSample( labels ); + std::cout << "Predict loaded\n"; + classifier->PredictBatch( samples, NULL ); + using TimeT = std::chrono::milliseconds; + auto duration = std::chrono::duration_cast<TimeT>( std::chrono::system_clock::now() - start ); + auto elapsed = duration.count(); + std::cout << "PredictAll took " << elapsed << " ms\n"; + + return EXIT_SUCCESS; +} +#endif diff --git a/Modules/Learning/Unsupervised/test/otbUnsupervisedTestDriver.cxx b/Modules/Learning/Unsupervised/test/otbUnsupervisedTestDriver.cxx new file mode 100644 index 0000000000000000000000000000000000000000..30a7194f52fb61c6370693fcd8b455b1f77ac7a2 --- /dev/null +++ b/Modules/Learning/Unsupervised/test/otbUnsupervisedTestDriver.cxx @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2005-2017 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 "otbTestMain.h" +void RegisterTests() +{ +#ifdef OTB_USE_SHARK + REGISTER_TEST(otbSharkKMeansMachineLearningModelCanRead); + REGISTER_TEST(otbSharkKMeansMachineLearningModelNew); + REGISTER_TEST(otbSharkKMeansMachineLearningModelTrain); + REGISTER_TEST(otbSharkKMeansMachineLearningModelPredict); + REGISTER_TEST(otbSharkUnsupervisedImageClassificationFilter); +#endif +} diff --git a/Modules/Learning/Unsupervised/test/tests-shark.cmake b/Modules/Learning/Unsupervised/test/tests-shark.cmake new file mode 100644 index 0000000000000000000000000000000000000000..df61cb46479f9922e3355441458a1e261879c40c --- /dev/null +++ b/Modules/Learning/Unsupervised/test/tests-shark.cmake @@ -0,0 +1,58 @@ +# kMeans Shark related tests + +otb_add_test(NAME leTvSharkKMeansMachineLearningModelNew COMMAND otbUnsupervisedTestDriver + otbSharkKMeansMachineLearningModelNew + ) + + +otb_add_test(NAME leTvSharkKMeansMachineLearningModel COMMAND otbUnsupervisedTestDriver + otbSharkKMeansMachineLearningModelTrain + ${INPUTDATA}/letter.scale + ${TEMP}/shark_km_model.txt + ) + +otb_add_test(NAME otbSharkKMeansMachineLearningModelPredict COMMAND otbUnsupervisedTestDriver + otbSharkKMeansMachineLearningModelPredict + ${INPUTDATA}/letter.scale + ${INPUTDATA}/Classification/shark_km_model.txt + ) + +otb_add_test(NAME leTvSharkKMeansMachineLearningModelCanRead COMMAND otbUnsupervisedTestDriver + otbSharkKMeansMachineLearningModelCanRead + ${INPUTDATA}/Classification/otbSharkImageClassificationFilter_KMeansmodel.txt + ) + +otb_add_test(NAME leTvSharkKMeansMachineLearningModelCanReadFail COMMAND otbUnsupervisedTestDriver + otbSharkKMeansMachineLearningModelCanRead + ${INPUTDATA}/Classification/otbSharkImageClassificationFilter_RFmodel.txt + ) + +set_property(TEST leTvSharkKMeansMachineLearningModelCanReadFail PROPERTY WILL_FAIL true) + + + +otb_add_test(NAME leTvImageClassificationFilterSharkKMeans COMMAND otbUnsupervisedTestDriver + --compare-n-images ${NOTOL} 1 + ${BASELINE}/leSharkUnsupervisedImageClassificationFilterOutput.tif + ${TEMP}/leSharkUnsupervisedImageClassificationFilterOutput.tif + otbSharkUnsupervisedImageClassificationFilter + ${INPUTDATA}/Classification/QB_1_ortho.tif + ${TEMP}/leSharkUnsupervisedImageClassificationFilterOutput.tif + ${TEMP}/leSharkUnsupervisedImageClassificationFilterConfidence.tif + 1 + ${INPUTDATA}/Classification/otbSharkImageClassificationFilter_KMeansmodel.txt + ) + + +otb_add_test(NAME leTvImageClassificationFilterSharkKMeansMask COMMAND otbUnsupervisedTestDriver + --compare-n-images ${NOTOL} 1 + ${BASELINE}/leSharkUnsupervisedImageClassificationFilterWithMaskOutput.tif + ${TEMP}/leSharkUnsupervisedImageClassificationFilterWithMaskOutput.tif + otbSharkUnsupervisedImageClassificationFilter + ${INPUTDATA}/Classification/QB_1_ortho.tif + ${TEMP}/leSharkUnsupervisedImageClassificationFilterWithMaskOutput.tif + ${TEMP}/leSharkUnsupervisedImageClassificationFilterWithMaskConfidence.tif + 1 + ${INPUTDATA}/Classification/otbSharkImageClassificationFilter_KMeansmodel.txt + ${INPUTDATA}/Classification/QB_1_ortho_mask.tif + )