diff --git a/CMake/FindOpenCV.cmake b/CMake/FindOpenCV.cmake index e59d465ea358c57ab9f105d6185cbb33699433b3..f14c205df429858c301f41a4c5d39b4126954a8e 100644 --- a/CMake/FindOpenCV.cmake +++ b/CMake/FindOpenCV.cmake @@ -30,6 +30,8 @@ if(OpenCV_DIR) opencv_INCLUDE_DIR opencv/cv.h PATHS "${OPENCV_SEARCH_PATH}" + #no additional paths are added to the search if OpenCV_DIR + NO_DEFAULT_PATH PATH_SUFFIXES "include" DOC "The directory where opencv/cv.h is installed") endif() @@ -52,15 +54,30 @@ endif() set(opencv_core_NAMES opencv_core) set(opencv_ml_NAMES opencv_ml) -if ( opencv_INCLUDE_DIR ) +if (opencv_INCLUDE_DIR) set(OPENCV_INCLUDE_DIRS "${opencv_INCLUDE_DIR}") if(NOT OpenCV_VERSION) file(READ "${opencv_INCLUDE_DIR}/opencv2/core/version.hpp" _header_content) - string(REGEX MATCH ".*# *define +CV_VERSION_EPOCH +([0-9]+).*" matched ${_header_content}) - if( matched) + # detect the type of version file (2.3.x , 2.4.x or 3.x) + string(REGEX MATCH ".*# *define +CV_VERSION_EPOCH +([0-9]+).*" has_epoch ${_header_content}) + string(REGEX MATCH ".*# *define +CV_MAJOR_VERSION +([0-9]+).*" has_old_major ${_header_content}) + string(REGEX MATCH ".*# *define +CV_MINOR_VERSION +([0-9]+).*" has_old_minor ${_header_content}) + string(REGEX MATCH ".*# *define +CV_SUBMINOR_VERSION +([0-9]+).*" has_old_subminor ${_header_content}) + + if(has_old_major AND has_old_minor AND has_old_subminor) + #for opencv 2.3.x + string(REGEX REPLACE ".*# *define +CV_MAJOR_VERSION +([0-9]+).*" "\\1" + OpenCV_VERSION_MAJOR ${_header_content}) + string(REGEX REPLACE ".*# *define +CV_MINOR_VERSION +([0-9]+).*" "\\1" + OpenCV_VERSION_MINOR ${_header_content}) + string(REGEX REPLACE ".*# *define +CV_SUBMINOR_VERSION +([0-9]+).*" "\\1" + OpenCV_VERSION_PATCH ${_header_content}) + set(OpenCV_VERSION_TWEAK) + elseif(has_epoch) + # for opencv 2.4.x string(REGEX REPLACE ".*# *define +CV_VERSION_EPOCH +([0-9]+).*" "\\1" OpenCV_VERSION_MAJOR ${_header_content}) string(REGEX REPLACE ".*# *define +CV_VERSION_MAJOR +([0-9]+).*" "\\1" @@ -70,12 +87,11 @@ if ( opencv_INCLUDE_DIR ) string(REGEX REPLACE ".*# *define +CV_VERSION_REVISION +([0-9]+).*" "\\1" OpenCV_VERSION_TWEAK ${_header_content}) else() - #for opencv 2.3.x - string(REGEX REPLACE ".*# *define +CV_MAJOR_VERSION +([0-9]+).*" "\\1" + string(REGEX REPLACE ".*# *define +CV_VERSION_MAJOR +([0-9]+).*" "\\1" OpenCV_VERSION_MAJOR ${_header_content}) - string(REGEX REPLACE ".*# *define +CV_MINOR_VERSION +([0-9]+).*" "\\1" + string(REGEX REPLACE ".*# *define +CV_VERSION_MINOR +([0-9]+).*" "\\1" OpenCV_VERSION_MINOR ${_header_content}) - string(REGEX REPLACE ".*# *define +CV_SUBMINOR_VERSION +([0-9]+).*" "\\1" + string(REGEX REPLACE ".*# *define +CV_VERSION_REVISION +([0-9]+).*" "\\1" OpenCV_VERSION_PATCH ${_header_content}) set(OpenCV_VERSION_TWEAK) endif() diff --git a/CMake/OTBCheckCpp11Keywords.cmake b/CMake/OTBCheckCpp11Keywords.cmake index a956670218e0ee932f057ea994a534767da9402b..707fe8b05a4aa71343df8daf5de3950c341fad71 100644 --- a/CMake/OTBCheckCpp11Keywords.cmake +++ b/CMake/OTBCheckCpp11Keywords.cmake @@ -22,6 +22,8 @@ include(CheckCXXSourceCompiles) set(CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS}) +unset(OTB_HAS_CXX11 CACHE) + CHECK_CXX_SOURCE_COMPILES(" #ifdef _MSC_VER #if _MSC_VER <= 1700 diff --git a/Documentation/Cookbook/Scripts/otbGenerateWrappersRstDoc.py b/Documentation/Cookbook/Scripts/otbGenerateWrappersRstDoc.py index e31bdcc37cc6508e75ac2ab42f32757a0d7fa6dc..4c6c30fa402b69ad2c3b342a1e3a4b3684650681 100755 --- a/Documentation/Cookbook/Scripts/otbGenerateWrappersRstDoc.py +++ b/Documentation/Cookbook/Scripts/otbGenerateWrappersRstDoc.py @@ -149,10 +149,10 @@ def FindLengthOfLargestColumnText(app,paramlist): else: if colLength[0] < len(param): colLength[0] = len(param) - lenpdescr = len(app.GetParameterName(param)) + lenpdescr = len(GenerateParameterType(app, param)) if colLength[2] < lenpdescr: colLength[2] = lenpdescr - lenptype = len(GenerateParameterType(app,param)) + lenptype = len(app.GetParameterName(param)) if colLength[1] < lenptype: colLength[1] = lenptype return colLength @@ -181,14 +181,14 @@ def MakeText(text, size): def GenerateParametersTable(app,paramlist): colLength = FindLengthOfLargestColumnText(app, paramlist) output = linesep + ".. [#] Table: Parameters table for " + ConvertString(app.GetDocName()) + "." + linesep + linesep - headerlist = ["Parameter Key", "Parameter Type", "Parameter Description"] + headerlist = ["Parameter Key", "Parameter Name", "Parameter Type"] for i in xrange(len(headerlist)): colLength[i] = len(headerlist[i]) if colLength[i] < len(headerlist[i]) else colLength[i] output += RstTableHeading(headerlist, colLength) for param in paramlist: output += MakeText(param, colLength[0]) - output += MakeText(GenerateParameterType(app,param), colLength[1]) - output += MakeText(GenerateParameterType(app,param), colLength[2]) + output += MakeText(app.GetParameterName(param), colLength[1]) + output += MakeText(GenerateParameterType(app, param), colLength[2]) output += '|' + linesep output += RstTableHeaderLine(headerlist, colLength, '-') if app.GetParameterType(param) == otbApplication.ParameterType_Choice: diff --git a/Documentation/Cookbook/rst/Installation_Linux.txt b/Documentation/Cookbook/rst/Installation_Linux.txt index 8a6e941d15f3de94da5f53739af25686a2e000db..017106e86b21eada5118cae786d1bfc204e31170 100644 --- a/Documentation/Cookbook/rst/Installation_Linux.txt +++ b/Documentation/Cookbook/rst/Installation_Linux.txt @@ -11,6 +11,11 @@ double-click on the file, or with the command line : chmod +x OTB-|release|-Linux64.run ./OTB-|release|-Linux64.run +The self-extractible archive only needs common tools found on most Linux +distributions ("sed", "grep", "find", "cat", "printf", "ln", ...). However, be +aware that it requires tools such as "which" and "file" (they are not always +present, for instance when building a container). + Please note that the resulting installation is not meant to be moved, you should uncompress the archive in its final location. Once the archive is extracted, the directory structure is made of: @@ -33,7 +38,15 @@ archive is extracted, the directory structure is made of: In order to run the command line launchers, this package doesn’t require any special library that is not present in most modern Linux -distributions. The graphical executable (otbgui launchers, Monteverdi +distributions. There is a small caveat for "expat" though. The binaries depend +on "libexpat.so", which can be supplied by most package managers (apt, yum, ...). +If not already present, look for one of the following packages : + +:: + + libexpat-dev libexpat1-dev + +The graphical executable (otbgui launchers, Monteverdi and Mapla) use the X11 libraries, which are widely used in a lot of distributions : diff --git a/Documentation/Cookbook/rst/recipes/improc.rst b/Documentation/Cookbook/rst/recipes/improc.rst index ca935be146903a9b505fdccf2f32396d238c134d..776fa35ad94722c494e0f508d25ed2a48facf03d 100644 --- a/Documentation/Cookbook/rst/recipes/improc.rst +++ b/Documentation/Cookbook/rst/recipes/improc.rst @@ -145,9 +145,9 @@ the *MeanShiftSmoothing* application: :: - otbcli_MeanShiftSmoothing -in input_image + otbcli_MeanShiftSmoothing -in input_image.tif -fout filtered_range.tif - -foutpos filtered_spat.tif + -foutpos filtered_spatial.tif -ranger 30 -spatialr 5 -maxiter 10 @@ -173,7 +173,7 @@ so, the *LSMSSegmentation* will process them by tiles whose dimensions are defined by the *tilesizex* and *tilesizey* parameters, and by writing intermediate images to disk, thus keeping the memory consumption very low throughout the process. The segmentation will group together -adjacent pixels whose range distance is below the *ranger* parameter and +neighboring pixels whose range distance is below the *ranger* parameter and (optionally) spatial distance is below the *spatialr* parameter. :: @@ -250,7 +250,7 @@ projection, so does the output GIS file). :: - otbcli_LSMSVectorization -in input_image + otbcli_LSMSVectorization -in input_image.tif -inseg segmentation_merged.tif -out segmentation_merged.shp -tilesizex 256 diff --git a/Documentation/Latex/Insight.bib b/Documentation/Latex/Insight.bib index 10a3a1f53534e0d2be42f9a6b500d4a8fbefc28b..ed04b803fc7084f16cc2fc960fbca35e284e45fa 100644 --- a/Documentation/Latex/Insight.bib +++ b/Documentation/Latex/Insight.bib @@ -11667,3 +11667,13 @@ ISSN={1057-7149}, title = {{The OpenCV Library}}, year = {2000} } + +%reference to the shark machine learning library +@Article{shark_library, + author = {Christian Igel and Verena Heidrich-Meisner and Tobias Glasmachers}, + title = {Shark}, + journal = {Journal of Machine Learning Research}, + year = {2008}, + volume = {9}, + pages = {993--996} +} diff --git a/Documentation/SoftwareGuide/Latex/Classification.tex b/Documentation/SoftwareGuide/Latex/Classification.tex index 8aad0e667e2a72fbc1794112b5f966a2dbdb3b27..a324b86a843506b6896bff272fafbdfdf2fa8be3 100644 --- a/Documentation/SoftwareGuide/Latex/Classification.tex +++ b/Documentation/SoftwareGuide/Latex/Classification.tex @@ -233,11 +233,11 @@ own framework. \subsection{Generic machine learning framework} \label{sec:MLGenericFramework} -The OTB supervised classification is implemented as a generic Machine Learning +The OTB supervised classification is implemented as a generic Machine Learning framework, supporting several possible machine learning libraries as backends. -As of now both libSVM (the machine learning library historically integrated in OTB) -and the machine learning methods of OpenCV library (\cite{opencv_library}) are -available. +As of now libSVM (the machine learning library historically integrated in OTB), +machine learning methods of OpenCV library (\cite{opencv_library}) and also +Shark machine learning library (\cite{shark_library}) are available. The current list of classifiers available through the same generic interface within the OTB is: diff --git a/Documentation/SoftwareGuide/Latex/Installation.tex b/Documentation/SoftwareGuide/Latex/Installation.tex index 1c00e5dd5697827a757a28715f7fec5bc3385b6b..c17547c8b16e142bfbb22d7b1267600e890cbd25 100644 --- a/Documentation/SoftwareGuide/Latex/Installation.tex +++ b/Documentation/SoftwareGuide/Latex/Installation.tex @@ -84,7 +84,7 @@ See table \ref{tab:otb-dependencies} for the full list of dependencies. \hline \textbf{ITK} & \url{http://www.itk.org} & yes & 4.6.0 \\ \hline -\textbf{GDAL} & \url{http://www.gdal.org} & yes & 1.10 \\ +\textbf{GDAL} & \url{http://www.gdal.org} & yes & 1.10 (2.x also supported) \\ \hline \textbf{OSSIM} & \url{http://www.ossim.org} & yes & 1.8.20-3 \\ \hline @@ -120,7 +120,7 @@ See table \ref{tab:otb-dependencies} for the full list of dependencies. \hline \textbf{MuParserX} & \url{http://muparserx.beltoforion.de} & no & 4.0.7 \\ \hline -\textbf{OpenCV} & \url{http://opencv.org} & no & 2 \\ +\textbf{OpenCV} & \url{http://opencv.org} & no & 2 (3.x also supported) \\ \hline \textbf{OPENGL} & \url{https://www.opengl.org/} & no & - \\ \hline diff --git a/Documentation/SoftwareGuide/Latex/ReadWrite.tex b/Documentation/SoftwareGuide/Latex/ReadWrite.tex index 5c301d60511d4480b0a7757c7359be03072e1e92..2d82fac6b37302a4c00375c8797cf5eed0c8a7c4 100644 --- a/Documentation/SoftwareGuide/Latex/ReadWrite.tex +++ b/Documentation/SoftwareGuide/Latex/ReadWrite.tex @@ -253,6 +253,26 @@ IMPORTANT: Note that you'll probably need to "quote" the filename. \item Select the JPEG2000 sub-resolution image to read \item 0 by default \end{itemize} +\item \begin{verbatim}&bands=r1,r2,...,rn\end{verbatim} +\begin{itemize} + \item Select a subset of bands from the input image + \item The syntax is inspired by Python indexing syntax with + bands=r1,r2,r3,...,rn where each ri is a band range that can be : + \begin{itemize} + \item a single index (1-based) : + \begin{itemize} + \item $'2'$ means 2nd band + \item $'-1'$ means last band + \end{itemize} + \item or a range of bands : + \begin{itemize} + \item $'3:'$ means 3rd band until the last one + \item $':-2'$ means the first bands until the second to last + \item $'2:4'$ means bands 2,3 and 4 + \end{itemize} + \end{itemize} + \item empty by default (all bands are read from the input image) +\end{itemize} \item \begin{verbatim}&skipcarto=<(bool)true>\end{verbatim} \begin{itemize} \item Skip the cartographic information @@ -339,8 +359,8 @@ IMPORTANT: Note that you'll probably need to "quote" the filename. \item The region must be set with 4 unsigned integers (the separator used is the colon ':'). Values are: \begin{itemize} - \item startx: first index on X - \item starty: first index on Y + \item startx: first index on X (starting with 0) + \item starty: first index on Y (starting with 0) \item sizex: size along X \item sizey: size along Y \end{itemize} @@ -349,6 +369,26 @@ IMPORTANT: Note that you'll probably need to "quote" the filename. itk::Size classes. The origin of the region within the image with which it is associated is defined by Index \end{itemize} +\item \begin{verbatim}&bands=r1,r2,...,rn\end{verbatim} +\begin{itemize} + \item Select a subset of bands from the output image + \item The syntax is inspired by Python indexing syntax with + bands=r1,r2,r3,...,rn where each ri is a band range that can be : + \begin{itemize} + \item a single index (1-based) : + \begin{itemize} + \item $'2'$ means 2nd band + \item $'-1'$ means last band + \end{itemize} + \item or a range of bands : + \begin{itemize} + \item $'3:'$ means 3rd band until the last one + \item $':-2'$ means the first bands until the second to last + \item $'2:4'$ means bands 2,3 and 4 + \end{itemize} + \end{itemize} + \item empty by default (all bands are write from the output image) +\end{itemize} \end{itemize} diff --git a/Modules/Applications/AppClassification/include/otbLearningApplicationBase.h b/Modules/Applications/AppClassification/include/otbLearningApplicationBase.h index feb6989e86eba5d760098d09301ee2393a5f99df..991ee9aa892137f12ee07bdb3b89d15bdbb26d4a 100644 --- a/Modules/Applications/AppClassification/include/otbLearningApplicationBase.h +++ b/Modules/Applications/AppClassification/include/otbLearningApplicationBase.h @@ -34,28 +34,6 @@ //Estimator #include "otbMachineLearningModelFactory.h" -#ifdef OTB_USE_OPENCV -#include "otbKNearestNeighborsMachineLearningModel.h" -#include "otbRandomForestsMachineLearningModel.h" -// OpenCV SVM implementation is buggy with linear kernel -// Users should use the libSVM implementation instead. -//#include "otbSVMMachineLearningModel.h" -#include "otbBoostMachineLearningModel.h" -#include "otbDecisionTreeMachineLearningModel.h" -#include "otbGradientBoostedTreeMachineLearningModel.h" -#include "otbNormalBayesMachineLearningModel.h" -#include "otbNeuralNetworkMachineLearningModel.h" -#endif - -#ifdef OTB_USE_LIBSVM -#include "otbLibSVMMachineLearningModel.h" -#endif - -#ifdef OTB_USE_SHARK -#include "otbSharkRandomForestsMachineLearningModel.h" -#include "otbSharkKMeansMachineLearningModel.h" -#endif - namespace otb { namespace Wrapper @@ -114,7 +92,7 @@ public: // Machine Learning models typedef otb::MachineLearningModelFactory< - InputValueType, OutputValueType> ModelFactoryType; + InputValueType, OutputValueType> ModelFactoryType; typedef typename ModelFactoryType::MachineLearningModelTypePointer ModelPointerType; typedef typename ModelFactoryType::MachineLearningModelType ModelType; @@ -124,33 +102,10 @@ public: typedef typename ModelType::TargetSampleType TargetSampleType; typedef typename ModelType::TargetListSampleType TargetListSampleType; typedef typename ModelType::TargetValueType TargetValueType; - -#ifdef OTB_USE_OPENCV - typedef otb::RandomForestsMachineLearningModel<InputValueType, OutputValueType> RandomForestType; - typedef otb::KNearestNeighborsMachineLearningModel<InputValueType, OutputValueType> KNNType; - // OpenCV SVM implementation is buggy with linear kernel - // Users should use the libSVM implementation instead. - // typedef otb::SVMMachineLearningModel<InputValueType, OutputValueType> SVMType; - typedef otb::BoostMachineLearningModel<InputValueType, OutputValueType> BoostType; - typedef otb::DecisionTreeMachineLearningModel<InputValueType, OutputValueType> DecisionTreeType; - typedef otb::GradientBoostedTreeMachineLearningModel<InputValueType, OutputValueType> GradientBoostedTreeType; - typedef otb::NeuralNetworkMachineLearningModel<InputValueType, OutputValueType> NeuralNetworkType; - typedef otb::NormalBayesMachineLearningModel<InputValueType, OutputValueType> NormalBayesType; -#endif - -#ifdef OTB_USE_LIBSVM - typedef otb::LibSVMMachineLearningModel<InputValueType, OutputValueType> LibSVMType; -#endif - -#ifdef OTB_USE_SHARK - typedef otb::SharkRandomForestsMachineLearningModel<InputValueType, OutputValueType> SharkRandomForestType; - typedef otb::SharkKMeansMachineLearningModel<InputValueType, OutputValueType> SharkKMeansType; -#endif itkGetConstReferenceMacro(SupervisedClassifier, std::vector<std::string>); itkGetConstReferenceMacro(UnsupervisedClassifier, std::vector<std::string>); - enum ClassifierCategory{ Supervised, Unsupervised @@ -182,14 +137,10 @@ protected: /** Init method that creates all the parameters for machine learning models */ void DoInit() ITK_OVERRIDE; - /** Init method that creates all the parameters for machine learning models */ - void DoUpdateParameters() 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 */ @@ -212,9 +163,7 @@ private: #ifdef OTB_USE_OPENCV void InitBoostParams(); - // OpenCV SVM implementation is buggy with linear kernel - // Users should use the libSVM implementation instead. - // void InitSVMParams(); + void InitSVMParams(); void InitDecisionTreeParams(); void InitGradientBoostedTreeParams(); void InitNeuralNetworkParams(); @@ -225,11 +174,9 @@ private: void TrainBoost(typename ListSampleType::Pointer trainingListSample, typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath); - // OpenCV SVM implementation is buggy with linear kernel - // Users should use the libSVM implementation instead. - // void TrainSVM(typename ListSampleType::Pointer trainingListSample, - // typename TargetListSampleType::Pointer trainingLabeledListSample, - // std::string modelPath); + void TrainSVM(typename ListSampleType::Pointer trainingListSample, + typename TargetListSampleType::Pointer trainingLabeledListSample, + std::string modelPath); void TrainDecisionTree(typename ListSampleType::Pointer trainingListSample, typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath); @@ -276,9 +223,7 @@ private: #include "otbTrainNeuralNetwork.txx" #include "otbTrainNormalBayes.txx" #include "otbTrainRandomForests.txx" -// OpenCV SVM implementation is buggy with linear kernel -// Users should use the libSVM implementation instead. -//#include "otbTrainSVM.txx" +#include "otbTrainSVM.txx" #endif #ifdef OTB_USE_LIBSVM #include "otbTrainLibSVM.txx" diff --git a/Modules/Applications/AppClassification/include/otbLearningApplicationBase.txx b/Modules/Applications/AppClassification/include/otbLearningApplicationBase.txx index 511f94fb6ccd5b59191eb4f99c88eab6e8b6444c..a40d0e505e3af53a3625976691aa402b1d59b827 100644 --- a/Modules/Applications/AppClassification/include/otbLearningApplicationBase.txx +++ b/Modules/Applications/AppClassification/include/otbLearningApplicationBase.txx @@ -33,7 +33,6 @@ namespace Wrapper template <class TInputValue, class TOutputValue> LearningApplicationBase<TInputValue,TOutputValue> ::LearningApplicationBase() : m_RegressionFlag(false) - { } @@ -74,13 +73,6 @@ LearningApplicationBase<TInputValue,TOutputValue> return foundUnsupervised ? Unsupervised : Supervised; } -template <class TInputValue, class TOutputValue> -void -LearningApplicationBase<TInputValue,TOutputValue> -::DoUpdateParameters() -{ -}; - template <class TInputValue, class TOutputValue> void LearningApplicationBase<TInputValue,TOutputValue> @@ -193,7 +185,7 @@ LearningApplicationBase<TInputValue,TOutputValue> otbAppLogFATAL("Module SharkLearning is not installed. You should consider turning OTB_USE_SHARK on during cmake configuration."); #endif } - if(modelName == "sharkkm") + else if(modelName == "sharkkm") { #ifdef OTB_USE_SHARK TrainSharkKMeans( trainingListSample, trainingLabeledListSample, modelPath ); @@ -201,18 +193,14 @@ LearningApplicationBase<TInputValue,TOutputValue> otbAppLogFATAL("Module SharkLearning is not installed. You should consider turning OTB_USE_SHARK on during cmake configuration."); #endif } - - - // OpenCV SVM implementation is buggy with linear kernel - // Users should use the libSVM implementation instead. - // else if (modelName == "svm") - // { - // #ifdef OTB_USE_OPENCV - // TrainSVM(trainingListSample, trainingLabeledListSample, modelPath); - // #else - // otbAppLogFATAL("Module OPENCV is not installed. You should consider turning OTB_USE_OPENCV on during cmake configuration."); - // #endif - // } + else if (modelName == "svm") + { + #ifdef OTB_USE_OPENCV + TrainSVM(trainingListSample, trainingLabeledListSample, modelPath); + #else + otbAppLogFATAL("Module OPENCV is not installed. You should consider turning OTB_USE_OPENCV on during cmake configuration."); + #endif + } else if (modelName == "boost") { #ifdef OTB_USE_OPENCV diff --git a/Modules/Applications/AppClassification/include/otbTrainBoost.txx b/Modules/Applications/AppClassification/include/otbTrainBoost.txx index 2f10dbdb1ebae028427ae322d9ab579b9f0dfad4..44093ecd5990eb1b8a7fad10ffe9f4c98dc0051d 100644 --- a/Modules/Applications/AppClassification/include/otbTrainBoost.txx +++ b/Modules/Applications/AppClassification/include/otbTrainBoost.txx @@ -21,6 +21,7 @@ #ifndef otbTrainBoost_txx #define otbTrainBoost_txx #include "otbLearningApplicationBase.h" +#include "otbBoostMachineLearningModel.h" namespace otb { @@ -69,6 +70,7 @@ namespace Wrapper typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath) { + typedef otb::BoostMachineLearningModel<InputValueType, OutputValueType> BoostType; typename BoostType::Pointer boostClassifier = BoostType::New(); boostClassifier->SetRegressionMode(this->m_RegressionFlag); boostClassifier->SetInputListSample(trainingListSample); diff --git a/Modules/Applications/AppClassification/include/otbTrainDecisionTree.txx b/Modules/Applications/AppClassification/include/otbTrainDecisionTree.txx index 7da9a6fdfdbcf03f083d3a204df0348f5fd5893d..3517791928b5d4be87c03d6e7ec72707f29d4525 100644 --- a/Modules/Applications/AppClassification/include/otbTrainDecisionTree.txx +++ b/Modules/Applications/AppClassification/include/otbTrainDecisionTree.txx @@ -21,6 +21,7 @@ #ifndef otbTrainDecisionTree_txx #define otbTrainDecisionTree_txx #include "otbLearningApplicationBase.h" +#include "otbDecisionTreeMachineLearningModel.h" namespace otb { @@ -38,7 +39,11 @@ LearningApplicationBase<TInputValue,TOutputValue> "See complete documentation here \\url{http://docs.opencv.org/modules/ml/doc/decision_trees.html}."); //MaxDepth AddParameter(ParameterType_Int, "classifier.dt.max", "Maximum depth of the tree"); +#ifdef OTB_OPENCV_3 + SetParameterInt("classifier.dt.max",10, false); +#else SetParameterInt("classifier.dt.max",65535, false); +#endif SetParameterDescription( "classifier.dt.max", "The training algorithm attempts to split each node while its depth is smaller than the maximum " "possible depth of the tree. The actual depth may be smaller if the other termination criteria are met, and/or " @@ -71,7 +76,12 @@ LearningApplicationBase<TInputValue,TOutputValue> //CVFolds AddParameter(ParameterType_Int, "classifier.dt.f", "K-fold cross-validations"); +#ifdef OTB_OPENCV_3 + // disable cross validation by default (crash in opencv 3.2) + SetParameterInt("classifier.dt.f",0, false); +#else SetParameterInt("classifier.dt.f",10, false); +#endif SetParameterDescription( "classifier.dt.f", "If cv_folds > 1, then it prunes a tree with K-fold cross-validation where K is equal to cv_folds."); @@ -96,6 +106,7 @@ LearningApplicationBase<TInputValue,TOutputValue> typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath) { + typedef otb::DecisionTreeMachineLearningModel<InputValueType, OutputValueType> DecisionTreeType; typename DecisionTreeType::Pointer classifier = DecisionTreeType::New(); classifier->SetRegressionMode(this->m_RegressionFlag); classifier->SetInputListSample(trainingListSample); diff --git a/Modules/Applications/AppClassification/include/otbTrainGradientBoostedTree.txx b/Modules/Applications/AppClassification/include/otbTrainGradientBoostedTree.txx index 2f8afb3a8c9363e1e10686097b9c695f9341496e..7f69ac9338011c00f3c11164f3a4a1a362a65c65 100644 --- a/Modules/Applications/AppClassification/include/otbTrainGradientBoostedTree.txx +++ b/Modules/Applications/AppClassification/include/otbTrainGradientBoostedTree.txx @@ -21,6 +21,7 @@ #ifndef otbTrainGradientBoostedTree_txx #define otbTrainGradientBoostedTree_txx #include "otbLearningApplicationBase.h" +#include "otbGradientBoostedTreeMachineLearningModel.h" namespace otb { @@ -32,6 +33,8 @@ void LearningApplicationBase<TInputValue,TOutputValue> ::InitGradientBoostedTreeParams() { +// disable GBTree model with OpenCV 3 (not implemented) +#ifndef OTB_OPENCV_3 AddChoice("classifier.gbt", "Gradient Boosted Tree classifier"); SetParameterDescription( "classifier.gbt", @@ -79,7 +82,7 @@ LearningApplicationBase<TInputValue,TOutputValue> //UseSurrogates : don't need to be exposed ! //AddParameter(ParameterType_Empty, "classifier.gbt.sur", "Surrogate splits will be built"); //SetParameterDescription("classifier.gbt.sur","These splits allow working with missing data and compute variable importance correctly."); - +#endif } template <class TInputValue, class TOutputValue> @@ -89,6 +92,12 @@ LearningApplicationBase<TInputValue,TOutputValue> typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath) { +#ifdef OTB_OPENCV_3 + (void) trainingListSample; + (void) trainingLabeledListSample; + (void) modelPath; +#else + typedef otb::GradientBoostedTreeMachineLearningModel<InputValueType, OutputValueType> GradientBoostedTreeType; typename GradientBoostedTreeType::Pointer classifier = GradientBoostedTreeType::New(); classifier->SetRegressionMode(this->m_RegressionFlag); classifier->SetInputListSample(trainingListSample); @@ -123,6 +132,7 @@ LearningApplicationBase<TInputValue,TOutputValue> classifier->Train(); classifier->Save(modelPath); +#endif } } //end namespace wrapper diff --git a/Modules/Applications/AppClassification/include/otbTrainKNN.txx b/Modules/Applications/AppClassification/include/otbTrainKNN.txx index 770a834531ccdccfe16ccb0141b55308e08ccde6..2ff93632bcd9b399e6d399f16cfe1fa33ed2cc6d 100644 --- a/Modules/Applications/AppClassification/include/otbTrainKNN.txx +++ b/Modules/Applications/AppClassification/include/otbTrainKNN.txx @@ -21,6 +21,7 @@ #ifndef otbTrainKNN_txx #define otbTrainKNN_txx #include "otbLearningApplicationBase.h" +#include "otbKNearestNeighborsMachineLearningModel.h" namespace otb { @@ -62,6 +63,7 @@ namespace Wrapper typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath) { + typedef otb::KNearestNeighborsMachineLearningModel<InputValueType, OutputValueType> KNNType; typename KNNType::Pointer knnClassifier = KNNType::New(); knnClassifier->SetRegressionMode(this->m_RegressionFlag); knnClassifier->SetInputListSample(trainingListSample); diff --git a/Modules/Applications/AppClassification/include/otbTrainLibSVM.txx b/Modules/Applications/AppClassification/include/otbTrainLibSVM.txx index c34dab80f8589413cf1b311a30e6390d7d8b24fb..0dd2d8f56327eaad45cae9d26101f0f1094ff31a 100644 --- a/Modules/Applications/AppClassification/include/otbTrainLibSVM.txx +++ b/Modules/Applications/AppClassification/include/otbTrainLibSVM.txx @@ -21,6 +21,7 @@ #ifndef otbTrainLibSVM_txx #define otbTrainLibSVM_txx #include "otbLearningApplicationBase.h" +#include "otbLibSVMMachineLearningModel.h" namespace otb { @@ -84,6 +85,7 @@ namespace Wrapper typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath) { + typedef otb::LibSVMMachineLearningModel<InputValueType, OutputValueType> LibSVMType; typename LibSVMType::Pointer libSVMClassifier = LibSVMType::New(); libSVMClassifier->SetRegressionMode(this->m_RegressionFlag); libSVMClassifier->SetInputListSample(trainingListSample); diff --git a/Modules/Applications/AppClassification/include/otbTrainNeuralNetwork.txx b/Modules/Applications/AppClassification/include/otbTrainNeuralNetwork.txx index ff062d0e88704e6bdfcea139369e7ad737e420a7..fb8287c4996640bb745046f0b22955e9d79c15e0 100644 --- a/Modules/Applications/AppClassification/include/otbTrainNeuralNetwork.txx +++ b/Modules/Applications/AppClassification/include/otbTrainNeuralNetwork.txx @@ -22,6 +22,7 @@ #define otbTrainNeuralNetwork_txx #include <boost/lexical_cast.hpp> #include "otbLearningApplicationBase.h" +#include "otbNeuralNetworkMachineLearningModel.h" namespace otb { @@ -134,6 +135,7 @@ LearningApplicationBase<TInputValue,TOutputValue> typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath) { + typedef otb::NeuralNetworkMachineLearningModel<InputValueType, OutputValueType> NeuralNetworkType; typename NeuralNetworkType::Pointer classifier = NeuralNetworkType::New(); classifier->SetRegressionMode(this->m_RegressionFlag); classifier->SetInputListSample(trainingListSample); diff --git a/Modules/Applications/AppClassification/include/otbTrainNormalBayes.txx b/Modules/Applications/AppClassification/include/otbTrainNormalBayes.txx index eaadb5ef5af6d0348dae9c69930dff415239c443..f796e8e975e746887d6680c30cfbca47fe243f7f 100644 --- a/Modules/Applications/AppClassification/include/otbTrainNormalBayes.txx +++ b/Modules/Applications/AppClassification/include/otbTrainNormalBayes.txx @@ -21,6 +21,7 @@ #ifndef otbTrainNormalBayes_txx #define otbTrainNormalBayes_txx #include "otbLearningApplicationBase.h" +#include "otbNormalBayesMachineLearningModel.h" namespace otb { @@ -45,6 +46,7 @@ namespace Wrapper typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath) { + typedef otb::NormalBayesMachineLearningModel<InputValueType, OutputValueType> NormalBayesType; typename NormalBayesType::Pointer classifier = NormalBayesType::New(); classifier->SetRegressionMode(this->m_RegressionFlag); classifier->SetInputListSample(trainingListSample); diff --git a/Modules/Applications/AppClassification/include/otbTrainRandomForests.txx b/Modules/Applications/AppClassification/include/otbTrainRandomForests.txx index 313c63d612707891969b9b486c16871784b11056..f557731207aa92509c7f156fcfbdf794ebaf9d03 100644 --- a/Modules/Applications/AppClassification/include/otbTrainRandomForests.txx +++ b/Modules/Applications/AppClassification/include/otbTrainRandomForests.txx @@ -21,6 +21,7 @@ #ifndef otbTrainRandomForests_txx #define otbTrainRandomForests_txx #include "otbLearningApplicationBase.h" +#include "otbRandomForestsMachineLearningModel.h" namespace otb { @@ -110,6 +111,7 @@ LearningApplicationBase<TInputValue,TOutputValue> typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath) { + typedef otb::RandomForestsMachineLearningModel<InputValueType, OutputValueType> RandomForestType; typename RandomForestType::Pointer classifier = RandomForestType::New(); classifier->SetRegressionMode(this->m_RegressionFlag); classifier->SetInputListSample(trainingListSample); diff --git a/Modules/Applications/AppClassification/include/otbTrainSVM.txx b/Modules/Applications/AppClassification/include/otbTrainSVM.txx index 8b999e70c7ff58c16e728d4ce0b937c4195b81ff..4c4729e7c5b1cea810941871b6ac37a06ff97aff 100644 --- a/Modules/Applications/AppClassification/include/otbTrainSVM.txx +++ b/Modules/Applications/AppClassification/include/otbTrainSVM.txx @@ -21,6 +21,7 @@ #ifndef otbTrainSVM_txx #define otbTrainSVM_txx #include "otbLearningApplicationBase.h" +#include "otbSVMMachineLearningModel.h" namespace otb { @@ -114,6 +115,7 @@ namespace Wrapper typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath) { + typedef otb::SVMMachineLearningModel<InputValueType, OutputValueType> SVMType; typename SVMType::Pointer SVMClassifier = SVMType::New(); SVMClassifier->SetRegressionMode(this->m_RegressionFlag); SVMClassifier->SetInputListSample(trainingListSample); diff --git a/Modules/Applications/AppClassification/include/otbTrainSharkKMeans.txx b/Modules/Applications/AppClassification/include/otbTrainSharkKMeans.txx index e3cf63af98c6d42aac1f9657b928f09f11e0db09..ca03ea33b2d8ee3b3085db3d0f112447eebaf77b 100644 --- a/Modules/Applications/AppClassification/include/otbTrainSharkKMeans.txx +++ b/Modules/Applications/AppClassification/include/otbTrainSharkKMeans.txx @@ -21,6 +21,7 @@ #define otbTrainSharkKMeans_txx #include "otbLearningApplicationBase.h" +#include "otbSharkKMeansMachineLearningModel.h" namespace otb { @@ -58,6 +59,7 @@ void LearningApplicationBase<TInputValue, TOutputValue>::TrainSharkKMeans( 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 ); diff --git a/Modules/Applications/AppClassification/include/otbTrainSharkRandomForests.txx b/Modules/Applications/AppClassification/include/otbTrainSharkRandomForests.txx index 7f7380934b914af955b628149e1fc0bbd3f35584..f2c2f97dc24bc77d798e533eadb09ef9354298d0 100644 --- a/Modules/Applications/AppClassification/include/otbTrainSharkRandomForests.txx +++ b/Modules/Applications/AppClassification/include/otbTrainSharkRandomForests.txx @@ -22,6 +22,7 @@ #define otbTrainSharkRandomForests_txx #include "otbLearningApplicationBase.h" +#include "otbSharkRandomForestsMachineLearningModel.h" namespace otb { @@ -83,6 +84,7 @@ LearningApplicationBase<TInputValue,TOutputValue> typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath) { + typedef otb::SharkRandomForestsMachineLearningModel<InputValueType, OutputValueType> SharkRandomForestType; typename SharkRandomForestType::Pointer classifier = SharkRandomForestType::New(); classifier->SetRegressionMode(this->m_RegressionFlag); classifier->SetInputListSample(trainingListSample); diff --git a/Modules/Applications/AppClassification/include/otbTrainVectorBase.txx b/Modules/Applications/AppClassification/include/otbTrainVectorBase.txx index 2f22b778c8ece5c9ea43fda055ce064610386615..22fb96b47becde7a4461623e9f0f79e9b1240c97 100644 --- a/Modules/Applications/AppClassification/include/otbTrainVectorBase.txx +++ b/Modules/Applications/AppClassification/include/otbTrainVectorBase.txx @@ -105,8 +105,6 @@ void TrainVectorBase::DoInit() void TrainVectorBase::DoUpdateParameters() { - Superclass::DoUpdateParameters(); - // if vector data is present and updated then reload fields if( HasValue( "io.vd" ) ) { diff --git a/Modules/Applications/AppClassification/test/CMakeLists.txt b/Modules/Applications/AppClassification/test/CMakeLists.txt index 29b91374d626d1d0469212119be222ca24dfddc4..3b4e213470625f57238c635383b4bacf22e93e7c 100644 --- a/Modules/Applications/AppClassification/test/CMakeLists.txt +++ b/Modules/Applications/AppClassification/test/CMakeLists.txt @@ -126,7 +126,10 @@ set(classifierList) #endif() if(OTB_USE_OPENCV) #list(APPEND classifierList "SVM" "BOOST" "DT" "GBT" "ANN" "BAYES" "RF" "KNN") - list(APPEND classifierList "BOOST" "DT" "GBT" "ANN" "BAYES" "RF" "KNN") + list(APPEND classifierList "BOOST" "DT" "ANN" "BAYES" "RF" "KNN") + if(NOT OTB_OPENCV_3) + list(APPEND classifierList "GBT") + endif() endif() if(OTB_USE_SHARK) list(APPEND classifierList "SHARKRF" "SHARKKM") diff --git a/Modules/Applications/AppMorphology/app/otbBinaryMorphologicalOperation.cxx b/Modules/Applications/AppMorphology/app/otbBinaryMorphologicalOperation.cxx index cf37ba14ba722e5d510a2ddc46db06a12983a70d..66a303d0df63babda8dad546cab92d37fc0d8b34 100644 --- a/Modules/Applications/AppMorphology/app/otbBinaryMorphologicalOperation.cxx +++ b/Modules/Applications/AppMorphology/app/otbBinaryMorphologicalOperation.cxx @@ -89,7 +89,7 @@ SetDocAuthors("OTB-Team"); SetDocSeeAlso("itkBinaryDilateImageFilter, itkBinaryErodeImageFilter, itkBinaryMorphologicalOpeningImageFilter and itkBinaryMorphologicalClosingImageFilter classes"); AddDocTag(Tags::FeatureExtraction); -AddDocTag("MorphologicalOperations"); +AddDocTag("Morphology"); AddParameter(ParameterType_InputImage, "in", "Input Image"); SetParameterDescription("in", "The input image to be filtered."); diff --git a/Modules/Applications/AppMorphology/app/otbGrayScaleMorphologicalOperation.cxx b/Modules/Applications/AppMorphology/app/otbGrayScaleMorphologicalOperation.cxx index 4a662febcae1e74b56cd16080de908ce6226f9f4..8f7c60953f7dc20b44a188c9d862553ea901b00e 100644 --- a/Modules/Applications/AppMorphology/app/otbGrayScaleMorphologicalOperation.cxx +++ b/Modules/Applications/AppMorphology/app/otbGrayScaleMorphologicalOperation.cxx @@ -89,7 +89,7 @@ SetDocAuthors("OTB-Team"); SetDocSeeAlso("itkGrayscaleDilateImageFilter, itkGrayscaleErodeImageFilter, itkGrayscaleMorphologicalOpeningImageFilter and itkGrayscaleMorphologicalClosingImageFilter classes"); AddDocTag(Tags::FeatureExtraction); -AddDocTag("MorphologicalOperations"); +AddDocTag("Morphology"); AddParameter(ParameterType_InputImage, "in", "Input Image"); SetParameterDescription("in", "The input image to be filtered."); diff --git a/Modules/Applications/AppMorphology/app/otbMorphologicalClassification.cxx b/Modules/Applications/AppMorphology/app/otbMorphologicalClassification.cxx index fb270a91443a77e043bb2af467948502df1e2f0d..8362a7881e56a4823b3b5919d9fef0dcae95960e 100644 --- a/Modules/Applications/AppMorphology/app/otbMorphologicalClassification.cxx +++ b/Modules/Applications/AppMorphology/app/otbMorphologicalClassification.cxx @@ -91,16 +91,17 @@ private: ":math:`f` with a structuring element of size :math:`N`. One can derive\n" "the following decision rule to classify :math:`f` into Convex (label\n" ":math:`\\stackrel{\\smile}{k}`), Concave (label\n" - ":math:`\\stackrel{rown}{k}`) and Flat (label :math:`\\bar{k}`): \n" + ":math:`\\stackrel{\\frown}{k}`) and Flat (label :math:`\\bar{k}`): \n" "\n" - ":math:`f(n) = \\begin{cases} \\stackrel{\\smile}{k} &:& f-\\psi_{N}(f)>\\sigma \\\\ \\stackrel{\\frown}{k} &:& \\psi_{N}(f)-f>\\sigma\\\\ \\bar{k}&:&\\mid f - \\psi_{N}(f) \\mid \\leq \\sigma \\end{cases}`" + ":math:`f(n) = \\begin{cases} \\stackrel{\\smile}{k} & : f-\\psi_{N}(f)>\\sigma \\\\ \\stackrel{\\frown}{k} & : \\psi_{N}(f)-f>\\sigma \\\\ \\bar{k} & : \\mid f - \\psi_{N}(f) \\mid \\leq \\sigma \\end{cases}`" "\n\n" "This output is a labeled image (0 : Flat, 1 : Convex, 2 : Concave)" ); SetDocLimitations( "Generation of the morphological classification is not streamable, pay attention to this fact when setting the radius size of the structuring element." ); SetDocAuthors( "OTB-Team" ); SetDocSeeAlso( "otbConvexOrConcaveClassificationFilter class" ); - AddDocTag( "MorphologicalClassification" ); + AddDocTag(Tags::FeatureExtraction); + AddDocTag("Morphology"); AddParameter( ParameterType_InputImage, "in", "Input Image" ); SetParameterDescription( "in", "The input image to be classified." ); diff --git a/Modules/Applications/AppMorphology/app/otbMorphologicalMultiScaleDecomposition.cxx b/Modules/Applications/AppMorphology/app/otbMorphologicalMultiScaleDecomposition.cxx index dc30e7dddb7e3ad8f1dca958baced90e3af2ea80..824786a770644b5253a2bfdac32be91a113a624b 100644 --- a/Modules/Applications/AppMorphology/app/otbMorphologicalMultiScaleDecomposition.cxx +++ b/Modules/Applications/AppMorphology/app/otbMorphologicalMultiScaleDecomposition.cxx @@ -87,22 +87,23 @@ private: "following scheme. Let :math:`f_0` denote the input image, :math:`\\stackrel{\\smile}{\\mu}_{N}(f)` denote the convex membership function, :math:`\\stackrel{\\frown}{\\mu}_{N}(f)` denote the concave membership function and :math:`\\psi_{N}(f)` denote the leveling function, for a given radius :math:`N` as defined in the documentation\n" "of the GeodesicMorphologyDecompositionImageFilter. Let :math:`[N_{1},\\ldots, N_{n}]` denote a range of increasing radius (or scales). The iterative decomposition is defined as follows:\n" "\n" - "[ f\\_n = `\\psi`\\_N\\_n(f\\_n-1) ]\n" + ":math:`f_i` = :math:`\\psi_{N_i}(f_{i-1})` \n" "\n" - "[ :math:`\\stackrel{\\frown}{f}_n` = :math:`\\stackrel{\\frown}{\\mu}_N_N(f_n)` ]\n" + ":math:`\\stackrel{\\frown}{f}_i` = :math:`\\stackrel{\\frown}{\\mu}_{N_i}(f_i)` \n" "\n" - "[ :math:`\\stackrel{\\smile}{f}_n` = :math:`\\stackrel{\\smile}{\\mu}_N_N(f_n)` ]\n" + ":math:`\\stackrel{\\smile}{f}_i` = :math:`\\stackrel{\\smile}{\\mu}_{N_i}(f_i)` \n" "\n" - "The :math:`\\stackrel{\\frown}{f}_{n}` and :math:`\\stackrel{\\frown}{f}_{n}` are membership function for the convex\n" - "(resp. concave) objects whose size is comprised between :math:`N_{n-1}` and :math:`N_n`\n" + "The :math:`\\stackrel{\\smile}{f}_{i}` and :math:`\\stackrel{\\frown}{f}_{i}` are membership function for the convex\n" + "(resp. concave) objects whose size is comprised between :math:`N_{i-1}` and :math:`N_i`\n" "\n" - "Output convex, concave and leveling images with N bands, where N is the number of levels." ); + "Output convex, concave and leveling images with B bands, where n is the number of levels." ); SetDocLimitations( "Generation of the multi scale decomposition is not streamable, pay attention to this fact when setting the number of iterating levels." ); SetDocAuthors( "OTB-Team" ); SetDocSeeAlso( "otbGeodesicMorphologyDecompositionImageFilter class" ); - AddDocTag( "MorphologicalMultiScaleDecomposition" ); + AddDocTag(Tags::FeatureExtraction); + AddDocTag("Morphology"); AddParameter( ParameterType_InputImage, "in", "Input Image" ); SetParameterDescription( "in", "The input image to be classified." ); diff --git a/Modules/Applications/AppMorphology/app/otbMorphologicalProfilesAnalysis.cxx b/Modules/Applications/AppMorphology/app/otbMorphologicalProfilesAnalysis.cxx index 7fbb3dd7df08e6b670eca76abec83691f570e9d8..9a5d140ba962292244bc6e7b4401b6bf8cc7eaa0 100644 --- a/Modules/Applications/AppMorphology/app/otbMorphologicalProfilesAnalysis.cxx +++ b/Modules/Applications/AppMorphology/app/otbMorphologicalProfilesAnalysis.cxx @@ -98,7 +98,7 @@ private: ":math:`L_1, L_2` two labels associated, and :math:`\\sigma` a tolerance\n" "value, the following decision rule is applied:\n" "\n" - ":math:`L = \\begin{cases} L_{1} &:& x_{1}>x_{2} \\quad and \\quad x_{1}>\\sigma\\\\ L_{2} &:& x_{2}>x_{1} \\quad and \\quad x_{2}>\\sigma\\\\ 0 &:& otherwise. \\end{cases}`" + ":math:`L = \\begin{cases} L_{1} & : x_{1}>x_{2} \\quad and \\quad x_{1}>\\sigma \\\\ L_{2} & : x_{2}>x_{1} \\quad and \\quad x_{2}>\\sigma \\\\ 0 & : otherwise. \\end{cases}` \n" "\n" "The output image can be :" "- A :math:`N` multi band image for the opening/closing normal or derivative profiles.\n" @@ -108,7 +108,8 @@ private: SetDocAuthors( "OTB-Team" ); SetDocSeeAlso( "otbMorphologicalOpeningProfileFilter, otbMorphologicalClosingProfileFilter, otbProfileToProfileDerivativeFilter, otbProfileDerivativeToMultiScaleCharacteristicsFilter, otbMultiScaleConvexOrConcaveClassificationFilter, classes" ); - AddDocTag( "MorphologicalProfilesAnalysis" ); + AddDocTag(Tags::FeatureExtraction); + AddDocTag("Morphology"); AddParameter( ParameterType_InputImage, "in", "Input Image" ); SetParameterDescription( "in", "The input image." ); diff --git a/Modules/Applications/AppSARUtils/CMakeLists.txt b/Modules/Applications/AppSARUtils/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..bd7a065d1828ce742920e76cd6382c222f5f67cf --- /dev/null +++ b/Modules/Applications/AppSARUtils/CMakeLists.txt @@ -0,0 +1,2 @@ +project(OTBAppSARUtils) +otb_module_impl() diff --git a/Modules/Applications/AppSARUtils/app/CMakeLists.txt b/Modules/Applications/AppSARUtils/app/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f0e7132c08c68baa6c95c2bc7dd114974e26278f --- /dev/null +++ b/Modules/Applications/AppSARUtils/app/CMakeLists.txt @@ -0,0 +1,9 @@ +set(OTBAppSARUtils_LINK_LIBS + ${OTBSARUtils_LIBRARIES} + ${OTBApplicationEngine_LIBRARIES} +) + +otb_create_application( + NAME ComputeModulusAndPhase + SOURCES otbComputeModulusAndPhase.cxx + LINK_LIBRARIES ${${otb-module}_LIBRARIES}) diff --git a/Modules/Applications/AppSARUtils/app/otbComputeModulusAndPhase.cxx b/Modules/Applications/AppSARUtils/app/otbComputeModulusAndPhase.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f3ea3c2349c357faf97b6a3d2baa6e36ed99725d --- /dev/null +++ b/Modules/Applications/AppSARUtils/app/otbComputeModulusAndPhase.cxx @@ -0,0 +1,132 @@ +/* + * 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 "otbWrapperApplication.h" +#include "otbWrapperApplicationFactory.h" +#include <otbMultiToMonoChannelExtractROI.h> + +#include "itkComplexToPhaseImageFilter.h" +#include "itkComplexToModulusImageFilter.h" +#include <itkMacro.h> + +namespace otb +{ +// Application class is defined in Wrapper namespace. +namespace Wrapper +{ + +/** \class ComputeModulusAndPhase + * \brief ComputeModulusAndPhase is an application that + * computes modulus and phase from a complex SAR image. + * + * \ingroup AppSARUtils + */ +class ComputeModulusAndPhase: public Application +{ +public: + // Class declaration is followed by ITK public types for the class, the superclass and smart pointers. + typedef ComputeModulusAndPhase Self; + typedef Application Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Standard macro */ + itkNewMacro (Self); + itkTypeMacro(ComputeModulusAndPhase, otb::Wrapper::Application); + + //typedefs for the application + typedef otb::MultiToMonoChannelExtractROI<typename ComplexFloatVectorImageType::InternalPixelType, typename ComplexFloatImageType::PixelType> ExtractFilterType; + typedef itk::ComplexToModulusImageFilter<ComplexFloatImageType, FloatImageType> ModulusFilterType; + typedef itk::ComplexToPhaseImageFilter<ComplexFloatImageType, FloatImageType> PhaseFilterType; + +private: + void DoInit() + { + SetName("ComputeModulusAndPhase"); + SetDescription("This application computes the modulus and the phase of a complex SAR image."); + + SetDocName("Compute Modulus And Phase"); + SetDocLongDescription( + "This application computes the modulus and the phase of a " + "complex SAR image. The input shoud be a single band image with " + "complex pixels." + ); + SetDocLimitations("None"); + SetDocAuthors("Alexia Mondot (alexia.mondot@c-s.fr) and Mickael Savinaud (mickael.savinaud@c-s.fr)"); + SetDocSeeAlso("SARPolarMatrixConvert, SARPolarSynth"); + AddDocTag(Tags::SAR); + + // Input images + AddParameter(ParameterType_ComplexInputImage, "in", "Input Image"); + SetParameterDescription("in", "Input image (complex single band)"); + + // Outputs + AddParameter(ParameterType_OutputImage, "modulus", "Modulus"); + SetParameterDescription("modulus", "Modulus of the input: sqrt(real*real + imag*imag)."); + + AddParameter(ParameterType_OutputImage, "phase", "Phase"); + SetParameterDescription("phase", "Phase of the input: atan2(imag, real)."); + + AddRAMParameter(); + + // Doc example parameter settings + SetDocExampleParameterValue("in", "monobandComplexFloat.tif"); + SetDocExampleParameterValue("modulus", "modulus.tif"); + SetDocExampleParameterValue("phase", "phase.tif"); + } + + // DoUpdateParameters() is called as soon as a parameter value change. + void DoUpdateParameters() + { + } + + // DoExecute() contains the application core. + void DoExecute() + { + m_Modulus = ModulusFilterType::New(); + m_Phase = PhaseFilterType::New(); + + ComplexFloatVectorImageType::Pointer inImage = GetParameterComplexImage("in"); + + if (inImage->GetNumberOfComponentsPerPixel() != 1) + { + otbAppLogFATAL("Input must be a single band complex image."); + } + + // Get first band + m_Extract = ExtractFilterType::New(); + m_Extract->SetInput(inImage); + + // Compute modulus and phase + m_Modulus->SetInput(m_Extract->GetOutput()); + m_Phase->SetInput(m_Extract->GetOutput()); + + SetParameterOutputImage("modulus", m_Modulus->GetOutput() ); + SetParameterOutputImage("phase", m_Phase->GetOutput()); + } + + ExtractFilterType::Pointer m_Extract; + ModulusFilterType::Pointer m_Modulus; + PhaseFilterType::Pointer m_Phase; +}; + +} // namespace Wrapper +} // namespace otb +OTB_APPLICATION_EXPORT(otb::Wrapper::ComputeModulusAndPhase) diff --git a/Modules/Applications/AppSARUtils/otb-module.cmake b/Modules/Applications/AppSARUtils/otb-module.cmake new file mode 100644 index 0000000000000000000000000000000000000000..41a1b43467aa97d35721a46dd6f4e4f4ad6b04be --- /dev/null +++ b/Modules/Applications/AppSARUtils/otb-module.cmake @@ -0,0 +1,12 @@ +set(DOCUMENTATION "SAR Utils application.") + +otb_module(OTBAppSARUtils + DEPENDS + OTBApplicationEngine + TEST_DEPENDS + OTBTestKernel + OTBCommandLine + + DESCRIPTION + "${DOCUMENTATION}" + ) diff --git a/Modules/Applications/AppSARUtils/test/CMakeLists.txt b/Modules/Applications/AppSARUtils/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..65dc6b75a9de038c360f9671a1a83c357a020bed --- /dev/null +++ b/Modules/Applications/AppSARUtils/test/CMakeLists.txt @@ -0,0 +1,13 @@ +otb_module_test() +#----------- ComputeModulusAndPhase TESTS ---------------- +otb_test_application(NAME apTvUtComputeModulusAndPhase_1inputComplex + APP ComputeModulusAndPhase + OPTIONS -in ${INPUTDATA}/monobandComplexFloat.tif + -modulus ${TEMP}/apTvUtMod1inputComplex.tif + -phase ${TEMP}/apTvUtPha1inputComplex.tif + VALID --compare-n-images ${EPSILON_6} 2 + ${BASELINE}/Mod_monobandComplexFloat.tif + ${TEMP}/apTvUtMod1inputComplex.tif + ${BASELINE}/Pha_monobandComplexFloat.tif + ${TEMP}/apTvUtPha1inputComplex.tif + ) diff --git a/Modules/Applications/AppSegmentation/app/otbLSMSVectorization.cxx b/Modules/Applications/AppSegmentation/app/otbLSMSVectorization.cxx index a1e8e9b36f7ee71d6c37c973ce5f2c15752ed3f2..a7dae77d1d92c6413c1a573fee73a4df9adc18ff 100644 --- a/Modules/Applications/AppSegmentation/app/otbLSMSVectorization.cxx +++ b/Modules/Applications/AppSegmentation/app/otbLSMSVectorization.cxx @@ -100,7 +100,7 @@ private: AddRAMParameter(); // Doc example parameter settings - SetDocExampleParameterValue("in","avions.tif"); + SetDocExampleParameterValue("in","maur_rgb.png"); SetDocExampleParameterValue("inseg","merged.tif"); SetDocExampleParameterValue("out","vector.shp"); SetDocExampleParameterValue("tilesizex","256"); diff --git a/Modules/Applications/AppSegmentation/app/otbMeanShiftSmoothing.cxx b/Modules/Applications/AppSegmentation/app/otbMeanShiftSmoothing.cxx index b5ae63bdfb6d6372d23242a0286313a10d8e5578..6184904bfc67a914d198ee74be5013f51d485cd3 100644 --- a/Modules/Applications/AppSegmentation/app/otbMeanShiftSmoothing.cxx +++ b/Modules/Applications/AppSegmentation/app/otbMeanShiftSmoothing.cxx @@ -109,8 +109,8 @@ private: // Doc example parameter settings SetDocExampleParameterValue("in", "maur_rgb.png"); - SetDocExampleParameterValue("fout", "MeanShift_FilterOutput.tif"); - SetDocExampleParameterValue("foutpos", "MeanShift_SpatialOutput.tif"); + SetDocExampleParameterValue("fout", "smooth.tif"); + SetDocExampleParameterValue("foutpos", "position.tif"); SetDocExampleParameterValue("spatialr", "16"); SetDocExampleParameterValue("ranger", "16"); SetDocExampleParameterValue("thres", "0.1"); diff --git a/Modules/Core/ImageBase/include/otbImageIOBase.h b/Modules/Core/ImageBase/include/otbImageIOBase.h index 50e79ffaef85755d348ed5fad177d1603c45152d..b6ae1ec2a1393e4c73c66af09d7253b875b85a47 100644 --- a/Modules/Core/ImageBase/include/otbImageIOBase.h +++ b/Modules/Core/ImageBase/include/otbImageIOBase.h @@ -303,7 +303,6 @@ public: virtual void SetOutputImagePixelType( bool isComplexInternalPixelType, bool isVectorImage) = 0; - /*-------- This part of the interfaces deals with reading data ----- */ /** Determine the file type. Returns true if this ImageIO can read the @@ -421,6 +420,12 @@ public: */ const ArrayOfExtensionsType & GetSupportedWriteExtensions() const; + /** Remap band order in an input buffer using band mapping bandList + * This operation is done in-place. The buffer size should enough to + * contain extracted bands before and after mapping. bandList mapping + * between origin components and output components (before any + * conversion)*/ + void DoMapBuffer(void* buffer, size_t numberOfPixels, std::vector<unsigned int>& bandList); protected: ImageIOBase(); diff --git a/Modules/Core/ImageBase/src/otbImageIOBase.cxx b/Modules/Core/ImageBase/src/otbImageIOBase.cxx index efcf4d0244bc81d150f2686a3c871dd2ac17fca7..d88d601fd66a007b1db2ec7c4f782f1eee852b4b 100644 --- a/Modules/Core/ImageBase/src/otbImageIOBase.cxx +++ b/Modules/Core/ImageBase/src/otbImageIOBase.cxx @@ -1269,6 +1269,54 @@ ImageIOBase return axis; } +void +ImageIOBase +::DoMapBuffer(void* buffer, size_t numberOfPixels, std::vector<unsigned int>& bandList) +{ + size_t componentSize = this->GetComponentSize(); + size_t inPixelSize = componentSize * this->GetNumberOfComponents(); + size_t outPixelSize = componentSize * bandList.size(); + char* inPos = static_cast<char*>(buffer); + char* outPos = static_cast<char*>(buffer); + bool workBackward = (outPixelSize > inPixelSize); + char *pixBuffer = new char[outPixelSize]; + + memset(pixBuffer, 0, outPixelSize); + + if (workBackward) + { + inPos = inPos + numberOfPixels*inPixelSize; + outPos = outPos + numberOfPixels*outPixelSize; + for (size_t n=0 ; n<numberOfPixels ; n++) + { + inPos -= inPixelSize; + outPos -= outPixelSize; + for (unsigned int i=0 ; i < bandList.size() ; i++) + { + memcpy(pixBuffer + i*componentSize, inPos + bandList[i]*componentSize, componentSize); + } + // copy pixBuffer to output + memcpy(outPos, pixBuffer, outPixelSize); + } + } + else + { + for (size_t n=0 ; n<numberOfPixels ; n++) + { + for (unsigned int i=0 ; i < bandList.size() ; i++) + { + memcpy(pixBuffer + i*componentSize, inPos + bandList[i]*componentSize, componentSize); + } + // copy pixBuffer to output + memcpy(outPos, pixBuffer, outPixelSize); + inPos += inPixelSize; + outPos += outPixelSize; + } + } + + delete[] pixBuffer; +} + void ImageIOBase::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); diff --git a/Modules/Filtering/MathParser/src/otbParser.cxx b/Modules/Filtering/MathParser/src/otbParser.cxx index 56bdd287dcdb7f2c12fdb481bbe7d6f71dd03de4..4280d3ac9c85b508453b5c23685bf0dc52f89255 100644 --- a/Modules/Filtering/MathParser/src/otbParser.cxx +++ b/Modules/Filtering/MathParser/src/otbParser.cxx @@ -62,6 +62,7 @@ public: { m_MuParser.DefineFun("ndvi", Self::NDVI); m_MuParser.DefineFun("NDVI", Self::NDVI); + m_MuParser.DefineFun("atan2", Self::ATAN2); #ifdef OTB_MUPARSER_HAS_CXX_LOGICAL_OPERATORS /* Starting with muParser 2.0.0, logical operators have been @@ -208,6 +209,11 @@ private: } return (niri-r)/(niri+r); } + + static ValueType ATAN2(ValueType y, ValueType x) + { + return vcl_atan2(y,x); + } #ifdef OTB_MUPARSER_HAS_CXX_LOGICAL_OPERATORS static ValueType AND(ValueType left, ValueType right) diff --git a/Modules/IO/ExtendedFilename/include/otbExtendedFilenameHelper.h b/Modules/IO/ExtendedFilename/include/otbExtendedFilenameHelper.h index 1f6db89a082f5aa59589929c7ca44c8a8060d110..b6d29171cd0ef81fd67ad3822c06366c417f2544 100644 --- a/Modules/IO/ExtendedFilename/include/otbExtendedFilenameHelper.h +++ b/Modules/IO/ExtendedFilename/include/otbExtendedFilenameHelper.h @@ -55,6 +55,30 @@ public: itkGetStringMacro(ExtendedFileName); itkGetStringMacro(SimpleFileName); + struct GenericBandRange : std::pair<int,int> + { + GenericBandRange() {} + + GenericBandRange(int a); + + GenericBandRange(const std::pair<int,int>& a); + + GenericBandRange(int a,int b); + + bool SetString(const std::string& str, size_t start=0 , size_t size=std::string::npos); + + void Print(std::ostream& os); + }; + + /** Decode the string into a list of GenericBandRange, band indexes are + * 1-based. */ + std::vector<ExtendedFilenameHelper::GenericBandRange> GetGenericBandRange(const std::string &bandRange) const; + + /** Resolve the list of band ranges into real band indexes, according to + * a total number of bands in the image. Note that the output indexes are + * zero-based (0 is the first component) */ + bool ResolveBandRange(const std::string &bandRange, const unsigned int &nbBands, std::vector<unsigned int> &output) const; + protected: ExtendedFilenameHelper() {} ~ExtendedFilenameHelper() ITK_OVERRIDE {} diff --git a/Modules/IO/ExtendedFilename/include/otbExtendedFilenameToReaderOptions.h b/Modules/IO/ExtendedFilename/include/otbExtendedFilenameToReaderOptions.h index 0abb00111d23e4945ed98be97556d81928316654..79c8bb00e0a7058d1a5531174254661deb47da50 100644 --- a/Modules/IO/ExtendedFilename/include/otbExtendedFilenameToReaderOptions.h +++ b/Modules/IO/ExtendedFilename/include/otbExtendedFilenameToReaderOptions.h @@ -35,6 +35,13 @@ namespace otb * - &resol : resolution factor for jpeg200 files * - &skipcarto : switch to skip the cartographic information * - &skipgeom : switch to skip the geometric information + * - &bands : select a band composition different from the input image, + * syntax is bands=r1,r2,r3,...,rn where each ri is a band range + * that can be : + * - a single index (1-based) : '2' means 2nd band, '-1' means last band + * - a range of bands : '3:' means 3rd band until the last one + * ':-2' means the first bands until the second to last + * '2:4' means bands 2,3 and 4 * * \sa ImageFileReader * @@ -67,6 +74,7 @@ public: std::pair< bool, bool > skipCarto; std::pair< bool, bool > skipGeom; std::pair< bool, bool > skipRpcTag; + std::pair< bool, std::string > bandRange; std::vector<std::string> optionList; }; @@ -86,6 +94,10 @@ public: bool GetSkipGeom () const; bool SkipRpcTagIsSet () const; bool GetSkipRpcTag () const; + std::string GetBandRange () const; + + /** Test if band range extended filename is set */ + bool BandRangeIsSet () const; protected: ExtendedFilenameToReaderOptions(); diff --git a/Modules/IO/ExtendedFilename/include/otbExtendedFilenameToWriterOptions.h b/Modules/IO/ExtendedFilename/include/otbExtendedFilenameToWriterOptions.h index b99b755b263aa1b32744e1c0913df706e32f25f2..81909d152832b2a6ef7f6c98333db05835a805b3 100644 --- a/Modules/IO/ExtendedFilename/include/otbExtendedFilenameToWriterOptions.h +++ b/Modules/IO/ExtendedFilename/include/otbExtendedFilenameToWriterOptions.h @@ -72,6 +72,7 @@ public: std::pair<bool, std::string> streamingSizeMode; std::pair<bool, double> streamingSizeValue; std::pair<bool, std::string> box; + std::pair< bool, std::string> bandRange; std::vector<std::string> optionList; }; @@ -91,10 +92,13 @@ public: std::string GetStreamingSizeMode() const; bool StreamingSizeValueIsSet() const; double GetStreamingSizeValue() const; + std::string GetBandRange () const; bool BoxIsSet() const; std::string GetBox() const; + /** Test if band range extended filename is set */ + bool BandRangeIsSet () const; protected: ExtendedFilenameToWriterOptions(); diff --git a/Modules/IO/ExtendedFilename/src/otbExtendedFilenameHelper.cxx b/Modules/IO/ExtendedFilename/src/otbExtendedFilenameHelper.cxx index e6885ffbaf77ba027edbd53f5bbee5ce203cc479..e92e2b05fb6dc23643e42bd7b4b56d7f7a14e95b 100644 --- a/Modules/IO/ExtendedFilename/src/otbExtendedFilenameHelper.cxx +++ b/Modules/IO/ExtendedFilename/src/otbExtendedFilenameHelper.cxx @@ -20,6 +20,8 @@ #include "otbExtendedFilenameHelper.h" #include "otb_boost_string_header.h" +#include "otbStringUtils.h" + namespace otb { @@ -43,32 +45,31 @@ ExtendedFilenameHelper { boost::split(tmp2, tmp1[1], boost::is_any_of("&"), boost::token_compress_on); for (unsigned int i=0; i<tmp2.size(); i++) - if (tmp2[i].length() >0) + if (!tmp2[i].empty()) { - std::vector<std::string> tmp; - boost::split(tmp, tmp2[i], boost::is_any_of("="), boost::token_compress_on); - if (tmp.size()>1) - { - if (tmp[1].length()>0) - { - if (m_OptionMap[tmp[0]].empty()) - { - m_OptionMap[tmp[0]]=tmp[1]; - } - else - { - itkWarningMacro("Duplicated option detected: " << tmp[0] << ". Using value " << tmp[1] << "."); - } - } - else - itkGenericExceptionMacro( << "Value for option '" << tmp[0] << "' is not set."); - } + std::vector<std::string> tmp; + boost::split(tmp, tmp2[i], boost::is_any_of("="), boost::token_compress_on); + if (tmp.size()>1) + { + if (!tmp[1].empty()) + { + if (m_OptionMap[tmp[0]].empty()) + { + m_OptionMap[tmp[0]]=tmp[1]; + } + else + { + itkWarningMacro("Duplicated option detected: " << tmp[0] << ". Using value " << tmp[1] << "."); + } + } + else + itkGenericExceptionMacro( << "Value for option '" << tmp[0] << "' is not set."); + } } } } } - const ExtendedFilenameHelper::OptionMapType & ExtendedFilenameHelper ::GetOptionMap(void) const @@ -76,4 +77,181 @@ ExtendedFilenameHelper return this->m_OptionMap; } +/*-------------------- GenericBandRange ----------------------*/ + +ExtendedFilenameHelper::GenericBandRange +::GenericBandRange(int a) + : std::pair<int,int>(a,a) + { + } + +ExtendedFilenameHelper::GenericBandRange +::GenericBandRange(const std::pair<int,int>& a) + : std::pair<int,int>(a) + { + if (a.second>=0 && a.second < a.first) + { + throw std::range_error("Invalid range"); + } + } + +ExtendedFilenameHelper::GenericBandRange +::GenericBandRange(int a,int b) + : std::pair<int,int>(a,b) + { + if (b>=0 && b < a) + { + throw std::range_error("Invalid range"); + } + } + +bool +ExtendedFilenameHelper::GenericBandRange +::SetString(const std::string& str, size_t start , size_t size) + { + assert(start < str.size()); + bool ret = true; + if (size == 0) + { + first = 0; + second = 0; + return false; + } + size_t end = str.size(); + if (size != std::string::npos && (start+size) <= str.size()) + { + end = start + size; + } + size_t pos = str.find(':',start); + if (pos != std::string::npos && pos<end) + { + // range of values + if (pos > start) + { + try + { + first = boost::lexical_cast<int>(str.c_str()+start, pos-start); + } + catch(boost::bad_lexical_cast &) + { + ret = false; + } + } + else + { + first = 0; + } + if (end > pos + 1) + { + try + { + second = boost::lexical_cast<int>(str.c_str()+ pos + 1, end - pos - 1); + } + catch(boost::bad_lexical_cast &) + { + ret = false; + } + } + else + { + second = 0; + } + } + else + { + // single value + try + { + first = boost::lexical_cast<int>(str.c_str()+start, end-start); + second = first; + } + catch(boost::bad_lexical_cast &) + { + ret = false; + } + } + return ret; + } + +void +ExtendedFilenameHelper::GenericBandRange +::Print(std::ostream& os) + { + if (this->first) + { + os << this->first; + } + if (this->first != this->second) + { + if (this->first || this->second) + { + os << ":"; + } + if (this->second) + { + os << this->second; + } + } + } + +std::vector<ExtendedFilenameHelper::GenericBandRange> +ExtendedFilenameHelper +::GetGenericBandRange(const std::string &bandRange) const +{ + //Parse string to return vector of band range + std::vector<ExtendedFilenameHelper::GenericBandRange> vBands; + size_t start = 0; + size_t pos; + if (!bandRange.empty()) + { + while (start != std::string::npos) + { + pos = bandRange.find(',',start); + if (pos > start) + { + ExtendedFilenameHelper::GenericBandRange range; + size_t size = (pos == std::string::npos ? pos : pos - start); + + bool ret = range.SetString(bandRange, start, size); + if (ret) vBands.push_back(range); + } + if (pos != std::string::npos) pos++; + start = pos; + } + } + return vBands; +} + +bool +ExtendedFilenameHelper +::ResolveBandRange(const std::string &bandRange, const unsigned int &nbBands, std::vector<unsigned int> &output) const +{ + output.clear(); + std::vector<ExtendedFilenameHelper::GenericBandRange> bandRangeList = this->GetGenericBandRange(bandRange); + for (unsigned int i=0 ; i<bandRangeList.size() ; i++) + { + int a = bandRangeList[i].first; + int b = bandRangeList[i].second; + if (a<0) a+= nbBands+1; + if (b<0) b+= nbBands+1; + if (a==0) a=1; + if (b==0) b=nbBands; + + if (1<=a && a<=b && b<=(int)nbBands) + { + for (unsigned int k=a ; k <= (unsigned int)b ; k++) + { + output.push_back((int)k -1); + } + } + else + { + // Invalid range wrt. the given number of bands + itkExceptionMacro("Invalid band number."); + return false; + } + } + return true; +} + } // end namespace otb diff --git a/Modules/IO/ExtendedFilename/src/otbExtendedFilenameToReaderOptions.cxx b/Modules/IO/ExtendedFilename/src/otbExtendedFilenameToReaderOptions.cxx index de61847cf8e42dd06856b9d5f34f7182bb1ecbda..308f5239c1e9aeb4aaccd7066e08cfaca1e605bc 100644 --- a/Modules/IO/ExtendedFilename/src/otbExtendedFilenameToReaderOptions.cxx +++ b/Modules/IO/ExtendedFilename/src/otbExtendedFilenameToReaderOptions.cxx @@ -20,6 +20,7 @@ #include "otbExtendedFilenameToReaderOptions.h" #include "otb_boost_string_header.h" +#include "itksys/RegularExpression.hxx" namespace otb { @@ -48,12 +49,16 @@ ExtendedFilenameToReaderOptions m_Options.skipRpcTag.first = false; m_Options.skipRpcTag.second = false; + m_Options.bandRange.first = false; + m_Options.bandRange.second = ""; + m_Options.optionList.push_back("geom"); m_Options.optionList.push_back("sdataidx"); m_Options.optionList.push_back("resol"); m_Options.optionList.push_back("skipcarto"); m_Options.optionList.push_back("skipgeom"); m_Options.optionList.push_back("skiprpctag"); + m_Options.optionList.push_back("bands"); } void @@ -124,6 +129,22 @@ ExtendedFilenameToReaderOptions } } + if (!map["bands"].empty()) + { + // Basic check on bandRange (using regex) + itksys::RegularExpression reg; + reg.compile("^((\\-?[0-9]+)?(:(\\-?[0-9]+)?)?)(,(\\-?[0-9]+)?(:(\\-?[0-9]+)?)?)*$"); + if (reg.find(map["bands"])) + { + m_Options.bandRange.first = true; + m_Options.bandRange.second = map["bands"]; + } + else + { + itkExceptionMacro("Unkwown value "<<map["bands"]<<" for band range. Expect a list of tokens separated with comma (each token being a single band index or a range in the form x:y)"); + } + } + //Option Checking MapIteratorType it; for ( it=map.begin(); it != map.end(); it++ ) @@ -224,4 +245,18 @@ ExtendedFilenameToReaderOptions return m_Options.skipRpcTag.second; } +bool +ExtendedFilenameToReaderOptions +::BandRangeIsSet () const +{ + return m_Options.bandRange.first; +} + +std::string +ExtendedFilenameToReaderOptions +::GetBandRange () const +{ + return m_Options.bandRange.second; +} + } // end namespace otb diff --git a/Modules/IO/ExtendedFilename/src/otbExtendedFilenameToWriterOptions.cxx b/Modules/IO/ExtendedFilename/src/otbExtendedFilenameToWriterOptions.cxx index 305afc72ba4bdecd7b24fe511aaa02abdc83c0f0..b3413fdc53286ac0cbf322f76783edf10c4cdc6f 100644 --- a/Modules/IO/ExtendedFilename/src/otbExtendedFilenameToWriterOptions.cxx +++ b/Modules/IO/ExtendedFilename/src/otbExtendedFilenameToWriterOptions.cxx @@ -43,12 +43,16 @@ ExtendedFilenameToWriterOptions m_Options.streamingSizeMode.first = false; m_Options.streamingSizeValue.first = false; + m_Options.bandRange.first = false; + m_Options.bandRange.second = ""; + m_Options.optionList.push_back("writegeom"); m_Options.optionList.push_back("writerpctags"); m_Options.optionList.push_back("streaming:type"); m_Options.optionList.push_back("streaming:sizemode"); m_Options.optionList.push_back("streaming:sizevalue"); m_Options.optionList.push_back("box"); + m_Options.optionList.push_back("bands"); } void @@ -158,6 +162,22 @@ ExtendedFilenameToWriterOptions } } + if (!map["bands"].empty()) + { + // Basic check on bandRange (using regex) + itksys::RegularExpression reg; + reg.compile("^((\\-?[0-9]+)?(:(\\-?[0-9]+)?)?)(,(\\-?[0-9]+)?(:(\\-?[0-9]+)?)?)*$"); + if (reg.find(map["bands"])) + { + m_Options.bandRange.first = true; + m_Options.bandRange.second = map["bands"]; + } + else + { + itkWarningMacro("Unkwown value "<<map["bands"]<<" for band range. Expect a list of tokens separated with comma (each token being a single band index or a range in the form x:y)"); + } + } + //Option Checking for ( it=map.begin(); it != map.end(); it++ ) { @@ -289,5 +309,18 @@ ExtendedFilenameToWriterOptions return m_Options.box.second; } +bool +ExtendedFilenameToWriterOptions +::BandRangeIsSet () const +{ + return m_Options.bandRange.first; +} + +std::string +ExtendedFilenameToWriterOptions +::GetBandRange () const +{ + return m_Options.bandRange.second; +} } // end namespace otb diff --git a/Modules/IO/ExtendedFilename/test/CMakeLists.txt b/Modules/IO/ExtendedFilename/test/CMakeLists.txt index d5a7cedb3b88e0d39be9bff42f84b6459493f28e..2ab3ae184c45597375b44deb46810c98cea1e835 100644 --- a/Modules/IO/ExtendedFilename/test/CMakeLists.txt +++ b/Modules/IO/ExtendedFilename/test/CMakeLists.txt @@ -58,7 +58,7 @@ otb_add_test(NAME ioTvExtendedFilenameToReaderOptions_FullOptions COMMAND otbExt ${BASELINE}/ioTvExtendedFilenameToReaderOptions_FullOptions.txt ${TEMP}/ioTvExtendedFilenameToReaderOptions_FullOptions.txt otbExtendedFilenameToReaderOptions - /home/data/filename.tif?&geom=/home/dev/custom.geom&sdataidx=2&resol=4&skipcarto=On + /home/data/filename.tif?&geom=/home/dev/custom.geom&sdataidx=2&resol=4&skipcarto=On&bands=-23,:3,45:,-6:-6,234:-5 ${TEMP}/ioTvExtendedFilenameToReaderOptions_FullOptions.txt ) @@ -71,6 +71,16 @@ otb_add_test(NAME ioTvExtendedFilenameToReaderOptions_NoOptions COMMAND otbExten ${TEMP}/ioTvExtendedFilenameToReaderOptions_NoOptions.txt ) +otb_add_test(NAME ioTvExtendedFilenameToReaderOptions_BandList COMMAND otbExtendedFilenameTestDriver + --compare-ascii ${NOTOL} + ${BASELINE}/ioTvExtendedFilenameToReaderOptions_BandList.txt + ${TEMP}/ioTvExtendedFilenameToReaderOptions_BandList.txt + otbExtendedFilenameToReaderOptions + /home/data/filename.tif?bands=3,5:,-3,2:-2 + ${TEMP}/ioTvExtendedFilenameToReaderOptions_BandList.txt + 6 + ) + otb_add_test(NAME ioTvExtendedFilenameToWriterOptions_FullOptions COMMAND otbExtendedFilenameTestDriver --compare-ascii ${NOTOL} ${BASELINE}/ioTvExtendedFilenameToWriterOptions_FullOptions.txt diff --git a/Modules/IO/ExtendedFilename/test/otbExtendedFilenameToReaderOptionsTest.cxx b/Modules/IO/ExtendedFilename/test/otbExtendedFilenameToReaderOptionsTest.cxx index 31aab027ebd40b4c64586fea29623318db311987..46ea10134688591fe3fc93bc77fffdec0223474b 100644 --- a/Modules/IO/ExtendedFilename/test/otbExtendedFilenameToReaderOptionsTest.cxx +++ b/Modules/IO/ExtendedFilename/test/otbExtendedFilenameToReaderOptionsTest.cxx @@ -24,7 +24,7 @@ typedef otb::ExtendedFilenameToReaderOptions FilenameHelperType; -int otbExtendedFilenameToReaderOptions(int itkNotUsed(argc), char* argv[]) +int otbExtendedFilenameToReaderOptions(int argc, char* argv[]) { // Verify the number of parameters in the command line const char * inputExtendedFilename = argv[1]; @@ -52,5 +52,38 @@ int otbExtendedFilenameToReaderOptions(int itkNotUsed(argc), char* argv[]) file << helper->SkipCartoIsSet() << std::endl; file << helper->GetSkipCarto() << std::endl; + file << helper->BandRangeIsSet() << std::endl; + file << "["; + + std::vector<otb::ExtendedFilenameHelper::GenericBandRange> rangeList = helper->GetGenericBandRange(helper->GetBandRange()); + for (unsigned int i=0 ; i<rangeList.size(); i++) + { + if (i) file << ","; + rangeList[i].Print(file); + } + file << "]" << std::endl; + + if (argc >= 4) + { + unsigned int nbBands = atoi(argv[3]); + std::vector<unsigned int> bandList; + bool ret = helper->ResolveBandRange(helper->GetBandRange(), nbBands,bandList); + if (ret) + { + file << "BandList = ["; + for (unsigned int k=0 ; k<bandList.size() ; k++) + { + if (k) file << ","; + file << bandList[k]; + } + file << "]" << std::endl; + } + else + { + std::cout << "Invalid band range for a "<<nbBands<<" bands image"<< std::endl; + } + } + + file.close(); return EXIT_SUCCESS; } diff --git a/Modules/IO/ImageIO/include/otbImageFileReader.h b/Modules/IO/ImageIO/include/otbImageFileReader.h index 928cef11e9be230153b5ab7b8c51bb0fc4c3c16d..daf6c58e800fc4c14bccb519edc9dcfc47400324 100644 --- a/Modules/IO/ImageIO/include/otbImageFileReader.h +++ b/Modules/IO/ImageIO/include/otbImageFileReader.h @@ -207,6 +207,15 @@ private: unsigned int m_AdditionalNumber; bool m_KeywordListUpToDate; + + /** Mapping between origin components and output components (before any + * conversion) */ + std::vector<unsigned int> m_BandList; + + /** Store the number of components to be exported to the output image + * This variable can be the number of components in m_ImageIO or the + * number of components in the m_BandList (if used) */ + unsigned int m_IOComponents; }; } //namespace otb diff --git a/Modules/IO/ImageIO/include/otbImageFileReader.txx b/Modules/IO/ImageIO/include/otbImageFileReader.txx index f0e30086dbd75a3425831cc5f531f478d4566893..cf647aac63f77a3945b60f8b48eb160d94d74779 100644 --- a/Modules/IO/ImageIO/include/otbImageFileReader.txx +++ b/Modules/IO/ImageIO/include/otbImageFileReader.txx @@ -69,7 +69,8 @@ ImageFileReader<TOutputImage, ConvertPixelTraits> m_ActualIORegion(), m_FilenameHelper(FNameHelperType::New()), m_AdditionalNumber(0), - m_KeywordListUpToDate(false) + m_KeywordListUpToDate(false), + m_IOComponents(0) { } @@ -185,7 +186,8 @@ ImageFileReader<TOutputImage, ConvertPixelTraits> if (this->m_ImageIO->GetComponentTypeInfo() == typeid(typename ConvertOutputPixelTraits::ComponentType) && (this->m_ImageIO->GetNumberOfComponents() - == ConvertIOPixelTraits::GetNumberOfComponents())) + == ConvertIOPixelTraits::GetNumberOfComponents()) + && !m_FilenameHelper->BandRangeIsSet()) { // Have the ImageIO read directly into the allocated buffer this->m_ImageIO->Read(buffer); @@ -197,19 +199,26 @@ ImageFileReader<TOutputImage, ConvertPixelTraits> // regardless of the actual type of the pixels. ImageRegionType region = output->GetBufferedRegion(); - // Adapt the image size with the region - std::streamoff nbBytes = (this->m_ImageIO->GetComponentSize() * this->m_ImageIO->GetNumberOfComponents()) - * static_cast<std::streamoff>(region.GetNumberOfPixels()); + // Adapt the image size with the region and take into account a potential + // remapping of the components. m_BandList is empty if no band range is set + std::streamoff nbBytes = + ( this->m_ImageIO->GetComponentSize() + * std::max(this->m_ImageIO->GetNumberOfComponents(),(unsigned int) m_BandList.size())) + * static_cast<std::streamoff>(region.GetNumberOfPixels()); char * loadBuffer = new char[nbBytes]; - otbMsgDevMacro(<< "size of Buffer to GDALImageIO::read = " << nbBytes << " = \n" + otbMsgDevMacro(<< "buffer size for ImageIO::read = " << nbBytes << " = \n" << "ComponentSize ("<< this->m_ImageIO->GetComponentSize() << ") x " \ - << "Nb of Component (" << this->m_ImageIO->GetNumberOfComponents() << ") x " \ - << "Nb of Pixel to read (" << region.GetNumberOfPixels() << ")" ); + << "Nb of Component ( max(" << this->m_ImageIO->GetNumberOfComponents() \ + << " , "<<m_BandList.size() << ") ) x " \ + << "Nb of Pixel to read (" << region.GetNumberOfPixels() << ")"); this->m_ImageIO->Read(loadBuffer); + if (m_FilenameHelper->BandRangeIsSet()) + this->m_ImageIO->DoMapBuffer(loadBuffer, region.GetNumberOfPixels(), this->m_BandList); + this->DoConvertBuffer(loadBuffer, region.GetNumberOfPixels()); delete[] loadBuffer; @@ -534,13 +543,28 @@ ImageFileReader<TOutputImage, ConvertPixelTraits> region.SetSize(dimSize); region.SetIndex(start); + // detect number of output components + m_IOComponents = this->m_ImageIO->GetNumberOfComponents(); + m_BandList.clear(); + if (m_FilenameHelper->BandRangeIsSet()) + { + bool ret = m_FilenameHelper->ResolveBandRange(m_FilenameHelper->GetBandRange(), m_IOComponents, m_BandList); + if (ret == false || m_BandList.size() == 0) + { + // invalid range + itkGenericExceptionMacro("The given band range is either empty or invalid for a " + <<m_IOComponents <<" bands input image!"); + } + m_IOComponents = m_BandList.size(); + } + // THOMAS : ajout // If a VectorImage, this requires us to set the // VectorLength before allocate if (strcmp(output->GetNameOfClass(), "VectorImage") == 0) { typedef typename TOutputImage::AccessorFunctorType AccessorFunctorType; - AccessorFunctorType::SetVectorLength(output, this->m_ImageIO->GetNumberOfComponents()); + AccessorFunctorType::SetVectorLength(output, m_IOComponents); } output->SetLargestPossibleRegion(region); @@ -808,7 +832,7 @@ ImageFileReader<TOutputImage, ConvertPixelTraits> > \ ::ConvertVectorImage( \ static_cast<type*>(inputData), \ - m_ImageIO->GetNumberOfComponents(), \ + m_IOComponents, \ outputData, \ numberOfPixels); \ } \ @@ -821,7 +845,7 @@ ImageFileReader<TOutputImage, ConvertPixelTraits> > \ ::Convert( \ static_cast<type*>(inputData), \ - m_ImageIO->GetNumberOfComponents(), \ + m_IOComponents, \ outputData, \ numberOfPixels); \ } \ @@ -843,7 +867,7 @@ ImageFileReader<TOutputImage, ConvertPixelTraits> > \ ::ConvertComplexVectorImageToVectorImageComplex( \ static_cast<type*>(inputData), \ - m_ImageIO->GetNumberOfComponents(), \ + m_IOComponents, \ outputData, \ numberOfPixels); \ }\ @@ -856,7 +880,7 @@ ImageFileReader<TOutputImage, ConvertPixelTraits> > \ ::ConvertComplexVectorImageToVectorImage( \ static_cast<type*>(inputData), \ - m_ImageIO->GetNumberOfComponents(), \ + m_IOComponents, \ outputData, \ numberOfPixels); \ }\ @@ -870,7 +894,7 @@ ImageFileReader<TOutputImage, ConvertPixelTraits> > \ ::ConvertComplexToGray( \ static_cast<type*>(inputData), \ - m_ImageIO->GetNumberOfComponents(), \ + m_IOComponents, \ outputData, \ numberOfPixels); \ } \ @@ -921,6 +945,7 @@ ImageFileReader<TOutputImage, ConvertPixelTraits> #undef OTB_CONVERT_CBUFFER_IF_BLOCK } + } //namespace otb #endif diff --git a/Modules/IO/ImageIO/include/otbImageFileWriter.h b/Modules/IO/ImageIO/include/otbImageFileWriter.h index 47f64fb70eb57255d4e54afc00a25bac24dbdc56..b7bc6499b089a47cf7c75822523e56fb9cf819e0 100644 --- a/Modules/IO/ImageIO/include/otbImageFileWriter.h +++ b/Modules/IO/ImageIO/include/otbImageFileWriter.h @@ -261,6 +261,15 @@ private: bool m_IsObserving; unsigned long m_ObserverID; InputIndexType m_ShiftOutputIndex; + + /** Mapping between origin components and output components (before any + * conversion) */ + std::vector<unsigned int> m_BandList; + + /** Store the number of components to be exported to the output image + * This variable can be the number of components in m_ImageIO or the + * number of components in the m_BandList (if used) */ + unsigned int m_IOComponents; }; } // end namespace otb diff --git a/Modules/IO/ImageIO/include/otbImageFileWriter.txx b/Modules/IO/ImageIO/include/otbImageFileWriter.txx index da083b764e2bd349a217efb99df005dcabcb4fdc..3224f5a3860a47e2cb59c7d24d00296bb90747dd 100644 --- a/Modules/IO/ImageIO/include/otbImageFileWriter.txx +++ b/Modules/IO/ImageIO/include/otbImageFileWriter.txx @@ -69,7 +69,8 @@ ImageFileWriter<TInputImage> m_WriteGeomFile(false), m_FilenameHelper(), m_IsObserving(true), - m_ObserverID(0) + m_ObserverID(0), + m_IOComponents(0) { //Init output index shift m_ShiftOutputIndex.Fill(0); @@ -710,6 +711,19 @@ ImageFileWriter<TInputImage> typedef typename InputImageType::AccessorFunctorType AccessorFunctorType; m_ImageIO->SetNumberOfComponents(AccessorFunctorType::GetVectorLength(input)); + + m_IOComponents = m_ImageIO->GetNumberOfComponents(); + m_BandList.clear(); + if (m_FilenameHelper->BandRangeIsSet()) + { + // get band range + bool retBandRange = m_FilenameHelper->ResolveBandRange(m_FilenameHelper->GetBandRange(), m_IOComponents, m_BandList); + if (retBandRange == false || m_BandList.empty()) + { + // invalid range + itkGenericExceptionMacro("The given band range is either empty or invalid for a " << m_IOComponents <<" bands input image!"); + } + } } else { @@ -734,8 +748,10 @@ ImageFileWriter<TInputImage> Convert(m_ImageIO->GetIORegion(), ioRegion, m_ShiftOutputIndex); InputImageRegionType bufferedRegion = input->GetBufferedRegion(); - // before this test, bad stuff would happened when they don't match - if (bufferedRegion != ioRegion) + // before this test, bad stuff would happened when they don't match. + // In case of the buffer has not enough components, adapt the region. + if ((bufferedRegion != ioRegion) || (m_FilenameHelper->BandRangeIsSet() + && (m_IOComponents < m_BandList.size()))) { if ( m_NumberOfDivisions > 1 || m_UserSpecifiedIORegion) { @@ -744,9 +760,22 @@ ImageFileWriter<TInputImage> cacheImage = InputImageType::New(); cacheImage->CopyInformation(input); + + // set number of components at the band range size + if (m_FilenameHelper->BandRangeIsSet() && (m_IOComponents < m_BandList.size())) + { + cacheImage->SetNumberOfComponentsPerPixel(m_BandList.size()); + } + cacheImage->SetBufferedRegion(ioRegion); cacheImage->Allocate(); + // set number of components at the initial size + if (m_FilenameHelper->BandRangeIsSet() && (m_IOComponents < m_BandList.size())) + { + cacheImage->SetNumberOfComponentsPerPixel(m_IOComponents); + } + typedef itk::ImageRegionConstIterator<TInputImage> ConstIteratorType; typedef itk::ImageRegionIterator<TInputImage> IteratorType; @@ -777,6 +806,14 @@ ImageFileWriter<TInputImage> } } + if (m_FilenameHelper->BandRangeIsSet() && (!m_BandList.empty())) + { + // Adapt the image size with the region and take into account a potential + // remapping of the components. m_BandList is empty if no band range is set + m_ImageIO->DoMapBuffer(const_cast< void* >(dataPtr), bufferedRegion.GetNumberOfPixels(), this->m_BandList); + m_ImageIO->SetNumberOfComponents(m_BandList.size()); + } + m_ImageIO->Write(dataPtr); if (m_WriteGeomFile || m_FilenameHelper->GetWriteGEOMFile()) diff --git a/Modules/IO/ImageIO/test/CMakeLists.txt b/Modules/IO/ImageIO/test/CMakeLists.txt index fec74c10db2bd998c7509d4a064e7d63807fa246..5f720d46cb8607683bb9794d94c1943a10efeff8 100644 --- a/Modules/IO/ImageIO/test/CMakeLists.txt +++ b/Modules/IO/ImageIO/test/CMakeLists.txt @@ -74,6 +74,8 @@ otbComplexImageManipulationTest.cxx otbImageFileWriterTest.cxx otbImageIOFactoryNew.cxx otbCompareWritingComplexImage.cxx +otbImageFileReaderOptBandTest.cxx +otbImageFileWriterOptBandTest.cxx ) add_executable(otbImageIOTestDriver ${OTBImageIOTests}) @@ -1301,3 +1303,39 @@ otb_add_test(NAME ioTvImageFileReaderPNG2ENVI COMMAND otbImageIOTestDriver otbImageFileReaderTest ${INPUTDATA}/cthead1.png ${TEMP}/ioImageFileReaderPNG2ENVI.hdr ) + +otb_add_test(NAME ioTvImageIOToReaderOptions_OptBandTest COMMAND otbImageIOTestDriver + --compare-image ${EPSILON_9} ${BASELINE}/QB_Toulouse_Ortho_XS_OptBand2to4.tif + ${TEMP}/QB_Toulouse_Ortho_XS_OptBand2to4.tif + otbImageFileReaderOptBandTest + ${INPUTDATA}/QB_Toulouse_Ortho_XS.tif?bands=2:4 + ${TEMP}/QB_Toulouse_Ortho_XS_OptBand2to4.tif + 4 + ) + +otb_add_test(NAME ioTvImageIOToReaderOptions_OptBandReorgTest COMMAND otbImageIOTestDriver + --compare-image ${EPSILON_9} ${BASELINE}/QB_Toulouse_Ortho_XS_OptBandReorg.tif + ${TEMP}/QB_Toulouse_Ortho_XS_OptBandReorg.tif + otbImageFileReaderOptBandTest + ${INPUTDATA}/QB_Toulouse_Ortho_XS.tif?bands=2,:,-3,2:-1 + ${TEMP}/QB_Toulouse_Ortho_XS_OptBandReorg.tif + 4 + ) + +otb_add_test(NAME ioTvImageIOToWriterOptions_OptBandTest COMMAND otbImageIOTestDriver + --compare-image ${EPSILON_9} ${BASELINE}/QB_Toulouse_Ortho_XS_OptBand2to4.tif + ${TEMP}/QB_Toulouse_Ortho_XS_WriterOptBand2to4.tif + otbImageFileWriterOptBandTest + ${INPUTDATA}/QB_Toulouse_Ortho_XS.tif + ${TEMP}/QB_Toulouse_Ortho_XS_WriterOptBand2to4.tif?bands=2:4 + 4 + ) + +otb_add_test(NAME ioTvImageIOToWriterOptions_OptBandReorgTest COMMAND otbImageIOTestDriver + --compare-image ${EPSILON_9} ${BASELINE}/QB_Toulouse_Ortho_XS_OptBandReorg.tif + ${TEMP}/QB_Toulouse_Ortho_XS_WriterOptBandReorg.tif + otbImageFileWriterOptBandTest + ${INPUTDATA}/QB_Toulouse_Ortho_XS.tif + ${TEMP}/QB_Toulouse_Ortho_XS_WriterOptBandReorg.tif?bands=2,:,-3,2:-1 + 4 + ) diff --git a/Modules/IO/ImageIO/test/otbImageFileReaderOptBandTest.cxx b/Modules/IO/ImageIO/test/otbImageFileReaderOptBandTest.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5f308702b95f9df3c2cea8b3650c0ab85bdab715 --- /dev/null +++ b/Modules/IO/ImageIO/test/otbImageFileReaderOptBandTest.cxx @@ -0,0 +1,77 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "otbImage.h" +#include "itkMacro.h" +#include <iostream> +#include <fstream> + +#include "otbVectorImage.h" +#include "otbImageFileReader.h" +#include "otbImageFileWriter.h" +#include "otbExtendedFilenameToReaderOptions.h" + +int otbImageFileReaderOptBandTest(int itkNotUsed(argc), char* argv[]) +{ + typedef otb::ExtendedFilenameToReaderOptions FilenameHelperType; + FilenameHelperType::Pointer helper = FilenameHelperType::New(); + + // Verify the number of parameters in the command line + const char * inputFilename = argv[1]; + const char * outputFilename = argv[2]; + + + + helper->SetExtendedFileName(inputFilename); + unsigned int nbBands = atoi(argv[3]); + std::vector<unsigned int> bandList; + bool ret = helper->ResolveBandRange(helper->GetBandRange(),nbBands,bandList); + if (ret) + { + std::cout << "BandList = ["; + for (unsigned int k=0 ; k<bandList.size() ; k++) + { + if (k) std::cout << ","; + std::cout << bandList[k]; + } + std::cout << "]" << std::endl; + } + else + { + std::cout << "Invalid band range for a "<<nbBands<<" bands image"<< std::endl; + } + + + typedef unsigned int PixelType; + const unsigned int Dimension = 2; + + typedef otb::VectorImage<PixelType, Dimension> ImageType; + + typedef otb::ImageFileReader<ImageType> ReaderType; + typedef otb::ImageFileWriter<ImageType> WriterType; + + ReaderType::Pointer reader = ReaderType::New(); + WriterType::Pointer writer = WriterType::New(); + + reader->SetFileName(inputFilename); + writer->SetFileName(outputFilename); + + writer->SetInput(reader->GetOutput()); + writer->Update(); + + return EXIT_SUCCESS; +} diff --git a/Modules/IO/ImageIO/test/otbImageFileWriterOptBandTest.cxx b/Modules/IO/ImageIO/test/otbImageFileWriterOptBandTest.cxx new file mode 100644 index 0000000000000000000000000000000000000000..66173cd05ab14aa1dce8135ff2300d56a6bbc2e2 --- /dev/null +++ b/Modules/IO/ImageIO/test/otbImageFileWriterOptBandTest.cxx @@ -0,0 +1,77 @@ +/* + * 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 "otbImage.h" +#include "itkMacro.h" +#include <iostream> +#include <fstream> + +#include "otbVectorImage.h" +#include "otbImageFileReader.h" +#include "otbImageFileWriter.h" +#include "otbExtendedFilenameToWriterOptions.h" + +int otbImageFileWriterOptBandTest(int itkNotUsed(argc), char* argv[]) +{ + typedef otb::ExtendedFilenameToWriterOptions FilenameHelperType; + FilenameHelperType::Pointer helper = FilenameHelperType::New(); + + // Verify the number of parameters in the command line + const char * inputFilename = argv[1]; + const char * outputFilename = argv[2]; + + helper->SetExtendedFileName(outputFilename); + unsigned int nbBands = atoi(argv[3]); + std::vector<unsigned int> bandList; + bool ret = helper->ResolveBandRange(helper->GetBandRange(),nbBands,bandList); + if (ret) + { + std::cout << "BandList = ["; + for (unsigned int k=0 ; k<bandList.size() ; k++) + { + if (k) std::cout << ","; + std::cout << bandList[k]; + } + std::cout << "]" << std::endl; + } + else + { + std::cout << "Invalid band range for a "<<nbBands<<" bands image"<< std::endl; + } + + typedef unsigned int PixelType; + const unsigned int Dimension = 2; + + typedef otb::VectorImage<PixelType, Dimension> ImageType; + + typedef otb::ImageFileReader<ImageType> ReaderType; + typedef otb::ImageFileWriter<ImageType> WriterType; + + ReaderType::Pointer reader = ReaderType::New(); + WriterType::Pointer writer = WriterType::New(); + + reader->SetFileName(inputFilename); + writer->SetFileName(outputFilename); + + writer->SetInput(reader->GetOutput()); + writer->Update(); + + return EXIT_SUCCESS; +} diff --git a/Modules/IO/ImageIO/test/otbImageIOTestDriver.cxx b/Modules/IO/ImageIO/test/otbImageIOTestDriver.cxx index 7621e85c445ee20c7d79d4342535182635dc549d..fb2aa583aa73653ece1ffb9f523ae6caaec71d84 100644 --- a/Modules/IO/ImageIO/test/otbImageIOTestDriver.cxx +++ b/Modules/IO/ImageIO/test/otbImageIOTestDriver.cxx @@ -152,4 +152,6 @@ void RegisterTests() REGISTER_TEST(otbImageFileWriterTest); REGISTER_TEST(otbImageIOFactoryNew); REGISTER_TEST(otbCompareWritingComplexImageTest); + REGISTER_TEST(otbImageFileReaderOptBandTest); + REGISTER_TEST(otbImageFileWriterOptBandTest); } diff --git a/Modules/Learning/Supervised/include/otbBoostMachineLearningModel.h b/Modules/Learning/Supervised/include/otbBoostMachineLearningModel.h index 9c5ab0acad866718f061e7485e3caf4fc54363b6..ec96746f6db0a8646b4fef008ca8ec6fa9194bf4 100644 --- a/Modules/Learning/Supervised/include/otbBoostMachineLearningModel.h +++ b/Modules/Learning/Supervised/include/otbBoostMachineLearningModel.h @@ -27,8 +27,11 @@ #include "itkFixedArray.h" #include "otbMachineLearningModel.h" - +#ifdef OTB_OPENCV_3 +#include "otbOpenCVUtils.h" +#else class CvBoost; +#endif namespace otb { @@ -131,7 +134,11 @@ private: BoostMachineLearningModel(const Self &); //purposely not implemented void operator =(const Self&); //purposely not implemented +#ifdef OTB_OPENCV_3 + cv::Ptr<cv::ml::Boost> m_BoostModel; +#else CvBoost * m_BoostModel; +#endif int m_BoostType; int m_WeakCount; double m_WeightTrimRate; diff --git a/Modules/Learning/Supervised/include/otbBoostMachineLearningModel.txx b/Modules/Learning/Supervised/include/otbBoostMachineLearningModel.txx index 62a069003aa17d398ad801a47fc88ee378699181..09d703a9dec0d50770069ac1c60d583abfbb0516 100644 --- a/Modules/Learning/Supervised/include/otbBoostMachineLearningModel.txx +++ b/Modules/Learning/Supervised/include/otbBoostMachineLearningModel.txx @@ -33,11 +33,19 @@ namespace otb template <class TInputValue, class TOutputValue> BoostMachineLearningModel<TInputValue,TOutputValue> ::BoostMachineLearningModel() : +#ifdef OTB_OPENCV_3 + m_BoostModel(cv::ml::Boost::create()), +#else m_BoostModel (new CvBoost), +#endif m_BoostType(CvBoost::REAL), m_WeakCount(100), m_WeightTrimRate(0.95), +#ifdef OTB_OPENCV_3 + m_SplitCrit(0), // not used in OpenCV 3.x +#else m_SplitCrit(CvBoost::DEFAULT), +#endif m_MaxDepth(1) { this->m_ConfidenceIndex = true; @@ -48,7 +56,9 @@ template <class TInputValue, class TOutputValue> BoostMachineLearningModel<TInputValue,TOutputValue> ::~BoostMachineLearningModel() { +#ifndef OTB_OPENCV_3 delete m_BoostModel; +#endif } /** Train the machine learning model */ @@ -64,16 +74,30 @@ BoostMachineLearningModel<TInputValue,TOutputValue> cv::Mat labels; otb::ListSampleToMat<TargetListSampleType>(this->GetTargetListSample(),labels); - CvBoostParams params = CvBoostParams(m_BoostType, m_WeakCount, m_WeightTrimRate, m_MaxDepth, false, ITK_NULLPTR); - params.split_criteria = m_SplitCrit; - - //train the Boost model cv::Mat var_type = cv::Mat(this->GetInputListSample()->GetMeasurementVectorSize() + 1, 1, CV_8U ); var_type.setTo(cv::Scalar(CV_VAR_NUMERICAL) ); // all inputs are numerical - var_type.at<uchar>(this->GetInputListSample()->GetMeasurementVectorSize(), 0) = CV_VAR_CATEGORICAL; +#ifdef OTB_OPENCV_3 + m_BoostModel->setBoostType(m_BoostType); + m_BoostModel->setWeakCount(m_WeakCount); + m_BoostModel->setWeightTrimRate(m_WeightTrimRate); + m_BoostModel->setMaxDepth(m_MaxDepth); + m_BoostModel->setUseSurrogates(false); + m_BoostModel->setPriors(cv::Mat()); + m_BoostModel->train(cv::ml::TrainData::create( + samples, + cv::ml::ROW_SAMPLE, + labels, + cv::noArray(), + cv::noArray(), + cv::noArray(), + var_type)); +#else + CvBoostParams params = CvBoostParams(m_BoostType, m_WeakCount, m_WeightTrimRate, m_MaxDepth, false, ITK_NULLPTR); + params.split_criteria = m_SplitCrit; m_BoostModel->train(samples,CV_ROW_SAMPLE,labels,cv::Mat(),cv::Mat(),var_type,cv::Mat(),params); +#endif } template <class TInputValue, class TOutputValue> @@ -82,25 +106,34 @@ typename BoostMachineLearningModel<TInputValue,TOutputValue> BoostMachineLearningModel<TInputValue,TOutputValue> ::DoPredict(const InputSampleType & input, ConfidenceValueType *quality) const { + TargetSampleType target; + //convert listsample to Mat cv::Mat sample; otb::SampleToMat<InputSampleType>(input,sample); + double result = 0.; +#ifdef OTB_OPENCV_3 + result = m_BoostModel->predict(sample); +#else cv::Mat missing = cv::Mat(1,input.Size(), CV_8U ); missing.setTo(0); - double result = m_BoostModel->predict(sample,missing); - - TargetSampleType target; - - target[0] = static_cast<TOutputValue>(result); + result = m_BoostModel->predict(sample,missing); +#endif if (quality != ITK_NULLPTR) { (*quality) = static_cast<ConfidenceValueType>( - m_BoostModel->predict(sample,missing,cv::Range::all(),false,true)); +#ifdef OTB_OPENCV_3 + m_BoostModel->predict(sample,cv::noArray(), cv::ml::StatModel::RAW_OUTPUT) +#else + m_BoostModel->predict(sample,missing,cv::Range::all(),false,true) +#endif + ); } + target[0] = static_cast<TOutputValue>(result); return target; } @@ -109,10 +142,18 @@ void BoostMachineLearningModel<TInputValue,TOutputValue> ::Save(const std::string & filename, const std::string & name) { +#ifdef OTB_OPENCV_3 + cv::FileStorage fs(filename, cv::FileStorage::WRITE); + fs << (name.empty() ? m_BoostModel->getDefaultName() : cv::String(name)) << "{"; + m_BoostModel->write(fs); + fs << "}"; + fs.release(); +#else if (name == "") m_BoostModel->save(filename.c_str(), ITK_NULLPTR); else m_BoostModel->save(filename.c_str(), name.c_str()); +#endif } template <class TInputValue, class TOutputValue> @@ -120,10 +161,15 @@ void BoostMachineLearningModel<TInputValue,TOutputValue> ::Load(const std::string & filename, const std::string & name) { +#ifdef OTB_OPENCV_3 + cv::FileStorage fs(filename, cv::FileStorage::READ); + m_BoostModel->read(name.empty() ? fs.getFirstTopLevelNode() : fs[name]); +#else if (name == "") m_BoostModel->load(filename.c_str(), ITK_NULLPTR); else m_BoostModel->load(filename.c_str(), name.c_str()); +#endif } template <class TInputValue, class TOutputValue> @@ -146,7 +192,11 @@ BoostMachineLearningModel<TInputValue,TOutputValue> std::getline(ifs, line); //if (line.find(m_SVMModel->getName()) != std::string::npos) - if (line.find(CV_TYPE_NAME_ML_BOOSTING) != std::string::npos) + if (line.find(CV_TYPE_NAME_ML_BOOSTING) != std::string::npos +#ifdef OTB_OPENCV_3 + || line.find(m_BoostModel->getDefaultName()) != std::string::npos +#endif + ) { //std::cout<<"Reading a "<<CV_TYPE_NAME_ML_BOOSTING<<" model"<<std::endl; return true; diff --git a/Modules/Learning/Supervised/include/otbCvRTreesWrapper.h b/Modules/Learning/Supervised/include/otbCvRTreesWrapper.h index 0f8fedffa162b67e3f3b725db671ef70e63ebafa..a3874b1c5fa0d278ba755bf7117fe74f4ae4eab7 100644 --- a/Modules/Learning/Supervised/include/otbCvRTreesWrapper.h +++ b/Modules/Learning/Supervised/include/otbCvRTreesWrapper.h @@ -32,7 +32,12 @@ namespace otb * * \ingroup OTBSupervised */ -class OTBSupervised_EXPORT CvRTreesWrapper : public CvRTrees +class OTBSupervised_EXPORT CvRTreesWrapper +#ifdef OTB_OPENCV_3 + : public cv::ml::RTrees +#else + : public CvRTrees +#endif { public: typedef std::vector<unsigned int> VotesVectorType; @@ -60,6 +65,70 @@ public: float predict_margin(const cv::Mat& sample, const cv::Mat& missing = cv::Mat()) const; + +#ifdef OTB_OPENCV_3 + +#define OTB_CV_WRAP_PROPERTY(type,name) \ + virtual type get##name() const; \ + virtual void set##name(type val); + +#define OTB_CV_WRAP_PROPERTY_REF(type,name) \ + virtual type get##name() const; \ + virtual void set##name(const type &val); + +#define OTB_CV_WRAP_CSTREF_GET(type, name) \ + virtual const type& get##name() const; + + // TODO : wrap all method used + virtual int getVarCount() const; + + virtual bool isTrained() const; + + virtual bool isClassifier() const; + + OTB_CV_WRAP_PROPERTY(int, MaxCategories) + OTB_CV_WRAP_PROPERTY(int, MaxDepth) + OTB_CV_WRAP_PROPERTY(int, MinSampleCount) + OTB_CV_WRAP_PROPERTY(bool, UseSurrogates) + OTB_CV_WRAP_PROPERTY(int, CVFolds) + OTB_CV_WRAP_PROPERTY(bool, Use1SERule) + OTB_CV_WRAP_PROPERTY(bool,TruncatePrunedTree) + OTB_CV_WRAP_PROPERTY(float, RegressionAccuracy) + OTB_CV_WRAP_PROPERTY(bool, CalculateVarImportance) + OTB_CV_WRAP_PROPERTY(int, ActiveVarCount) + OTB_CV_WRAP_PROPERTY_REF(cv::Mat, Priors) + OTB_CV_WRAP_PROPERTY_REF(cv::TermCriteria, TermCriteria) + + OTB_CV_WRAP_CSTREF_GET(std::vector<int>, Roots) + OTB_CV_WRAP_CSTREF_GET(std::vector<cv::ml::DTrees::Node>, Nodes) + OTB_CV_WRAP_CSTREF_GET(std::vector<cv::ml::DTrees::Split>, Splits) + OTB_CV_WRAP_CSTREF_GET(std::vector<int>, Subsets) + + virtual cv::Mat getVarImportance() const; + + virtual cv::String getDefaultName () const; + + virtual void read (const cv::FileNode &fn); + + virtual void write (cv::FileStorage &fs) const; + + virtual void save (const cv::String &filename) const; + + virtual bool train(cv::InputArray samples, int layout, cv::InputArray responses); + + virtual bool train( const cv::Ptr<cv::ml::TrainData>& trainData, int flags=0 ); + + virtual float predict (cv::InputArray samples, cv::OutputArray results=cv::noArray(), int flags=0) const; + + static cv::Ptr<CvRTreesWrapper> create(); + +#undef OTB_CV_WRAP_PROPERTY +#undef OTB_CV_WRAP_PROPERTY_REF +#undef OTB_CV_WRAP_CSTREF_GET + +private: + cv::Ptr<cv::ml::RTrees> m_Impl; +#endif // OTB_OPENCV_3 }; } diff --git a/Modules/Learning/Supervised/include/otbDecisionTreeMachineLearningModel.h b/Modules/Learning/Supervised/include/otbDecisionTreeMachineLearningModel.h index 7090f034e782c9a421d1e0793e4b62a5b2e5df9a..260fc835c79e2aaca65625e7928e3d8ffd122c50 100644 --- a/Modules/Learning/Supervised/include/otbDecisionTreeMachineLearningModel.h +++ b/Modules/Learning/Supervised/include/otbDecisionTreeMachineLearningModel.h @@ -27,8 +27,11 @@ #include "itkFixedArray.h" #include "otbMachineLearningModel.h" - +#ifdef OTB_OPENCV_3 +#include "otbOpenCVUtils.h" +#else class CvDTree; +#endif namespace otb { @@ -185,7 +188,11 @@ private: DecisionTreeMachineLearningModel(const Self &); //purposely not implemented void operator =(const Self&); //purposely not implemented +#ifdef OTB_OPENCV_3 + cv::Ptr<cv::ml::DTrees> m_DTreeModel; +#else CvDTree * m_DTreeModel; +#endif int m_MaxDepth; int m_MinSampleCount; diff --git a/Modules/Learning/Supervised/include/otbDecisionTreeMachineLearningModel.txx b/Modules/Learning/Supervised/include/otbDecisionTreeMachineLearningModel.txx index bd049899c19d1c00893cc9058c90d266c608d029..e84e5f92627a87bbfa2f3c5e1ad5d8c98cfd4698 100644 --- a/Modules/Learning/Supervised/include/otbDecisionTreeMachineLearningModel.txx +++ b/Modules/Learning/Supervised/include/otbDecisionTreeMachineLearningModel.txx @@ -33,6 +33,15 @@ namespace otb template <class TInputValue, class TOutputValue> DecisionTreeMachineLearningModel<TInputValue,TOutputValue> ::DecisionTreeMachineLearningModel() : +#ifdef OTB_OPENCV_3 + m_DTreeModel(cv::ml::DTrees::create()), + m_MaxDepth(10), + m_MinSampleCount(10), + m_RegressionAccuracy(0.01), + m_UseSurrogates(false), + m_MaxCategories(10), + m_CVFolds(0), +#else m_DTreeModel (new CvDTree), m_MaxDepth(INT_MAX), m_MinSampleCount(10), @@ -40,18 +49,20 @@ DecisionTreeMachineLearningModel<TInputValue,TOutputValue> m_UseSurrogates(true), m_MaxCategories(10), m_CVFolds(10), +#endif m_Use1seRule(true), m_TruncatePrunedTree(true) { this->m_IsRegressionSupported = true; } - template <class TInputValue, class TOutputValue> DecisionTreeMachineLearningModel<TInputValue,TOutputValue> ::~DecisionTreeMachineLearningModel() { +#ifndef OTB_OPENCV_3 delete m_DTreeModel; +#endif } /** Train the machine learning model */ @@ -67,19 +78,39 @@ DecisionTreeMachineLearningModel<TInputValue,TOutputValue> cv::Mat labels; otb::ListSampleToMat<TargetListSampleType>(this->GetTargetListSample(),labels); - float * priors = m_Priors.empty() ? ITK_NULLPTR : &m_Priors.front(); - - CvDTreeParams params = CvDTreeParams(m_MaxDepth, m_MinSampleCount, m_RegressionAccuracy, - m_UseSurrogates, m_MaxCategories, m_CVFolds, m_Use1seRule, m_TruncatePrunedTree, priors); - - //train the Decision Tree model cv::Mat var_type = cv::Mat(this->GetInputListSample()->GetMeasurementVectorSize() + 1, 1, CV_8U ); var_type.setTo(cv::Scalar(CV_VAR_NUMERICAL) ); // all inputs are numerical if (!this->m_RegressionMode) //Classification var_type.at<uchar>(this->GetInputListSample()->GetMeasurementVectorSize(), 0) = CV_VAR_CATEGORICAL; +#ifdef OTB_OPENCV_3 + m_DTreeModel->setMaxDepth(m_MaxDepth); + m_DTreeModel->setMinSampleCount(m_MinSampleCount); + m_DTreeModel->setRegressionAccuracy(m_RegressionAccuracy); + m_DTreeModel->setUseSurrogates(m_UseSurrogates); + m_DTreeModel->setMaxCategories(m_MaxCategories); + m_DTreeModel->setCVFolds(m_CVFolds); + m_DTreeModel->setUse1SERule(m_Use1seRule); + m_DTreeModel->setTruncatePrunedTree(m_TruncatePrunedTree); + m_DTreeModel->setPriors(cv::Mat(m_Priors)); + m_DTreeModel->train(cv::ml::TrainData::create( + samples, + cv::ml::ROW_SAMPLE, + labels, + cv::noArray(), + cv::noArray(), + cv::noArray(), + var_type)); +#else + float * priors = m_Priors.empty() ? ITK_NULLPTR : &m_Priors.front(); + + CvDTreeParams params = CvDTreeParams(m_MaxDepth, m_MinSampleCount, m_RegressionAccuracy, + m_UseSurrogates, m_MaxCategories, m_CVFolds, m_Use1seRule, m_TruncatePrunedTree, priors); + + //train the Decision Tree model m_DTreeModel->train(samples,CV_ROW_SAMPLE,labels,cv::Mat(),cv::Mat(),var_type,cv::Mat(),params); +#endif } template <class TInputValue, class TOutputValue> @@ -88,14 +119,17 @@ typename DecisionTreeMachineLearningModel<TInputValue,TOutputValue> DecisionTreeMachineLearningModel<TInputValue,TOutputValue> ::DoPredict(const InputSampleType & input, ConfidenceValueType *quality) const { + TargetSampleType target; + //convert listsample to Mat cv::Mat sample; otb::SampleToMat<InputSampleType>(input,sample); - +#ifdef OTB_OPENCV_3 + double result = m_DTreeModel->predict(sample); +#else double result = m_DTreeModel->predict(sample, cv::Mat(), false)->value; - - TargetSampleType target; +#endif target[0] = static_cast<TOutputValue>(result); @@ -115,10 +149,18 @@ void DecisionTreeMachineLearningModel<TInputValue,TOutputValue> ::Save(const std::string & filename, const std::string & name) { +#ifdef OTB_OPENCV_3 + cv::FileStorage fs(filename, cv::FileStorage::WRITE); + fs << (name.empty() ? m_DTreeModel->getDefaultName() : cv::String(name)) << "{"; + m_DTreeModel->write(fs); + fs << "}"; + fs.release(); +#else if (name == "") m_DTreeModel->save(filename.c_str(), ITK_NULLPTR); else m_DTreeModel->save(filename.c_str(), name.c_str()); +#endif } template <class TInputValue, class TOutputValue> @@ -126,10 +168,15 @@ void DecisionTreeMachineLearningModel<TInputValue,TOutputValue> ::Load(const std::string & filename, const std::string & name) { +#ifdef OTB_OPENCV_3 + cv::FileStorage fs(filename, cv::FileStorage::READ); + m_DTreeModel->read(name.empty() ? fs.getFirstTopLevelNode() : fs[name]); +#else if (name == "") m_DTreeModel->load(filename.c_str(), ITK_NULLPTR); else m_DTreeModel->load(filename.c_str(), name.c_str()); +#endif } template <class TInputValue, class TOutputValue> @@ -152,7 +199,11 @@ DecisionTreeMachineLearningModel<TInputValue,TOutputValue> std::getline(ifs, line); //if (line.find(m_SVMModel->getName()) != std::string::npos) - if (line.find(CV_TYPE_NAME_ML_TREE) != std::string::npos) + if (line.find(CV_TYPE_NAME_ML_TREE) != std::string::npos +#ifdef OTB_OPENCV_3 + || line.find(m_DTreeModel->getDefaultName()) != std::string::npos +#endif + ) { //std::cout<<"Reading a "<<CV_TYPE_NAME_ML_TREE<<" model"<<std::endl; return true; diff --git a/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModel.h b/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModel.h index 3c881cb399d2197689614af8a1d85af3a066d047..4ff453acb0cbd60ba029ff86846e3e072b59e6e9 100644 --- a/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModel.h +++ b/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModel.h @@ -27,6 +27,7 @@ #include "itkFixedArray.h" #include "otbMachineLearningModel.h" +#ifndef OTB_OPENCV_3 class CvGBTrees; @@ -157,3 +158,4 @@ private: #endif #endif +#endif diff --git a/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModel.txx b/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModel.txx index eee326a14404b4c3e04ceb9d3a071ee1359ac6e1..5f1380332d1d8db88d7d057199a798c69c165974 100644 --- a/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModel.txx +++ b/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModel.txx @@ -27,6 +27,7 @@ #include <fstream> #include "itkMacro.h" +#ifndef OTB_OPENCV_3 namespace otb { @@ -178,3 +179,4 @@ GradientBoostedTreeMachineLearningModel<TInputValue,TOutputValue> } //end namespace otb #endif +#endif diff --git a/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModelFactory.h b/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModelFactory.h index e6fad35494ffaa5a0f3f9c560ed78b54632d8fec..7d4d1faad88822285bac50fed67eea52d22883ce 100644 --- a/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModelFactory.h +++ b/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModelFactory.h @@ -26,6 +26,8 @@ #include "itkObjectFactoryBase.h" #include "itkImageIOBase.h" +#ifndef OTB_OPENCV_3 + namespace otb { /** \class GradientBoostedTreeMachineLearningModelFactory @@ -77,3 +79,4 @@ private: #endif #endif +#endif diff --git a/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModelFactory.txx b/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModelFactory.txx index 69812cde123e5e850f1293f51af7e58314278137..81fb5aab088614eb89db81164c256b7a17e40b70 100644 --- a/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModelFactory.txx +++ b/Modules/Learning/Supervised/include/otbGradientBoostedTreeMachineLearningModelFactory.txx @@ -27,6 +27,7 @@ #include "otbGradientBoostedTreeMachineLearningModel.h" #include "itkVersion.h" +#ifndef OTB_OPENCV_3 namespace otb { @@ -68,5 +69,5 @@ GradientBoostedTreeMachineLearningModelFactory<TInputValue,TOutputValue> } } // end namespace otb - +#endif #endif diff --git a/Modules/Learning/Supervised/include/otbKNearestNeighborsMachineLearningModel.h b/Modules/Learning/Supervised/include/otbKNearestNeighborsMachineLearningModel.h index b7c96249b4da901f744c8c10cb2ae69effe00d2a..069ff1eb47b7570f08aba5592ede2e4da8ef49ab 100644 --- a/Modules/Learning/Supervised/include/otbKNearestNeighborsMachineLearningModel.h +++ b/Modules/Learning/Supervised/include/otbKNearestNeighborsMachineLearningModel.h @@ -27,7 +27,11 @@ #include "itkFixedArray.h" #include "otbMachineLearningModel.h" +#ifdef OTB_OPENCV_3 +#include "otbOpenCVUtils.h" +#else class CvKNearest; +#endif namespace otb { @@ -110,7 +114,11 @@ private: KNearestNeighborsMachineLearningModel(const Self &); //purposely not implemented void operator =(const Self&); //purposely not implemented +#ifdef OTB_OPENCV_3 + cv::Ptr<cv::ml::KNearest> m_KNearestModel; +#else CvKNearest * m_KNearestModel; +#endif int m_K; int m_DecisionRule; diff --git a/Modules/Learning/Supervised/include/otbKNearestNeighborsMachineLearningModel.txx b/Modules/Learning/Supervised/include/otbKNearestNeighborsMachineLearningModel.txx index 1a3fbb559821b4b508cdc4ae6fd6a6ab208ce974..3b6dc52a25674819aff7ddb715e2be4b964c0c38 100644 --- a/Modules/Learning/Supervised/include/otbKNearestNeighborsMachineLearningModel.txx +++ b/Modules/Learning/Supervised/include/otbKNearestNeighborsMachineLearningModel.txx @@ -35,7 +35,11 @@ namespace otb template <class TInputValue, class TTargetValue> KNearestNeighborsMachineLearningModel<TInputValue,TTargetValue> ::KNearestNeighborsMachineLearningModel() : +#ifdef OTB_OPENCV_3 + m_KNearestModel(cv::ml::KNearest::create()), +#else m_KNearestModel (new CvKNearest), +#endif m_K(32), m_DecisionRule(KNN_VOTING) { @@ -48,7 +52,9 @@ template <class TInputValue, class TTargetValue> KNearestNeighborsMachineLearningModel<TInputValue,TTargetValue> ::~KNearestNeighborsMachineLearningModel() { +#ifndef OTB_OPENCV_3 delete m_KNearestModel; +#endif } /** Train the machine learning model */ @@ -80,8 +86,20 @@ KNearestNeighborsMachineLearningModel<TInputValue,TTargetValue> } } +#ifdef OTB_OPENCV_3 + m_KNearestModel->setDefaultK(m_K); + // would be nice to expose KDTree mode ( maybe in a different classifier) + m_KNearestModel->setAlgorithmType(cv::ml::KNearest::BRUTE_FORCE); + m_KNearestModel->setIsClassifier(!this->m_RegressionMode); + // setEmax() ? + m_KNearestModel->train(cv::ml::TrainData::create( + samples, + cv::ml::ROW_SAMPLE, + labels)); +#else //train the KNN model m_KNearestModel->train(samples, labels, cv::Mat(), this->m_RegressionMode, m_K, false); +#endif } template <class TInputValue, class TTargetValue> @@ -90,14 +108,19 @@ typename KNearestNeighborsMachineLearningModel<TInputValue,TTargetValue> KNearestNeighborsMachineLearningModel<TInputValue,TTargetValue> ::DoPredict(const InputSampleType & input, ConfidenceValueType *quality) const { + TargetSampleType target; + //convert listsample to Mat cv::Mat sample; otb::SampleToMat<InputSampleType>(input, sample); float result; cv::Mat nearest(1,m_K,CV_32FC1); +#ifdef OTB_OPENCV_3 + result = m_KNearestModel->findNearest(sample, m_K, cv::noArray(), nearest, cv::noArray()); +#else result = m_KNearestModel->find_nearest(sample, m_K,ITK_NULLPTR,ITK_NULLPTR,&nearest,ITK_NULLPTR); - +#endif // compute quality if asked (only happens in classification mode) if (quality != ITK_NULLPTR) { @@ -130,8 +153,6 @@ KNearestNeighborsMachineLearningModel<TInputValue,TTargetValue> result = *median; } - TargetSampleType target; - target[0] = static_cast<TTargetValue>(result); return target; } @@ -139,8 +160,17 @@ KNearestNeighborsMachineLearningModel<TInputValue,TTargetValue> template <class TInputValue, class TTargetValue> void KNearestNeighborsMachineLearningModel<TInputValue,TTargetValue> -::Save(const std::string & filename, const std::string & itkNotUsed(name)) +::Save(const std::string & filename, const std::string & name) { +#ifdef OTB_OPENCV_3 + cv::FileStorage fs(filename, cv::FileStorage::WRITE); + fs << (name.empty() ? m_KNearestModel->getDefaultName() : cv::String(name)) << "{"; + m_KNearestModel->write(fs); + fs << "DecisionRule" << m_DecisionRule; + fs << "}"; + fs.release(); +#else + (void) name; //there is no m_KNearestModel->save(filename.c_str(), name.c_str()). //We need to save the K parameter, IsRegression flag, DecisionRule and the samples. @@ -172,6 +202,7 @@ KNearestNeighborsMachineLearningModel<TInputValue,TTargetValue> ofs <<"\n"; } ofs.close(); +#endif } template <class TInputValue, class TTargetValue> @@ -179,12 +210,36 @@ void KNearestNeighborsMachineLearningModel<TInputValue,TTargetValue> ::Load(const std::string & filename, const std::string & itkNotUsed(name)) { - //there is no m_KNearestModel->load(filename.c_str(), name.c_str()); std::ifstream ifs(filename.c_str()); if(!ifs) { itkExceptionMacro(<<"Could not read file "<<filename); } +#ifdef OTB_OPENCV_3 + // try to load with the 3.x syntax + bool isKNNv3 = false; + while (!ifs.eof()) + { + std::string line; + std::getline(ifs, line); + if (line.find(m_KNearestModel->getDefaultName()) != std::string::npos) + { + isKNNv3 = true; + break; + } + } + ifs.close(); + if (isKNNv3) + { + cv::FileStorage fs(filename, cv::FileStorage::READ); + m_KNearestModel->read(fs.getFirstTopLevelNode()); + m_DecisionRule = (int)(fs.getFirstTopLevelNode()["DecisionRule"]); + return; + } + ifs.open(filename.c_str()); +#endif + //there is no m_KNearestModel->load(filename.c_str(), name.c_str()); + //first line is the K parameter of this algorithm. std::string line; std::getline(ifs, line); diff --git a/Modules/Learning/Supervised/include/otbMachineLearningModelFactory.txx b/Modules/Learning/Supervised/include/otbMachineLearningModelFactory.txx index 676bc40272ac4696cd4e3b66e78ad437a8c3f1c5..760096feafeada28f0328d8a6fced9e3a7cf9397 100644 --- a/Modules/Learning/Supervised/include/otbMachineLearningModelFactory.txx +++ b/Modules/Learning/Supervised/include/otbMachineLearningModelFactory.txx @@ -25,6 +25,7 @@ #include "otbConfigure.h" #ifdef OTB_USE_OPENCV +#include "otb_opencv_api.h" #include "otbKNearestNeighborsMachineLearningModelFactory.h" #include "otbRandomForestsMachineLearningModelFactory.h" #include "otbSVMMachineLearningModelFactory.h" @@ -32,8 +33,10 @@ #include "otbNeuralNetworkMachineLearningModelFactory.h" #include "otbNormalBayesMachineLearningModelFactory.h" #include "otbDecisionTreeMachineLearningModelFactory.h" +#ifndef OTB_OPENCV_3 #include "otbGradientBoostedTreeMachineLearningModelFactory.h" #endif +#endif #ifdef OTB_USE_LIBSVM #include "otbLibSVMMachineLearningModelFactory.h" #endif @@ -118,7 +121,9 @@ MachineLearningModelFactory<TInputValue,TOutputValue> RegisterFactory(NeuralNetworkMachineLearningModelFactory<TInputValue,TOutputValue>::New()); RegisterFactory(NormalBayesMachineLearningModelFactory<TInputValue,TOutputValue>::New()); RegisterFactory(DecisionTreeMachineLearningModelFactory<TInputValue,TOutputValue>::New()); +#ifndef OTB_OPENCV_3 RegisterFactory(GradientBoostedTreeMachineLearningModelFactory<TInputValue,TOutputValue>::New()); +#endif RegisterFactory(KNearestNeighborsMachineLearningModelFactory<TInputValue,TOutputValue>::New()); #endif } @@ -224,6 +229,7 @@ MachineLearningModelFactory<TInputValue,TOutputValue> itk::ObjectFactoryBase::UnRegisterFactory(dtFactory); continue; } +#ifndef OTB_OPENCV_3 // Gradient Boosted tree GradientBoostedTreeMachineLearningModelFactory<TInputValue,TOutputValue> *gbtFactory = dynamic_cast<GradientBoostedTreeMachineLearningModelFactory<TInputValue,TOutputValue> *>(*itFac); @@ -232,6 +238,7 @@ MachineLearningModelFactory<TInputValue,TOutputValue> itk::ObjectFactoryBase::UnRegisterFactory(gbtFactory); continue; } +#endif // KNN KNearestNeighborsMachineLearningModelFactory<TInputValue,TOutputValue> *knnFactory = dynamic_cast<KNearestNeighborsMachineLearningModelFactory<TInputValue,TOutputValue> *>(*itFac); diff --git a/Modules/Learning/Supervised/include/otbNeuralNetworkMachineLearningModel.h b/Modules/Learning/Supervised/include/otbNeuralNetworkMachineLearningModel.h index 8a6f6dcef0e559732dc4b59290889a97349bbdbf..3253c23686fcd46e2afcf513546518ade051cb6f 100644 --- a/Modules/Learning/Supervised/include/otbNeuralNetworkMachineLearningModel.h +++ b/Modules/Learning/Supervised/include/otbNeuralNetworkMachineLearningModel.h @@ -22,26 +22,7 @@ #define otbNeuralNetworkMachineLearningModel_h #include "otbRequiresOpenCVCheck.h" - -#include <opencv2/core/core_c.h> - -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-align" -#include <opencv2/core/core.hpp> -#pragma GCC diagnostic pop -#else -#include <opencv2/core/core.hpp> -#endif - -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Woverloaded-virtual" -#include <opencv2/ml/ml.hpp> -#pragma GCC diagnostic pop -#else -#include <opencv2/ml/ml.hpp> -#endif +#include "otbOpenCVUtils.h" #include "itkLightObject.h" #include "itkFixedArray.h" @@ -209,10 +190,13 @@ private: void operator =(const Self&); //purposely not implemented void CreateNetwork(); - CvANN_MLP_TrainParams SetNetworkParameters(); void SetupNetworkAndTrain(cv::Mat& labels); - +#ifdef OTB_OPENCV_3 + cv::Ptr<cv::ml::ANN_MLP> m_ANNModel; +#else + CvANN_MLP_TrainParams SetNetworkParameters(); CvANN_MLP * m_ANNModel; +#endif int m_TrainMethod; int m_ActivateFunction; std::vector<unsigned int> m_LayerSizes; diff --git a/Modules/Learning/Supervised/include/otbNeuralNetworkMachineLearningModel.txx b/Modules/Learning/Supervised/include/otbNeuralNetworkMachineLearningModel.txx index 06e8985c4fd2234ced2b52c5752ccb1749450514..6b157752f0a466e2c73989b032db558ba924e925 100644 --- a/Modules/Learning/Supervised/include/otbNeuralNetworkMachineLearningModel.txx +++ b/Modules/Learning/Supervised/include/otbNeuralNetworkMachineLearningModel.txx @@ -23,7 +23,6 @@ #include <fstream> #include "otbNeuralNetworkMachineLearningModel.h" -#include "otbOpenCVUtils.h" #include "itkMacro.h" // itkExceptionMacro namespace otb @@ -31,7 +30,12 @@ namespace otb template<class TInputValue, class TOutputValue> NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::NeuralNetworkMachineLearningModel() : +#ifdef OTB_OPENCV_3 + m_ANNModel(cv::ml::ANN_MLP::create()), + // TODO +#else m_ANNModel (new CvANN_MLP), +#endif m_TrainMethod(CvANN_MLP_TrainParams::RPROP), m_ActivateFunction(CvANN_MLP::SIGMOID_SYM), m_Alpha(1.), @@ -52,7 +56,9 @@ NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::NeuralNetworkMachi template<class TInputValue, class TOutputValue> NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::~NeuralNetworkMachineLearningModel() { +#ifndef OTB_OPENCV_3 delete m_ANNModel; +#endif cvReleaseMat(&m_CvMatOfLabels); } @@ -153,9 +159,15 @@ void NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::CreateNetwork layers.row(i) = m_LayerSizes[i]; } +#ifdef OTB_OPENCV_3 + m_ANNModel->setLayerSizes(layers); + m_ANNModel->setActivationFunction(m_ActivateFunction, m_Alpha, m_Beta); +#else m_ANNModel->create(layers, m_ActivateFunction, m_Alpha, m_Beta); +#endif } +#ifndef OTB_OPENCV_3 template<class TInputValue, class TOutputValue> CvANN_MLP_TrainParams NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::SetNetworkParameters() { @@ -169,6 +181,7 @@ CvANN_MLP_TrainParams NeuralNetworkMachineLearningModel<TInputValue, TOutputValu params.term_crit = term_crit; return params; } +#endif template<class TInputValue, class TOutputValue> void NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::SetupNetworkAndTrain(cv::Mat& labels) @@ -177,9 +190,27 @@ void NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::SetupNetworkA cv::Mat samples; otb::ListSampleToMat<InputListSampleType>(this->GetInputListSample(), samples); this->CreateNetwork(); +#ifdef OTB_OPENCV_3 + int flags = (this->m_RegressionMode ? 0 : cv::ml::ANN_MLP::NO_OUTPUT_SCALE); + m_ANNModel->setTrainMethod(m_TrainMethod); + m_ANNModel->setBackpropMomentumScale(m_BackPropMomentScale); + m_ANNModel->setBackpropWeightScale(m_BackPropDWScale); + m_ANNModel->setRpropDW0(m_RegPropDW0); + //m_ANNModel->setRpropDWMax( ); + m_ANNModel->setRpropDWMin(m_RegPropDWMin); + //m_ANNModel->setRpropDWMinus( ); + //m_ANNModel->setRpropDWPlus( ); + m_ANNModel->setTermCriteria(cv::TermCriteria(m_TermCriteriaType,m_MaxIter,m_Epsilon)); + m_ANNModel->train(cv::ml::TrainData::create( + samples, + cv::ml::ROW_SAMPLE, + labels), + flags); +#else CvANN_MLP_TrainParams params = this->SetNetworkParameters(); //train the Neural network model m_ANNModel->train(samples, labels, cv::Mat(), cv::Mat(), params); +#endif } /** Train the machine learning model for classification*/ @@ -205,6 +236,7 @@ template<class TInputValue, class TOutputValue> typename NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::TargetSampleType NeuralNetworkMachineLearningModel< TInputValue, TOutputValue>::DoPredict(const InputSampleType & input, ConfidenceValueType *quality) const { + TargetSampleType target; //convert listsample to Mat cv::Mat sample; @@ -213,7 +245,6 @@ typename NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::TargetSam cv::Mat response; //(1, 1, CV_32FC1); m_ANNModel->predict(sample, response); - TargetSampleType target; float currentResponse = 0; float maxResponse = response.at<float> (0, 0); @@ -251,7 +282,6 @@ typename NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::TargetSam { (*quality) = static_cast<ConfidenceValueType>(maxResponse) - static_cast<ConfidenceValueType>(secondResponse); } - return target; } @@ -259,6 +289,18 @@ template<class TInputValue, class TOutputValue> void NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::Save(const std::string & filename, const std::string & name) { +#ifdef OTB_OPENCV_3 + cv::FileStorage fs(filename, cv::FileStorage::WRITE); + fs << (name.empty() ? m_ANNModel->getDefaultName() : cv::String(name)) << "{"; + m_ANNModel->write(fs); + if (m_CvMatOfLabels != ITK_NULLPTR) + { + std::string labelsName("class_labels"); + fs.writeObj(labelsName,m_CvMatOfLabels); + } + fs << "}"; + fs.release(); +#else const char* lname = "my_nn"; if ( !name.empty() ) lname = name.c_str(); @@ -275,12 +317,20 @@ void NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::Save(const st cvWrite(fs, "class_labels", m_CvMatOfLabels); cvReleaseFileStorage(&fs); +#endif } template<class TInputValue, class TOutputValue> void NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::Load(const std::string & filename, const std::string & name) { +#ifdef OTB_OPENCV_3 + cv::FileStorage fs(filename, cv::FileStorage::READ); + cv::FileNode model_node(name.empty() ? fs.getFirstTopLevelNode() : fs[name]); + m_ANNModel->read(model_node); + m_CvMatOfLabels = (CvMat*)cvReadByName( *fs, *model_node, "class_labels" ); + fs.release(); +#else const char* lname = ITK_NULLPTR; if ( !name.empty() ) lname = name.c_str(); @@ -307,6 +357,7 @@ void NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::Load(const st m_CvMatOfLabels = (CvMat*)cvReadByName( *fs, *model_node, "class_labels" ); fs.release(); +#endif } template<class TInputValue, class TOutputValue> @@ -326,7 +377,11 @@ bool NeuralNetworkMachineLearningModel<TInputValue, TOutputValue>::CanReadFile(c std::string line; std::getline(ifs, line); - if (line.find(CV_TYPE_NAME_ML_ANN_MLP) != std::string::npos) + if (line.find(CV_TYPE_NAME_ML_ANN_MLP) != std::string::npos +#ifdef OTB_OPENCV_3 + || line.find(m_ANNModel->getDefaultName()) != std::string::npos +#endif + ) { //std::cout << "Reading a " << CV_TYPE_NAME_ML_ANN_MLP << " model" << std::endl; return true; diff --git a/Modules/Learning/Supervised/include/otbNormalBayesMachineLearningModel.h b/Modules/Learning/Supervised/include/otbNormalBayesMachineLearningModel.h index e659470983e863c21f3139c0f66467c7c3d626d0..0b1ddc2c3c03512cd482f88fdb0dd330959aa6d4 100644 --- a/Modules/Learning/Supervised/include/otbNormalBayesMachineLearningModel.h +++ b/Modules/Learning/Supervised/include/otbNormalBayesMachineLearningModel.h @@ -27,8 +27,11 @@ #include "itkFixedArray.h" #include "otbMachineLearningModel.h" - +#ifdef OTB_OPENCV_3 +#include "otbOpenCVUtils.h" +#else class CvNormalBayesClassifier; +#endif namespace otb { @@ -90,8 +93,11 @@ protected: private: NormalBayesMachineLearningModel(const Self &); //purposely not implemented void operator =(const Self&); //purposely not implemented - +#ifdef OTB_OPENCV_3 + cv::Ptr<cv::ml::NormalBayesClassifier> m_NormalBayesModel; +#else CvNormalBayesClassifier * m_NormalBayesModel; +#endif }; } // end namespace otb diff --git a/Modules/Learning/Supervised/include/otbNormalBayesMachineLearningModel.txx b/Modules/Learning/Supervised/include/otbNormalBayesMachineLearningModel.txx index 1562a9b2c190ce9c1426064a114372df331fb32b..a1977850548288eb5c75d79b27e02c7a6e66a82b 100644 --- a/Modules/Learning/Supervised/include/otbNormalBayesMachineLearningModel.txx +++ b/Modules/Learning/Supervised/include/otbNormalBayesMachineLearningModel.txx @@ -32,7 +32,11 @@ namespace otb template <class TInputValue, class TOutputValue> NormalBayesMachineLearningModel<TInputValue,TOutputValue> ::NormalBayesMachineLearningModel() : +#ifdef OTB_OPENCV_3 + m_NormalBayesModel(cv::ml::NormalBayesClassifier::create()) +#else m_NormalBayesModel (new CvNormalBayesClassifier) +#endif { } @@ -41,7 +45,9 @@ template <class TInputValue, class TOutputValue> NormalBayesMachineLearningModel<TInputValue,TOutputValue> ::~NormalBayesMachineLearningModel() { +#ifndef OTB_OPENCV_3 delete m_NormalBayesModel; +#endif } /** Train the machine learning model */ @@ -57,7 +63,22 @@ NormalBayesMachineLearningModel<TInputValue,TOutputValue> cv::Mat labels; otb::ListSampleToMat<TargetListSampleType>(this->GetTargetListSample(),labels); +#ifdef OTB_OPENCV_3 + cv::Mat var_type = cv::Mat(this->GetInputListSample()->GetMeasurementVectorSize() + 1, 1, CV_8U ); + var_type.setTo(cv::Scalar(CV_VAR_NUMERICAL) ); // all inputs are numerical + var_type.at<uchar>(this->GetInputListSample()->GetMeasurementVectorSize(), 0) = CV_VAR_CATEGORICAL; + + m_NormalBayesModel->train(cv::ml::TrainData::create( + samples, + cv::ml::ROW_SAMPLE, + labels, + cv::noArray(), + cv::noArray(), + cv::noArray(), + var_type)); +#else m_NormalBayesModel->train(samples,labels,cv::Mat(),cv::Mat(),false); +#endif } template <class TInputValue, class TOutputValue> @@ -66,6 +87,8 @@ typename NormalBayesMachineLearningModel<TInputValue,TOutputValue> NormalBayesMachineLearningModel<TInputValue,TOutputValue> ::DoPredict(const InputSampleType & input, ConfidenceValueType *quality) const { + TargetSampleType target; + //convert listsample to Mat cv::Mat sample; @@ -75,8 +98,6 @@ NormalBayesMachineLearningModel<TInputValue,TOutputValue> missing.setTo(0); double result = m_NormalBayesModel->predict(sample); - TargetSampleType target; - target[0] = static_cast<TOutputValue>(result); if (quality != ITK_NULLPTR) @@ -86,7 +107,6 @@ NormalBayesMachineLearningModel<TInputValue,TOutputValue> itkExceptionMacro("Confidence index not available for this classifier !"); } } - return target; } @@ -95,10 +115,18 @@ void NormalBayesMachineLearningModel<TInputValue,TOutputValue> ::Save(const std::string & filename, const std::string & name) { +#ifdef OTB_OPENCV_3 + cv::FileStorage fs(filename, cv::FileStorage::WRITE); + fs << (name.empty() ? m_NormalBayesModel->getDefaultName() : cv::String(name)) << "{"; + m_NormalBayesModel->write(fs); + fs << "}"; + fs.release(); +#else if (name == "") m_NormalBayesModel->save(filename.c_str(), ITK_NULLPTR); else m_NormalBayesModel->save(filename.c_str(), name.c_str()); +#endif } template <class TInputValue, class TOutputValue> @@ -106,10 +134,15 @@ void NormalBayesMachineLearningModel<TInputValue,TOutputValue> ::Load(const std::string & filename, const std::string & name) { +#ifdef OTB_OPENCV_3 + cv::FileStorage fs(filename, cv::FileStorage::READ); + m_NormalBayesModel->read(name.empty() ? fs.getFirstTopLevelNode() : fs[name]); +#else if (name == "") m_NormalBayesModel->load(filename.c_str(), ITK_NULLPTR); else m_NormalBayesModel->load(filename.c_str(), name.c_str()); +#endif } template <class TInputValue, class TOutputValue> @@ -131,7 +164,11 @@ NormalBayesMachineLearningModel<TInputValue,TOutputValue> std::string line; std::getline(ifs, line); - if (line.find(CV_TYPE_NAME_ML_NBAYES) != std::string::npos) + if (line.find(CV_TYPE_NAME_ML_NBAYES) != std::string::npos +#ifdef OTB_OPENCV_3 + || line.find(m_NormalBayesModel->getDefaultName()) != std::string::npos +#endif + ) { //std::cout<<"Reading a "<<CV_TYPE_NAME_ML_NBAYES<<" model"<<std::endl; return true; diff --git a/Modules/Learning/Supervised/include/otbOpenCVUtils.h b/Modules/Learning/Supervised/include/otbOpenCVUtils.h index 9061c76f2dbab4bf6be583ce9b427775edfe6560..6e5dc07406ffe6558bda59677784fa5bc126aa3e 100644 --- a/Modules/Learning/Supervised/include/otbOpenCVUtils.h +++ b/Modules/Learning/Supervised/include/otbOpenCVUtils.h @@ -41,10 +41,29 @@ #include <opencv2/ml/ml.hpp> #endif +#include "otb_opencv_api.h" + #include "OTBSupervisedExport.h" #include "itkListSample.h" +#ifdef OTB_OPENCV_3 +#define CV_TYPE_NAME_ML_SVM "opencv-ml-svm" +#define CV_TYPE_NAME_ML_RTREES "opencv-ml-random-trees" +#define CV_TYPE_NAME_ML_BOOSTING "opencv-ml-boost-tree" +#define CV_TYPE_NAME_ML_ANN_MLP "opencv-ml-ann-mlp" +#define CV_TYPE_NAME_ML_NBAYES "opencv-ml-bayesian" +#define CV_TYPE_NAME_ML_TREE "opencv-ml-tree" + +#define CvSVM cv::ml::SVM +#define CvANN_MLP_TrainParams cv::ml::ANN_MLP +#define CvANN_MLP cv::ml::ANN_MLP +#define CvBoost cv::ml::Boost + +#define CV_VAR_NUMERICAL cv::ml::VAR_NUMERICAL +#define CV_VAR_CATEGORICAL cv::ml::VAR_CATEGORICAL +#endif + namespace otb { template <class T> void SampleToMat(const T & sample, cv::Mat& output) diff --git a/Modules/Learning/Supervised/include/otbRandomForestsMachineLearningModel.h b/Modules/Learning/Supervised/include/otbRandomForestsMachineLearningModel.h index d269c67a7d506a4753e3c66fe15d1b74559b5106..04bbbca95184da9f4406f8c902349ba8301adb17 100644 --- a/Modules/Learning/Supervised/include/otbRandomForestsMachineLearningModel.h +++ b/Modules/Learning/Supervised/include/otbRandomForestsMachineLearningModel.h @@ -154,7 +154,11 @@ private: RandomForestsMachineLearningModel(const Self &); //purposely not implemented void operator =(const Self&); //purposely not implemented +#ifdef OTB_OPENCV_3 + cv::Ptr<CvRTreesWrapper> m_RFModel; +#else CvRTreesWrapper * m_RFModel; +#endif /** The depth of the tree. A low value will likely underfit and conversely a * high value will likely overfit. The optimal value can be obtained using cross * validation or other suitable methods. */ diff --git a/Modules/Learning/Supervised/include/otbRandomForestsMachineLearningModel.txx b/Modules/Learning/Supervised/include/otbRandomForestsMachineLearningModel.txx index 0578e79314a3a111418d8481277d036a1ca2bc5e..646bc5936bf1c7232f13d0e3f2404740464ea0ab 100644 --- a/Modules/Learning/Supervised/include/otbRandomForestsMachineLearningModel.txx +++ b/Modules/Learning/Supervised/include/otbRandomForestsMachineLearningModel.txx @@ -32,7 +32,11 @@ namespace otb template <class TInputValue, class TOutputValue> RandomForestsMachineLearningModel<TInputValue,TOutputValue> ::RandomForestsMachineLearningModel() : +#ifdef OTB_OPENCV_3 + m_RFModel(CvRTreesWrapper::create()), +#else m_RFModel (new CvRTreesWrapper), +#endif m_MaxDepth(5), m_MinSampleCount(10), m_RegressionAccuracy(0.01), @@ -42,7 +46,7 @@ RandomForestsMachineLearningModel<TInputValue,TOutputValue> m_MaxNumberOfVariables(0), m_MaxNumberOfTrees(100), m_ForestAccuracy(0.01), - m_TerminationCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS), + m_TerminationCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS), // identic for v3 ? m_ComputeMargin(false) { this->m_ConfidenceIndex = true; @@ -54,7 +58,9 @@ template <class TInputValue, class TOutputValue> RandomForestsMachineLearningModel<TInputValue,TOutputValue> ::~RandomForestsMachineLearningModel() { +#ifndef OTB_OPENCV_3 delete m_RFModel; +#endif } template <class TInputValue, class TOutputValue> @@ -62,7 +68,36 @@ float RandomForestsMachineLearningModel<TInputValue,TOutputValue> ::GetTrainError() { +#ifdef OTB_OPENCV_3 + // TODO + cv::Mat samples; + otb::ListSampleToMat<InputListSampleType>(this->GetInputListSample(), samples); + + cv::Mat labels; + otb::ListSampleToMat<TargetListSampleType>(this->GetTargetListSample(),labels); + + cv::Mat var_type = cv::Mat(this->GetInputListSample()->GetMeasurementVectorSize() + 1, 1, CV_8U ); + var_type.setTo(cv::Scalar(CV_VAR_NUMERICAL) ); // all inputs are numerical + + if(this->m_RegressionMode) + var_type.at<uchar>(this->GetInputListSample()->GetMeasurementVectorSize(), 0) = CV_VAR_NUMERICAL; + else + var_type.at<uchar>(this->GetInputListSample()->GetMeasurementVectorSize(), 0) = CV_VAR_CATEGORICAL; + + return m_RFModel->calcError( + cv::ml::TrainData::create( + samples, + cv::ml::ROW_SAMPLE, + labels, + cv::noArray(), + cv::noArray(), + cv::noArray(), + var_type), + false, + cv::noArray()); +#else return m_RFModel->get_train_error(); +#endif } /** Train the machine learning model */ @@ -77,11 +112,41 @@ RandomForestsMachineLearningModel<TInputValue,TOutputValue> cv::Mat labels; otb::ListSampleToMat<TargetListSampleType>(this->GetTargetListSample(),labels); + + cv::Mat var_type = cv::Mat(this->GetInputListSample()->GetMeasurementVectorSize() + 1, 1, CV_8U ); + var_type.setTo(cv::Scalar(CV_VAR_NUMERICAL) ); // all inputs are numerical + + if(this->m_RegressionMode) + var_type.at<uchar>(this->GetInputListSample()->GetMeasurementVectorSize(), 0) = CV_VAR_NUMERICAL; + else + var_type.at<uchar>(this->GetInputListSample()->GetMeasurementVectorSize(), 0) = CV_VAR_CATEGORICAL; + //Mat var_type = Mat(ATTRIBUTES_PER_SAMPLE + 1, 1, CV_8U ); //std::cout << "priors " << m_Priors[0] << std::endl; //Define random forests paramneters //FIXME do this in the constructor? - +#ifdef OTB_OPENCV_3 + m_RFModel->setMaxDepth(m_MaxDepth); + m_RFModel->setMinSampleCount(m_MinSampleCount); + m_RFModel->setRegressionAccuracy(m_RegressionAccuracy); + m_RFModel->setUseSurrogates(m_ComputeSurrogateSplit); + m_RFModel->setMaxCategories(m_MaxNumberOfCategories); + m_RFModel->setPriors(cv::Mat(m_Priors) ); // TODO + m_RFModel->setCalculateVarImportance(m_CalculateVariableImportance); + m_RFModel->setActiveVarCount(m_MaxNumberOfVariables); + m_RFModel->setTermCriteria( cv::TermCriteria( + m_TerminationCriteria, + m_MaxNumberOfTrees, + m_ForestAccuracy) ); + m_RFModel->train(cv::ml::TrainData::create( + samples, + cv::ml::ROW_SAMPLE, + labels, + cv::noArray(), + cv::noArray(), + cv::noArray(), + var_type)); +#else float * priors = m_Priors.empty() ? ITK_NULLPTR : &m_Priors.front(); CvRTParams params = CvRTParams(m_MaxDepth, // max depth @@ -96,18 +161,10 @@ RandomForestsMachineLearningModel<TInputValue,TOutputValue> m_ForestAccuracy, // forest accuracy m_TerminationCriteria // termination criteria ); - - cv::Mat var_type = cv::Mat(this->GetInputListSample()->GetMeasurementVectorSize() + 1, 1, CV_8U ); - var_type.setTo(cv::Scalar(CV_VAR_NUMERICAL) ); // all inputs are numerical - - if(this->m_RegressionMode) - var_type.at<uchar>(this->GetInputListSample()->GetMeasurementVectorSize(), 0) = CV_VAR_NUMERICAL; - else - var_type.at<uchar>(this->GetInputListSample()->GetMeasurementVectorSize(), 0) = CV_VAR_CATEGORICAL; - //train the RT model m_RFModel->train(samples, CV_ROW_SAMPLE, labels, cv::Mat(), cv::Mat(), var_type, cv::Mat(), params); +#endif } template <class TInputValue, class TOutputValue> @@ -116,6 +173,7 @@ typename RandomForestsMachineLearningModel<TInputValue,TOutputValue> RandomForestsMachineLearningModel<TInputValue,TOutputValue> ::DoPredict(const InputSampleType & value, ConfidenceValueType *quality) const { + TargetSampleType target; //convert listsample to Mat cv::Mat sample; @@ -123,8 +181,6 @@ RandomForestsMachineLearningModel<TInputValue,TOutputValue> double result = m_RFModel->predict(sample); - TargetSampleType target; - target[0] = static_cast<TOutputValue>(result); if (quality != ITK_NULLPTR) @@ -134,7 +190,6 @@ RandomForestsMachineLearningModel<TInputValue,TOutputValue> else (*quality) = m_RFModel->predict_confidence(sample); } - return target[0]; } @@ -143,10 +198,18 @@ void RandomForestsMachineLearningModel<TInputValue,TOutputValue> ::Save(const std::string & filename, const std::string & name) { +#ifdef OTB_OPENCV_3 + cv::FileStorage fs(filename, cv::FileStorage::WRITE); + fs << (name.empty() ? m_RFModel->getDefaultName() : cv::String(name)) << "{"; + m_RFModel->write(fs); + fs << "}"; + fs.release(); +#else if (name == "") m_RFModel->save(filename.c_str(), ITK_NULLPTR); else m_RFModel->save(filename.c_str(), name.c_str()); +#endif } template <class TInputValue, class TOutputValue> @@ -154,10 +217,15 @@ void RandomForestsMachineLearningModel<TInputValue,TOutputValue> ::Load(const std::string & filename, const std::string & name) { +#ifdef OTB_OPENCV_3 + cv::FileStorage fs(filename, cv::FileStorage::READ); + m_RFModel->read(name.empty() ? fs.getFirstTopLevelNode() : fs[name]); +#else if (name == "") m_RFModel->load(filename.c_str(), ITK_NULLPTR); else m_RFModel->load(filename.c_str(), name.c_str()); +#endif } template <class TInputValue, class TOutputValue> @@ -181,7 +249,11 @@ RandomForestsMachineLearningModel<TInputValue,TOutputValue> std::getline(ifs, line); //if (line.find(m_RFModel->getName()) != std::string::npos) - if (line.find(CV_TYPE_NAME_ML_RTREES) != std::string::npos) + if (line.find(CV_TYPE_NAME_ML_RTREES) != std::string::npos +#ifdef OTB_OPENCV_3 + || line.find(m_RFModel->getDefaultName()) != std::string::npos +#endif + ) { //std::cout<<"Reading a "<<CV_TYPE_NAME_ML_RTREES<<" model"<<std::endl; return true; diff --git a/Modules/Learning/Supervised/include/otbRequiresOpenCVCheck.h b/Modules/Learning/Supervised/include/otbRequiresOpenCVCheck.h index 391823d13966dde521bc42853e4181877267548f..ccdbd0d126ce9efff8048875d8739d458ecc904f 100644 --- a/Modules/Learning/Supervised/include/otbRequiresOpenCVCheck.h +++ b/Modules/Learning/Supervised/include/otbRequiresOpenCVCheck.h @@ -26,4 +26,6 @@ # error "You need to enable OpenCV to compile this file" #endif +#include "otb_opencv_api.h" + #endif diff --git a/Modules/Learning/Supervised/include/otbSVMMachineLearningModel.h b/Modules/Learning/Supervised/include/otbSVMMachineLearningModel.h index 27586d75a89d50fb112cd2740bb5d50326c92829..07059be9b8c0a0a42f78f8fc9753da1e365c8a5b 100644 --- a/Modules/Learning/Supervised/include/otbSVMMachineLearningModel.h +++ b/Modules/Learning/Supervised/include/otbSVMMachineLearningModel.h @@ -26,7 +26,11 @@ #include "itkFixedArray.h" #include "otbMachineLearningModel.h" +#ifdef OTB_OPENCV_3 +#include "otbOpenCVUtils.h" +#else class CvSVM; +#endif namespace otb { @@ -146,8 +150,11 @@ protected: private: SVMMachineLearningModel(const Self &); //purposely not implemented void operator =(const Self&); //purposely not implemented - +#ifdef OTB_OPENCV_3 + cv::Ptr<cv::ml::SVM> m_SVMModel; +#else CvSVM * m_SVMModel; +#endif int m_SVMType; int m_KernelType; double m_Degree; diff --git a/Modules/Learning/Supervised/include/otbSVMMachineLearningModel.txx b/Modules/Learning/Supervised/include/otbSVMMachineLearningModel.txx index 67a8964e12b3be672e6e156e8546af6d9a3bffb1..2ff1154102f2b182098c0f82268ae7fc03d3a243 100644 --- a/Modules/Learning/Supervised/include/otbSVMMachineLearningModel.txx +++ b/Modules/Learning/Supervised/include/otbSVMMachineLearningModel.txx @@ -32,7 +32,11 @@ namespace otb template <class TInputValue, class TOutputValue> SVMMachineLearningModel<TInputValue,TOutputValue> ::SVMMachineLearningModel() : +#ifdef OTB_OPENCV_3 + m_SVMModel(cv::ml::SVM::create()), +#else m_SVMModel (new CvSVM), +#endif m_SVMType(CvSVM::C_SVC), m_KernelType(CvSVM::RBF), m_Degree(0), @@ -61,7 +65,9 @@ template <class TInputValue, class TOutputValue> SVMMachineLearningModel<TInputValue,TOutputValue> ::~SVMMachineLearningModel() { +#ifndef OTB_OPENCV_3 delete m_SVMModel; +#endif } /** Train the machine learning model */ @@ -85,6 +91,53 @@ SVMMachineLearningModel<TInputValue,TOutputValue> cv::Mat labels; otb::ListSampleToMat<TargetListSampleType>(this->GetTargetListSample(),labels); +#ifdef OTB_OPENCV_3 + cv::Mat var_type = cv::Mat(this->GetInputListSample()->GetMeasurementVectorSize() + 1, 1, CV_8U ); + var_type.setTo(cv::Scalar(CV_VAR_NUMERICAL) ); // all inputs are numerical + + if (!this->m_RegressionMode) //Classification + var_type.at<uchar>(this->GetInputListSample()->GetMeasurementVectorSize(), 0) = CV_VAR_CATEGORICAL; + + m_SVMModel->setType(m_SVMType); + m_SVMModel->setKernel(m_KernelType); + m_SVMModel->setDegree(m_Degree); + m_SVMModel->setGamma(m_Gamma); + m_SVMModel->setCoef0(m_Coef0); + m_SVMModel->setC(m_C); + m_SVMModel->setNu(m_Nu); + m_SVMModel->setP(m_P); + m_SVMModel->setTermCriteria(cv::TermCriteria(m_TermCriteriaType,m_MaxIter,m_Epsilon)); + + if (!m_ParameterOptimization) + { + m_SVMModel->train(cv::ml::TrainData::create( + samples, + cv::ml::ROW_SAMPLE, + labels, + cv::noArray(), + cv::noArray(), + cv::noArray(), + var_type)); + } + else + { + m_SVMModel->trainAuto(cv::ml::TrainData::create( + samples, + cv::ml::ROW_SAMPLE, + labels, + cv::noArray(), + cv::noArray(), + cv::noArray(), + var_type)); + } + + m_OutputDegree = m_SVMModel->getDegree(); + m_OutputGamma = m_SVMModel->getGamma(); + m_OutputCoef0 = m_SVMModel->getCoef0(); + m_OutputC = m_SVMModel->getC(); + m_OutputNu = m_SVMModel->getNu(); + m_OutputP = m_SVMModel->getP(); +#else // Set up SVM's parameters CvTermCriteria term_crit = cvTermCriteria(m_TermCriteriaType, m_MaxIter, m_Epsilon); CvSVMParams params( m_SVMType, m_KernelType, m_Degree, m_Gamma, m_Coef0, m_C, m_Nu, m_P, ITK_NULLPTR , term_crit ); @@ -114,7 +167,7 @@ SVMMachineLearningModel<TInputValue,TOutputValue> m_OutputC = m_SVMModel->get_params().C; m_OutputNu = m_SVMModel->get_params().nu; m_OutputP = m_SVMModel->get_params().p; - +#endif } template <class TInputValue, class TOutputValue> @@ -123,22 +176,28 @@ typename SVMMachineLearningModel<TInputValue,TOutputValue> SVMMachineLearningModel<TInputValue,TOutputValue> ::DoPredict(const InputSampleType & input, ConfidenceValueType *quality) const { + TargetSampleType target; //convert listsample to Mat cv::Mat sample; otb::SampleToMat<InputSampleType>(input,sample); +#ifdef OTB_OPENCV_3 + double result = m_SVMModel->predict(sample); +#else double result = m_SVMModel->predict(sample,false); - - TargetSampleType target; +#endif target[0] = static_cast<TOutputValue>(result); if (quality != ITK_NULLPTR) { +#ifdef OTB_OPENCV_3 + (*quality) = m_SVMModel->predict(sample,cv::noArray(),cv::ml::StatModel::RAW_OUTPUT); +#else (*quality) = m_SVMModel->predict(sample,true); +#endif } - return target; } @@ -147,10 +206,18 @@ void SVMMachineLearningModel<TInputValue,TOutputValue> ::Save(const std::string & filename, const std::string & name) { +#ifdef OTB_OPENCV_3 + cv::FileStorage fs(filename, cv::FileStorage::WRITE); + fs << (name.empty() ? m_SVMModel->getDefaultName() : cv::String(name)) << "{"; + m_SVMModel->write(fs); + fs << "}"; + fs.release(); +#else if (name == "") m_SVMModel->save(filename.c_str(), ITK_NULLPTR); else m_SVMModel->save(filename.c_str(), name.c_str()); +#endif } template <class TInputValue, class TOutputValue> @@ -158,10 +225,15 @@ void SVMMachineLearningModel<TInputValue,TOutputValue> ::Load(const std::string & filename, const std::string & name) { +#ifdef OTB_OPENCV_3 + cv::FileStorage fs(filename, cv::FileStorage::READ); + m_SVMModel->read(name.empty() ? fs.getFirstTopLevelNode() : fs[name]); +#else if (name == "") m_SVMModel->load(filename.c_str(), ITK_NULLPTR); else m_SVMModel->load(filename.c_str(), name.c_str()); +#endif } template <class TInputValue, class TOutputValue> @@ -184,7 +256,11 @@ SVMMachineLearningModel<TInputValue,TOutputValue> std::getline(ifs, line); //if (line.find(m_SVMModel->getName()) != std::string::npos) - if (line.find(CV_TYPE_NAME_ML_SVM) != std::string::npos) + if (line.find(CV_TYPE_NAME_ML_SVM) != std::string::npos +#ifdef OTB_OPENCV_3 + || line.find(m_SVMModel->getDefaultName()) != std::string::npos +#endif + ) { //std::cout<<"Reading a "<<CV_TYPE_NAME_ML_SVM<<" model"<<std::endl; return true; diff --git a/Modules/Learning/Supervised/src/otbCvRTreesWrapper.cxx b/Modules/Learning/Supervised/src/otbCvRTreesWrapper.cxx index 4b84403654c211bf0e3467e5c54156d75f695093..ddc3a821d8f3bb1b9aae69c2559f9b8af543dad1 100644 --- a/Modules/Learning/Supervised/src/otbCvRTreesWrapper.cxx +++ b/Modules/Learning/Supervised/src/otbCvRTreesWrapper.cxx @@ -25,14 +25,72 @@ namespace otb { -CvRTreesWrapper::CvRTreesWrapper(){} +CvRTreesWrapper::CvRTreesWrapper() +{ +#ifdef OTB_OPENCV_3 + m_Impl = cv::ml::RTrees::create(); +#endif +} -CvRTreesWrapper::~CvRTreesWrapper(){} +CvRTreesWrapper::~CvRTreesWrapper() +{ +} void CvRTreesWrapper::get_votes(const cv::Mat& sample, const cv::Mat& missing, CvRTreesWrapper::VotesVectorType& vote_count) const { +#ifdef OTB_OPENCV_3 + // missing samples not implemented yet + (void) missing; + + // Here we have to re-implement a basic "predict_tree()" since the function is + // not exposed anymore + const std::vector< cv::ml::DTrees::Node > &nodes = m_Impl->getNodes(); + const std::vector< cv::ml::DTrees::Split > &splits = m_Impl->getSplits(); + const std::vector<int> &roots = m_Impl->getRoots(); + int ntrees = roots.size(); + int nodeIdx, prevNodeIdx; + int predictedClass = -1; + const float* samplePtr = sample.ptr<float>(); + std::map<int, unsigned int> votes; + + for (int t=0; t<ntrees ; t++) + { + nodeIdx = roots[t]; + prevNodeIdx = nodeIdx; + while(1) + { + prevNodeIdx = nodeIdx; + const cv::ml::DTrees::Node &curNode = nodes[nodeIdx]; + // test if this node is a leaf + if (curNode.split < 0) + break; + const cv::ml::DTrees::Split& split = splits[curNode.split]; + int varIdx = split.varIdx; + float val = samplePtr[varIdx]; + nodeIdx = val <= split.c ? curNode.left : curNode.right; + } + predictedClass = nodes[prevNodeIdx].classIdx; + votes[predictedClass] += 1; + } + + vote_count.resize(votes.size()); + int pos=0; + for (std::map<int, unsigned int>::const_iterator it=votes.begin() ; + it != votes.end() ; + ++it) + { + vote_count[pos] = it->second; + pos++; + } + + if (vote_count.size() == 1) + { + // give at least 2 classes + vote_count.push_back(0); + } +#else vote_count.resize(nclasses); for( int k = 0; k < ntrees; k++ ) { @@ -41,11 +99,15 @@ void CvRTreesWrapper::get_votes(const cv::Mat& sample, CV_Assert( 0 <= class_idx && class_idx < nclasses ); ++vote_count[class_idx]; } +#endif } float CvRTreesWrapper::predict_margin(const cv::Mat& sample, const cv::Mat& missing) const { +#ifdef OTB_OPENCV_3 + int ntrees = m_Impl->getRoots().size(); +#endif // Sanity check (division by ntrees later on) if(ntrees == 0) { @@ -63,6 +125,9 @@ float CvRTreesWrapper::predict_margin(const cv::Mat& sample, float CvRTreesWrapper::predict_confidence(const cv::Mat& sample, const cv::Mat& missing) const { +#ifdef OTB_OPENCV_3 + int ntrees = m_Impl->getRoots().size(); +#endif // Sanity check (division by ntrees later on) if(ntrees == 0) { @@ -76,4 +141,106 @@ float CvRTreesWrapper::predict_confidence(const cv::Mat& sample, return confidence; } +#ifdef OTB_OPENCV_3 +#define OTB_CV_WRAP_IMPL(type,name) \ +type CvRTreesWrapper::get##name() const \ +{ return m_Impl->get##name(); } \ +void CvRTreesWrapper::set##name(type val) \ +{ m_Impl->set##name(val); } + +#define OTB_CV_WRAP_IMPL_REF(type,name) \ +type CvRTreesWrapper::get##name() const \ +{ return m_Impl->get##name(); } \ +void CvRTreesWrapper::set##name(const type &val) \ +{ m_Impl->set##name(val); } + +#define OTB_CV_WRAP_IMPL_CSTREF_GET(type, name) \ +const type& CvRTreesWrapper::get##name() const \ +{ return m_Impl->get##name(); } + +// TODO : wrap all method used +OTB_CV_WRAP_IMPL(int, MaxCategories) +OTB_CV_WRAP_IMPL(int, MaxDepth) +OTB_CV_WRAP_IMPL(int, MinSampleCount) +OTB_CV_WRAP_IMPL(bool, UseSurrogates) +OTB_CV_WRAP_IMPL(int, CVFolds) +OTB_CV_WRAP_IMPL(bool, Use1SERule) +OTB_CV_WRAP_IMPL(bool,TruncatePrunedTree) +OTB_CV_WRAP_IMPL(float, RegressionAccuracy) +OTB_CV_WRAP_IMPL(bool, CalculateVarImportance) +OTB_CV_WRAP_IMPL(int, ActiveVarCount) +OTB_CV_WRAP_IMPL_REF(cv::Mat, Priors) +OTB_CV_WRAP_IMPL_REF(cv::TermCriteria, TermCriteria) + +OTB_CV_WRAP_IMPL_CSTREF_GET(std::vector<int>, Roots) +OTB_CV_WRAP_IMPL_CSTREF_GET(std::vector<cv::ml::DTrees::Node>, Nodes) +OTB_CV_WRAP_IMPL_CSTREF_GET(std::vector<cv::ml::DTrees::Split>, Splits) +OTB_CV_WRAP_IMPL_CSTREF_GET(std::vector<int>, Subsets) + +int CvRTreesWrapper::getVarCount() const +{ + return m_Impl->getVarCount(); +} + +bool CvRTreesWrapper::isTrained() const +{ + return m_Impl->isTrained(); +} + +bool CvRTreesWrapper::isClassifier() const +{ + return m_Impl->isClassifier(); +} + +cv::Mat CvRTreesWrapper::getVarImportance() const +{ + return m_Impl->getVarImportance(); +} + +cv::String CvRTreesWrapper::getDefaultName () const +{ + return m_Impl->getDefaultName(); +} + + +void CvRTreesWrapper::read (const cv::FileNode &fn) +{ + m_Impl->read(fn); +} + +void CvRTreesWrapper::write (cv::FileStorage &fs) const +{ + m_Impl->write(fs); +} + +void CvRTreesWrapper::save (const cv::String &filename) const +{ + m_Impl->save(filename); +} + +bool CvRTreesWrapper::train(cv::InputArray samples, int layout, cv::InputArray responses) +{ + return m_Impl->train(samples,layout, responses); +} + +bool CvRTreesWrapper::train( const cv::Ptr<cv::ml::TrainData>& trainData, int flags ) +{ + return m_Impl->train(trainData, flags); +} + +float CvRTreesWrapper::predict (cv::InputArray samples, cv::OutputArray results, int flags) const +{ + return m_Impl->predict(samples, results, flags); +} + +cv::Ptr<CvRTreesWrapper> CvRTreesWrapper::create() + { + return cv::makePtr<CvRTreesWrapper>(); + } + +#undef OTB_CV_WRAP_IMPL +#undef OTB_CV_WRAP_IMPL_REF +#undef OTB_CV_WRAP_IMPL_CSTREF_GET +#endif + } diff --git a/Modules/Learning/Supervised/test/otbMachineLearningModelCanRead.cxx b/Modules/Learning/Supervised/test/otbMachineLearningModelCanRead.cxx index 983ffb841b009dcb15e8d8f8fef2fc898acf03bf..49faadbebe6a450d48c1bf8c4e958f4b508fa65a 100644 --- a/Modules/Learning/Supervised/test/otbMachineLearningModelCanRead.cxx +++ b/Modules/Learning/Supervised/test/otbMachineLearningModelCanRead.cxx @@ -236,7 +236,7 @@ int otbDecisionTreeMachineLearningModelCanRead(int argc, char* argv[]) return EXIT_SUCCESS; } - +#ifndef OTB_OPENCV_3 int otbGradientBoostedTreeMachineLearningModelCanRead(int argc, char* argv[]) { if (argc != 2) @@ -263,7 +263,7 @@ int otbGradientBoostedTreeMachineLearningModelCanRead(int argc, char* argv[]) return EXIT_SUCCESS; } - +#endif int otbKNNMachineLearningModelCanRead(int argc, char* argv[]) { if (argc != 2) diff --git a/Modules/Learning/Supervised/test/otbMachineLearningRegressionTests.cxx b/Modules/Learning/Supervised/test/otbMachineLearningRegressionTests.cxx index 7d24ebfccd195375766b71414bbe937e29f942a1..9fdd4ad0639bc2ebeb4fab86ce655ae3b3d17d4f 100644 --- a/Modules/Learning/Supervised/test/otbMachineLearningRegressionTests.cxx +++ b/Modules/Learning/Supervised/test/otbMachineLearningRegressionTests.cxx @@ -225,7 +225,7 @@ int testRegression(SampleGeneratorType& sg, RegressionType& rgrsn, RegressionTes rmse = sqrt( rmse / static_cast<double>(param.count) ); std::cout << "RMSE = "<< rmse << std::endl; - if(rmse > param.eps) + if(rmse > param.eps || vnl_math_isnan(rmse)) { std::cout << "Failed : RMSE above expected precision !" << std::endl; return EXIT_FAILURE; @@ -317,9 +317,8 @@ MachineLearningModelRegressionType::Pointer getNeuralNetworkRegressionModel(unsi regression->SetBackPropDWScale(0.1); regression->SetBackPropMomentScale(0.1); regression->SetRegPropDW0(0.1); - regression->SetRegPropDWMin(1e-7); regression->SetTermCriteriaType(CV_TERMCRIT_EPS); - regression->SetEpsilon(1e-5); + regression->SetEpsilon(1e-6); regression->SetMaxIter(1e4); return regression.GetPointer(); } @@ -334,7 +333,7 @@ int otbNeuralNetworkRegressionTests(int itkNotUsed(argc), RegressionTestParam param; param.vMin = -0.5; param.vMax = 0.5; - param.count = 20000; + param.count = 2000; param.eps = otb_epsilon_01; std::cout << "Testing regression on a linear monovariate function" << std::endl; @@ -493,7 +492,7 @@ int otbDecisionTreeRegressionTests(int itkNotUsed(argc), return status; } - +#ifndef OTB_OPENCV_3 MachineLearningModelRegressionType::Pointer getGradientBoostedTreeRegressionModel() { typedef otb::GradientBoostedTreeMachineLearningModel<InputValueRegressionType, @@ -554,6 +553,7 @@ int otbGradientBoostedTreeRegressionTests(int itkNotUsed(argc), } return status; } +#endif MachineLearningModelRegressionType::Pointer getKNearestNeighborsRegressionModel() @@ -650,7 +650,7 @@ int otbRandomForestsRegressionTests(int itkNotUsed(argc), std::cout << "Testing regression on a bilinear function" << std::endl; BilinearFunctionSampleGenerator<PrecisionType> bfsg(2.0,-1.0,1.0); // increase number of training samples for bilinear function - param.count = 1000; + param.count = 1500; regression = getRandomForestsRegressionModel(); ret = testRegression(bfsg,regression,param); if (ret == EXIT_FAILURE) diff --git a/Modules/Learning/Supervised/test/otbSupervisedTestDriver.cxx b/Modules/Learning/Supervised/test/otbSupervisedTestDriver.cxx index a91c4a860431ef7daa8bbc3e37e7a7c89e06b664..d96021c156c46b0e7d72ccac06f0d9006c0eb8b5 100644 --- a/Modules/Learning/Supervised/test/otbSupervisedTestDriver.cxx +++ b/Modules/Learning/Supervised/test/otbSupervisedTestDriver.cxx @@ -20,6 +20,10 @@ #include "otbTestMain.h" +#ifdef OTB_USE_OPENCV +#include "otb_opencv_api.h" +#endif + void RegisterTests() { REGISTER_TEST(otbConfusionMatrixCalculatorNew); @@ -42,7 +46,9 @@ void RegisterTests() REGISTER_TEST(otbNeuralNetworkMachineLearningModelCanRead); REGISTER_TEST(otbNormalBayesMachineLearningModelCanRead); REGISTER_TEST(otbDecisionTreeMachineLearningModelCanRead); + #ifndef OTB_OPENCV_3 REGISTER_TEST(otbGradientBoostedTreeMachineLearningModelCanRead); + #endif REGISTER_TEST(otbKNNMachineLearningModelCanRead); #endif @@ -68,12 +74,14 @@ void RegisterTests() REGISTER_TEST(otbNormalBayesMachineLearningModel); REGISTER_TEST(otbDecisionTreeMachineLearningModelNew); REGISTER_TEST(otbDecisionTreeMachineLearningModel); + #ifndef OTB_OPENCV_3 REGISTER_TEST(otbGradientBoostedTreeMachineLearningModelNew); REGISTER_TEST(otbGradientBoostedTreeMachineLearningModel); + REGISTER_TEST(otbGradientBoostedTreeRegressionTests); + #endif REGISTER_TEST(otbNeuralNetworkRegressionTests); REGISTER_TEST(otbSVMRegressionTests); REGISTER_TEST(otbDecisionTreeRegressionTests); - REGISTER_TEST(otbGradientBoostedTreeRegressionTests); REGISTER_TEST(otbKNearestNeighborsRegressionTests); REGISTER_TEST(otbRandomForestsRegressionTests); #endif diff --git a/Modules/Learning/Supervised/test/otbTrainMachineLearningModel.cxx b/Modules/Learning/Supervised/test/otbTrainMachineLearningModel.cxx index b29536c3cfb82e1b936a2aae2369352dfd372d33..590fae174907817e0ed525cda4d56c1d3e78e2d0 100644 --- a/Modules/Learning/Supervised/test/otbTrainMachineLearningModel.cxx +++ b/Modules/Learning/Supervised/test/otbTrainMachineLearningModel.cxx @@ -955,7 +955,7 @@ int otbDecisionTreeMachineLearningModel(int argc, char * argv[]) } } - +#ifndef OTB_OPENCV_3 int otbGradientBoostedTreeMachineLearningModelNew(int itkNotUsed(argc), char * itkNotUsed(argv) []) { typedef otb::GradientBoostedTreeMachineLearningModel<InputValueType,TargetValueType> GBTreeType; @@ -1037,6 +1037,7 @@ int otbGradientBoostedTreeMachineLearningModel(int argc, char * argv[]) return EXIT_FAILURE; } } +#endif // if not OpenCV 3 #endif #ifdef OTB_USE_SHARK diff --git a/Modules/Learning/Supervised/test/tests-opencv.cmake b/Modules/Learning/Supervised/test/tests-opencv.cmake index ade123bd9d26c28e38f0f65d6bceb78d54da9220..a309c341dc2b06f83d53b4a4aeab2305b9cf68a1 100644 --- a/Modules/Learning/Supervised/test/tests-opencv.cmake +++ b/Modules/Learning/Supervised/test/tests-opencv.cmake @@ -42,10 +42,11 @@ otb_add_test(NAME leTvSVMMachineLearningModelReg COMMAND otbSupervisedTestDriver otb_add_test(NAME leTvDecisionTreeMachineLearningModelReg COMMAND otbSupervisedTestDriver otbDecisionTreeRegressionTests ) - +if(NOT OTB_OPENCV_3) otb_add_test(NAME leTvGradientBoostedTreeMachineLearningModelReg COMMAND otbSupervisedTestDriver otbGradientBoostedTreeRegressionTests ) +endif() otb_add_test(NAME leTvKNearestNeighborsMachineLearningModelReg COMMAND otbSupervisedTestDriver otbKNearestNeighborsRegressionTests @@ -86,11 +87,15 @@ otb_add_test(NAME leTvNormalBayesMachineLearningModel COMMAND otbSupervisedTestD ${TEMP}/normalbayes_model.txt ) +if(NOT OTB_OPENCV_3) otb_add_test(NAME leTvGradientBoostedTreeMachineLearningModel COMMAND otbSupervisedTestDriver otbGradientBoostedTreeMachineLearningModel ${INPUTDATA}/letter.scale ${TEMP}/gbt_model.txt ) +otb_add_test(NAME leTuGradientBoostedTreeMachineLearningModelNew COMMAND otbSupervisedTestDriver + otbGradientBoostedTreeMachineLearningModelNew) +endif() otb_add_test(NAME leTvRandomForestsMachineLearningModel COMMAND otbSupervisedTestDriver otbRandomForestsMachineLearningModel @@ -98,9 +103,6 @@ otb_add_test(NAME leTvRandomForestsMachineLearningModel COMMAND otbSupervisedTes ${TEMP}/rf_model.txt ) -otb_add_test(NAME leTuGradientBoostedTreeMachineLearningModelNew COMMAND otbSupervisedTestDriver - otbGradientBoostedTreeMachineLearningModelNew) - otb_add_test(NAME leTuANNMachineLearningModelNew COMMAND otbSupervisedTestDriver otbANNMachineLearningModelNew) @@ -141,11 +143,13 @@ otb_add_test(NAME leTvDecisionTreeMachineLearningModelCanRead COMMAND otbSupervi ) set_property(TEST leTvDecisionTreeMachineLearningModelCanRead APPEND PROPERTY DEPENDS leTvDecisionTreeMachineLearningModel) +if(NOT OTB_OPENCV_3) otb_add_test(NAME leTvGradientBoostedTreeMachineLearningModelCanRead COMMAND otbSupervisedTestDriver otbGradientBoostedTreeMachineLearningModelCanRead ${TEMP}/gbt_model.txt ) set_property(TEST leTvGradientBoostedTreeMachineLearningModelCanRead PROPERTY DEPENDS leTvGradientBoostedTreeMachineLearningModel) +endif() otb_add_test(NAME leTvNormalBayesMachineLearningModelCanRead COMMAND otbSupervisedTestDriver otbNormalBayesMachineLearningModelCanRead diff --git a/Modules/ThirdParty/OpenCV/CMakeLists.txt b/Modules/ThirdParty/OpenCV/CMakeLists.txt index c3b7f370fcc70a73e69f52bfd38241d6a49fbd11..224f7318f21b3db89e7fb3848f8658727102bef3 100644 --- a/Modules/ThirdParty/OpenCV/CMakeLists.txt +++ b/Modules/ThirdParty/OpenCV/CMakeLists.txt @@ -20,8 +20,13 @@ project(OTBOpenCV) +configure_file( src/otb_opencv_api.h.in src/otb_opencv_api.h ) + set(OTBOpenCV_SYSTEM_INCLUDE_DIRS ${OPENCV_INCLUDE_DIRS}) set(OTBOpenCV_LIBRARIES "${OPENCV_LIBRARIES}") +set(OTBOpenCV_INCLUDE_DIRS + ${OTBOpenCV_BINARY_DIR}/src + ) set(OTBOpenCV_EXPORT_CODE_BUILD "find_package(OpenCV REQUIRED)") set(OTBOpenCV_EXPORT_CODE_INSTALL ${OTBOpenCV_EXPORT_CODE_BUILD}) diff --git a/Modules/ThirdParty/OpenCV/otb-module-init.cmake b/Modules/ThirdParty/OpenCV/otb-module-init.cmake index 3684290c8fa39b441a6d157ae1f4b11abec4f593..44f58cd474b3156c0bbdbf09158d664b973e31f4 100644 --- a/Modules/ThirdParty/OpenCV/otb-module-init.cmake +++ b/Modules/ThirdParty/OpenCV/otb-module-init.cmake @@ -25,3 +25,9 @@ if("${OpenCV_VERSION}" VERSION_LESS "2.4.0") message(WARNING "The OpenCV version detected (${OpenCV_VERSION}) is older than 2.4.0, " "it may not be fully compatible with OTB") endif() + +if(OpenCV_VERSION_MAJOR EQUAL 3) +set(OTB_OPENCV_3 1) +else() +set(OTB_OPENCV_3 0) +endif() diff --git a/Modules/ThirdParty/OpenCV/src/otb_opencv_api.h.in b/Modules/ThirdParty/OpenCV/src/otb_opencv_api.h.in new file mode 100644 index 0000000000000000000000000000000000000000..8e840a8661c5fad014b088b0b9f82daa772ef8bb --- /dev/null +++ b/Modules/ThirdParty/OpenCV/src/otb_opencv_api.h.in @@ -0,0 +1,25 @@ +/* + * 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 otb_opencv_api_h +#define otb_opencv_api_h + +#cmakedefine OTB_OPENCV_3 + +#endif diff --git a/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSentinel1Model.cpp b/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSentinel1Model.cpp index 71fcec0deef817ca1dac61661422e4b0d98577fb..10ecc6080a69d32de8e12cd55f94b140ab8d50d1 100644 --- a/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSentinel1Model.cpp +++ b/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSentinel1Model.cpp @@ -298,11 +298,13 @@ namespace ossimplugins All these cases should not go slient on error message. It must be FATAL errors. */ - - ossimNotify(ossimNotifyLevel_FATAL) - << MODULE - << " !xmlFileName.exists() || !this->readProduct(xmlFileName) fails \n"; - return false; + if(traceDebug()) + { + ossimNotify(ossimNotifyLevel_DEBUG) + << MODULE + << " !xmlFileName.exists() || !this->readProduct(xmlFileName) fails \n"; + } + return false; } else { diff --git a/Modules/Visualization/Ice/src/otbGlImageActor.cxx b/Modules/Visualization/Ice/src/otbGlImageActor.cxx index 7bdb2b4ca9cc267319cd2731c2668cff90599018..5bb1f06881dd91c94a6b9a6ba6ea8ca578fd7ab4 100644 --- a/Modules/Visualization/Ice/src/otbGlImageActor.cxx +++ b/Modules/Visualization/Ice/src/otbGlImageActor.cxx @@ -1276,7 +1276,7 @@ GlImageActor const Point2d & in, bool isPhysical ) const { - out = ViewportToImageTransform( in, isPhysical ); + out = ImageToViewportTransform( in, isPhysical ); return true; } diff --git a/Modules/Visualization/Monteverdi/src/main.cxx b/Modules/Visualization/Monteverdi/src/main.cxx index feccb84f5e3451e40784f083693ea57d608cb1cc..e44dbb8459d0b239c8bc5c5283d5c41a6412d7ef 100644 --- a/Modules/Visualization/Monteverdi/src/main.cxx +++ b/Modules/Visualization/Monteverdi/src/main.cxx @@ -111,7 +111,7 @@ main( int argc, char* argv[] ) QCoreApplication::translate( PROJECT_NAME, "Usage: %1 [-h|--help] [-a|--applications] [<filename>...]\n" - " -1, --no-glsl force OpenGL 1.x compatible rendering." + " -n, --no-glsl force OpenGL 1.x compatible rendering." " -a, --applications load OTB-applications from OTB_APPLICATIONS_PATH." " -h, --help display this help message.\n" ) @@ -130,7 +130,7 @@ main( int argc, char* argv[] ) it = args.erase( it ); } - else if(it->compare( "-1" )==0 || + else if(it->compare( "-n" )==0 || it->compare( "--no-glsl" )==0 ) { flags.forceNoGLSL = true; diff --git a/Modules/Visualization/MonteverdiGui/include/mvdShaderWidget.h b/Modules/Visualization/MonteverdiGui/include/mvdShaderWidget.h index 971b0d941de3662f2a52dad377bcf9ee4ffbd4ad..4d1b55c63ca5c478c313f5f497fd3c67c37f77d9 100644 --- a/Modules/Visualization/MonteverdiGui/include/mvdShaderWidget.h +++ b/Modules/Visualization/MonteverdiGui/include/mvdShaderWidget.h @@ -146,6 +146,14 @@ private: /** */ void virtual_SetSettings( ImageSettings * ) ITK_OVERRIDE; + /** + * Set the ComboBox effects item for the corresponding image settings. + * This will append or remove effects (lut) depending if settings + * correspond to grayscale image or not. + * \param imageSettings Settings of the current image. + */ + void UpdateComboBoxEffectItems(ImageSettings *imageSettings) ; + // // Private attributes. private: diff --git a/Modules/Visualization/MonteverdiGui/src/mvdShaderWidget.cxx b/Modules/Visualization/MonteverdiGui/src/mvdShaderWidget.cxx index 42dc9facf3e506fedb1d20cc17bb168e275aa476..36680eeaaeb232125c4fca2ff2c8c1c377176758 100644 --- a/Modules/Visualization/MonteverdiGui/src/mvdShaderWidget.cxx +++ b/Modules/Visualization/MonteverdiGui/src/mvdShaderWidget.cxx @@ -83,7 +83,7 @@ ShaderWidget m_UI->valueLineEdit->setValidator( new QDoubleValidator( m_UI->valueLineEdit ) ); -} +} /*******************************************************************************/ ShaderWidget @@ -128,18 +128,18 @@ void ShaderWidget { assert( qApp!=NULL ); - int index = - m_UI->effectComboBox->findText( - qApp->translate( "mvd", EFFECT_NAMES[ effect ] ) - ); + QString effectName = qApp->translate( "mvd", EFFECT_NAMES[ effect ] ); + int index = m_UI->effectComboBox->findText(effectName); if( visible ) { if( index<0 ) - m_UI->effectComboBox->addItem( qApp->translate( "mvd", EFFECT_NAMES[ effect ] ) ); + m_UI->effectComboBox->addItem( effectName ); } else if( index>=0 ) + { m_UI->effectComboBox->removeItem( index ); + } } /*******************************************************************************/ @@ -159,67 +159,45 @@ ShaderWidget { assert( qApp!=NULL ); - for( int i=0; i<m_UI->effectComboBox->count(); ++i ) - if( m_UI->effectComboBox->itemText( i ) - .compare( - qApp->translate( "mvd", - EFFECT_NAMES[ settings->GetEffect() ] ) )==0 ) - { - m_UI->effectComboBox->setCurrentIndex( i ); - - break; - } - - m_UI->sizeSpinBox->setValue( settings->GetSize() ); + const char *imageEffect = EFFECT_NAMES[settings->GetEffect()]; + QString tradEffect = qApp->translate( "mvd", imageEffect ); - char const * const text = settings->GetValueName(); + // Add or remove items from the comboBox + UpdateComboBoxEffectItems(settings); - if( text==NULL ) - { - m_UI->valueLabel->setVisible( false ); - m_UI->valueLabel->setText( QString() ); - } - else + for( int i = 0; i < m_UI->effectComboBox->count(); ++i ) { - m_UI->valueLabel->setVisible( true ); - m_UI->valueLabel->setText( QString( text ).append( ":" ) ); + QString comboBoxEffect = m_UI->effectComboBox->itemText( i ); + if( QString::compare( comboBoxEffect, tradEffect ) == 0 ) + { + // This change will emit currentIndexChanged SIGNAL + // and then call on_effectComboBox_currentIndexChanged + QString oldText = m_UI->effectComboBox->currentText(); + if(m_UI->effectComboBox->currentIndex() != i) + { + m_UI->effectComboBox->setCurrentIndex( i ); + } + break; + } } - - m_UI->valueLineEdit->setVisible( text!=NULL ); - m_UI->valueLineEdit->setText( - settings->HasValue() - ? QString::number( settings->GetValue(), 'g', std::numeric_limits< double >::digits10 ) // ToQString( settings->GetValue() ) - : QString() - ); - m_UI->valueLineEdit->setCursorPosition( 0 ); } - - VectorImageSettings * vis = dynamic_cast<VectorImageSettings*>(settings); - - if(vis!=NULL) - { - GrayscaleActivated(vis->IsGrayscaleActivated()); - } - -} + } /*******************************************************************************/ /* SLOTS */ /*******************************************************************************/ -void -ShaderWidget -::on_effectComboBox_currentIndexChanged( const QString & text ) +void ShaderWidget::on_effectComboBox_currentIndexChanged(const QString &text) { if( !HasSettings() ) return; - assert( qApp!=NULL ); + assert( qApp != NULL ); - for( int i=0; i<EFFECT_COUNT; ++i ) - if( QString::compare( text, qApp->translate( "mvd", EFFECT_NAMES[ i ] ) )==0 ) + for( int i = 0; i < EFFECT_COUNT; ++i ) + if( QString::compare( text, qApp->translate( "mvd", EFFECT_NAMES[i] ) ) == 0 ) { - ImageSettings * settings = GetSettings(); - assert( settings!=NULL ); + ImageSettings *settings = GetSettings(); + assert( settings != NULL ); settings->SetEffect( static_cast< Effect >( i ) ); @@ -228,29 +206,25 @@ ShaderWidget m_UI->sizeSpinBox->setValue( settings->GetSize() ); - char const * const textName = settings->GetValueName(); + char const *const textName = settings->GetValueName(); - if( textName==NULL ) - { - m_UI->valueLabel->setVisible( false ); - m_UI->valueLabel->setText( QString() ); - } + if( textName == NULL ) + { + m_UI->valueLabel->setVisible( false ); + m_UI->valueLabel->setText( QString() ); + } else - { - m_UI->valueLabel->setVisible( true ); - m_UI->valueLabel->setText( QString( textName ).append( ":" ) ); - } - - m_UI->valueLineEdit->setVisible( textName!=NULL ); - m_UI->valueLineEdit->setText( - settings->HasValue() - ? ToQString( settings->GetValue() ) - : QString() - ); + { + m_UI->valueLabel->setVisible( true ); + m_UI->valueLabel->setText( QString( textName ).append( ":" ) ); + } + + m_UI->valueLineEdit->setVisible( textName != NULL ); + m_UI->valueLineEdit->setText( settings->HasValue() ? ToQString( settings->GetValue() ) : QString() ); emit SettingsChanged(); - return; + break; } } @@ -294,7 +268,7 @@ ShaderWidget void ShaderWidget ::GrayscaleActivated(bool status) -{ +{ SetEffectVisible(EFFECT_LUT_JET,status); SetEffectVisible(EFFECT_LUT_LOCAL_JET,status); SetEffectVisible(EFFECT_LUT_HOT,status); @@ -308,4 +282,21 @@ void ShaderWidget SetEffectVisible(EFFECT_SPECTRAL_ANGLE,!status); } + +void ShaderWidget::UpdateComboBoxEffectItems(ImageSettings *imageSettings) +{ + if( imageSettings != NULL ) + { + VectorImageSettings *vis = dynamic_cast<VectorImageSettings *>(imageSettings); + if( vis != NULL ) + { + // Add Gray shader effect to the ComboBox if the image is grayscale. + // Update items in the comboBox but do not fire signal each time an item is removed. + bool oldState = m_UI->effectComboBox->blockSignals( true ); + GrayscaleActivated( vis->IsGrayscaleActivated() ); + m_UI->effectComboBox->blockSignals( oldState ); + } + } +} + } // end namespace 'mvd' diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h index b472376573cdd60b9fb4613bd1ed25d824afe335..c8c5357fb67dafbadaadb2b98bb2869f887862b9 100644 --- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h +++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplication.h @@ -243,7 +243,7 @@ public: * \li ParameterType_Int * \li ParameterType_Radius * \li ParameterType_InputImageParameter - * \li ParameterType_InputComplexImageParameter + * \li ParameterType_ComplexInputImageParameter * \li ParameterType_InputVectorDataParameter * \li ParameterType_OutputImageParameter * \li ParameterType_OutputVectorDataParameter @@ -396,7 +396,7 @@ public: * \li ParameterType_OutputFilename * \li ParameterType_Directory * \li ParameterType_InputImage - * \li ParameterType_InputComplexImage + * \li ParameterType_ComplexInputImage * \li ParameterType_InputVectorData * \li ParameterType_OutputImage * \li ParameterType_OutputVectorData @@ -601,7 +601,7 @@ public: /* Get a complex image value * * Can be called for types : - * \li ParameterType_InputComplexImage + * \li ParameterType_ComplexInputImage */ ComplexFloatVectorImageType* GetParameterComplexImage(std::string parameter); @@ -633,7 +633,7 @@ public: * \li ParameterType_OutputFilename * \li ParameterType_Directory * \li ParameterType_InputImage - * \li ParameterType_InputComplexImage + * \li ParameterType_ComplexInputImage * \li ParameterType_InputVectorData * \li ParameterType_OutputImage * \li ParameterType_OutputVectorData diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperChoiceParameter.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperChoiceParameter.h index da4d4537b7a30d7bcc9e227416878d15aa2e3dad..b376323214a31e02f6846b80d2aed4c7b126e6e3 100644 --- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperChoiceParameter.h +++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperChoiceParameter.h @@ -90,13 +90,14 @@ public: bool HasValue() const ITK_OVERRIDE { - // a choice parameter always has a value - return true; + return !m_ChoiceList.empty(); } void ClearValue() ITK_OVERRIDE { - // nothing to do : a choice parameter always has a value + // Same as constructor init value + // Note that this may be invalid if HasValue() == false + m_CurrentChoice = 0; } protected: diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx index c2d772d151c62a42a8ee3ba9a7e09a496518c66d..16f2a28637401ce72a634f4e4074a9f0bdf3bee9 100644 --- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx +++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx @@ -1015,19 +1015,26 @@ std::string Application::GetParameterString(std::string parameter) Parameter* param = GetParameterByKey(parameter); if (dynamic_cast<ChoiceParameter*>(param)) - { + { ChoiceParameter* paramDown = dynamic_cast<ChoiceParameter*>(param); - std::string choiceKey = paramDown->GetChoiceKey( paramDown->GetValue() ); - size_t lastPointPos = choiceKey.find_last_of('.'); - if(lastPointPos != std::string::npos) + if (paramDown->HasValue()) + { + std::string choiceKey = paramDown->GetChoiceKey( paramDown->GetValue() ); + size_t lastPointPos = choiceKey.find_last_of('.'); + if(lastPointPos != std::string::npos) { - ret = choiceKey.substr(lastPointPos); - } - else + ret = choiceKey.substr(lastPointPos); + } + else { - ret = choiceKey; + ret = choiceKey; } } + else + { + ret = ""; + } + } else if (dynamic_cast<ListViewParameter*>(param)) { ListViewParameter* paramDown = dynamic_cast<ListViewParameter*>(param); diff --git a/SuperBuild/CMake/External_opencv.cmake b/SuperBuild/CMake/External_opencv.cmake index ef09f209da1b5a163e4a593bebf3eb3fdfa668f7..854d09de427b0a9c86456694c46f98b3ca55e8f4 100644 --- a/SuperBuild/CMake/External_opencv.cmake +++ b/SuperBuild/CMake/External_opencv.cmake @@ -34,8 +34,8 @@ ADD_SUPERBUILD_CMAKE_VAR(OPENCV PNG_LIBRARY) ExternalProject_Add(OPENCV PREFIX OPENCV - URL "http://downloads.sourceforge.net/project/opencvlibrary/opencv-unix/2.4.11/opencv-2.4.11.zip" - URL_MD5 32f498451bff1817a60e1aabc2939575 + URL "https://github.com/opencv/opencv/archive/2.4.13.2.tar.gz" + URL_MD5 fe52791ce523681a67036def4c25261b BINARY_DIR ${OPENCV_SB_BUILD_DIR} INSTALL_DIR ${SB_INSTALL_PREFIX} DOWNLOAD_DIR ${DOWNLOAD_LOCATION} diff --git a/SuperBuild/CMake/SuperBuild_Macro.cmake b/SuperBuild/CMake/SuperBuild_Macro.cmake index 242c5dc40e5a975c461baa47e570f0b74fa2a8f4..62d4718e6750f61ffd15fa14274c02ca5d770de1 100644 --- a/SuperBuild/CMake/SuperBuild_Macro.cmake +++ b/SuperBuild/CMake/SuperBuild_Macro.cmake @@ -197,7 +197,7 @@ endmacro() macro(package_require_cxx11 project) if(NOT OTB_HAS_CXX11) - message(FATAL_ERROR "${project} requires C++11 support. consider adding --std=c++11 to your cxx compiler flags or disable ${project} ") + message(FATAL_ERROR "${project} requires C++11 support. consider adding -std=c++11 to your cxx compiler flags or disable ${project} ") endif() endmacro() diff --git a/SuperBuild/patches/OPENCV/opencv-fix-rpath-for-macx.diff b/SuperBuild/patches/OPENCV/opencv-fix-rpath-for-macx.diff deleted file mode 100644 index a251579008dd9c75d7656bc26f81b79eb9417d04..0000000000000000000000000000000000000000 --- a/SuperBuild/patches/OPENCV/opencv-fix-rpath-for-macx.diff +++ /dev/null @@ -1,11 +0,0 @@ -diff -burN opencv-2.4.11.orig/cmake/OpenCVModule.cmake opencv-2.4.11/cmake/OpenCVModule.cmake ---- opencv-2.4.11.orig/cmake/OpenCVModule.cmake 2016-04-19 12:20:03.000000000 +0200 -+++ opencv-2.4.11/cmake/OpenCVModule.cmake 2016-04-19 12:21:06.000000000 +0200 -@@ -589,7 +589,6 @@ - ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} - LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} - RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} -- INSTALL_NAME_DIR lib - ) - - # For dynamic link numbering convenions