diff --git a/CMake/FindOpenCV.cmake b/CMake/FindOpenCV.cmake
index 4f665c7290de7e18282460bebc7b197e423e6ecd..9a6ced7b9f3a6ce3938a1c50d3d7dd7b6f9d8a38 100755
--- a/CMake/FindOpenCV.cmake
+++ b/CMake/FindOpenCV.cmake
@@ -1,64 +1,108 @@
-find_path(
-cv_INCLUDE_DIR
-opencv/cv.h
-DOC "The directory where opencv/cv.h is installed")
-
-find_path(
-opencv2_INCLUDE_DIR
-opencv2/opencv.hpp
-DOC "The directory where opencv2/opencv.hpp is installed")
-
-set(opencv_core_NAMES opencv_core)
-set(opencv_ml_NAMES opencv_ml)
-
-if ( cv_INCLUDE_DIR AND opencv2_INCLUDE_DIR )
-	set(OPENCV_INCLUDE_DIRS "${cv_INCLUDE_DIR};${opencv2_INCLUDE_DIR}")
-	list(REMOVE_DUPLICATES OPENCV_INCLUDE_DIRS)
-
-	if(NOT OpenCV_VERSION)
-		file(READ "${opencv2_INCLUDE_DIR}/opencv2/core/version.hpp" _header_content)
-		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"
-		OpenCV_VERSION_MINOR ${_header_content})
-		string(REGEX REPLACE ".*# *define +CV_VERSION_MINOR +([0-9]+).*" "\\1"
-		OpenCV_VERSION_PATCH ${_header_content})
-		string(REGEX REPLACE ".*# *define +CV_VERSION_REVISION +([0-9]+).*" "\\1"
-		OpenCV_VERSION_TWEAK ${_header_content})
-		set(OpenCV_VERSION
-		"${OpenCV_VERSION_MAJOR}.${OpenCV_VERSION_MINOR}.${OpenCV_VERSION_PATCH}")
-	endif()
-
-	if(WIN32)
-	list(APPEND opencv_core_NAMES
-	"opencv_core${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}")
-	list(APPEND opencv_ml_NAMES
-	"opencv_ml${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}")
-	endif()
-endif()
-
-# Prefer the static library.
-find_library(
-OPENCV_core_LIBRARY
-NAMES ${opencv_core_NAMES}
-DOC "Path to opencv_core library")
-
-find_library(
-OPENCV_ml_LIBRARY
-NAMES ${opencv_ml_NAMES}
-DOC "Path to opencv_ml library")
-
-set(OpenCV_FOUND FALSE)
-if ( OPENCV_core_LIBRARY AND OPENCV_ml_LIBRARY )
-	set(OPENCV_LIBRARIES "${OPENCV_core_LIBRARY};${OPENCV_ml_LIBRARY}")
-endif ()
-
-if( OPENCV_INCLUDE_DIRS AND OPENCV_LIBRARIES )
-  set(OpenCV_FOUND TRUE)
-  set(OPENCV_VERSION ${OpenCV_VERSION}) #for compatility
-endif()
-
-include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENCV
-  REQUIRED_VARS OPENCV_core_LIBRARY OPENCV_INCLUDE_DIRS
-  VERSION_VAR OpenCV_VERSION)
+set(OPENCV_SEARCH_PATH)
+
+if(OpenCV_DIR)
+  get_filename_component(OPENCV_SEARCH_PATH "${OpenCV_DIR}" PATH)
+  if(OPENCV_SEARCH_PATH)
+    get_filename_component(OPENCV_SEARCH_PATH "${OPENCV_SEARCH_PATH}" PATH)
+  endif()
+  if(OPENCV_SEARCH_PATH)
+    find_path(
+      opencv_INCLUDE_DIR
+      opencv/cv.h
+      PATHS "${OPENCV_SEARCH_PATH}"
+      PATH_SUFFIXES "include"
+      DOC "The directory where opencv/cv.h is installed")
+  endif()
+endif()
+
+if(NOT opencv_INCLUDE_DIR)
+  find_path(
+    opencv_INCLUDE_DIR
+    opencv/cv.h
+    PATHS "${OpenCV_DIR}"
+    PATH_SUFFIXES "include"
+    DOC "The directory where opencv/cv.h is installed")
+endif()
+
+if(NOT EXISTS ${opencv_INCLUDE_DIR}/opencv2/opencv.hpp)
+  message(FATAL_ERROR "${opencv_INCLUDE_DIR}/opencv2/opencv.hpp does not exists. "
+    "Make sure you have opencv 2.3 or higher. We had searched in ${OPENCV_SEARCH_PATHS}")
+endif()
+
+set(opencv_core_NAMES opencv_core)
+set(opencv_ml_NAMES opencv_ml)
+
+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)
+      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"
+        OpenCV_VERSION_MINOR ${_header_content})
+      string(REGEX REPLACE ".*# *define +CV_VERSION_MINOR +([0-9]+).*" "\\1"
+        OpenCV_VERSION_PATCH ${_header_content})
+      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"
+        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)
+    endif()
+    set(OpenCV_VERSION
+      "${OpenCV_VERSION_MAJOR}.${OpenCV_VERSION_MINOR}.${OpenCV_VERSION_PATCH}")
+  endif()
+
+  if(WIN32)
+    list(APPEND opencv_core_NAMES
+      "opencv_core${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}")
+    list(APPEND opencv_ml_NAMES
+      "opencv_ml${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}")
+  endif()
+endif()
+
+if(NOT OPENCV_SEARCH_PATH)
+  get_filename_component(OPENCV_SEARCH_PATH "${opencv_INCLUDE_DIR}" PATH)
+endif()
+
+# Prefer the static library.
+find_library(
+  OPENCV_core_LIBRARY
+  NAMES ${opencv_core_NAMES}
+  PATHS ${OPENCV_SEARCH_PATH}
+  PATH_SUFFIXES "lib" "lib64" "lib/x86_64-linux-gnu"
+  NO_DEFAULT_PATH
+  DOC "Path to opencv_core library")
+
+find_library(
+  OPENCV_ml_LIBRARY
+  NAMES ${opencv_ml_NAMES}
+  PATHS ${OPENCV_SEARCH_PATH}
+  PATH_SUFFIXES "lib" "lib64" "lib/x86_64-linux-gnu"
+  NO_DEFAULT_PATH
+  DOC "Path to opencv_ml library")
+
+set(OpenCV_FOUND FALSE)
+if ( OPENCV_core_LIBRARY AND OPENCV_ml_LIBRARY )
+  set(OPENCV_LIBRARIES "${OPENCV_core_LIBRARY};${OPENCV_ml_LIBRARY}")
+endif ()
+
+if( OPENCV_INCLUDE_DIRS AND OPENCV_LIBRARIES )
+  set(OpenCV_FOUND TRUE)
+  set(OPENCV_VERSION ${OpenCV_VERSION}) #for compatility
+endif()
+
+include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenCV
+  REQUIRED_VARS OPENCV_core_LIBRARY OPENCV_INCLUDE_DIRS
+  VERSION_VAR OpenCV_VERSION)
diff --git a/CMake/OTBSetStandardCompilerFlags.cmake b/CMake/OTBSetStandardCompilerFlags.cmake
index 28c40e694dd37652c28dd6b07325e00f5b2d02ee..129eeb075d3cd674d761967c0873d67bdfebbd4c 100644
--- a/CMake/OTBSetStandardCompilerFlags.cmake
+++ b/CMake/OTBSetStandardCompilerFlags.cmake
@@ -73,7 +73,7 @@ function(check_compiler_warning_flags c_warning_flags_var cxx_warning_flags_var)
   ## is reporting 1000's of wanings in windows
   ## header files, for now, limit the number of
   ## warnings to level 3
-  if( WIN32 )
+  if( MSVC )
     set(VerboseWarningsFlag -W3 )
     ## A better solution would be to use -Wall,
     ## and then disable warnings one by one
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 26357a57a010120eb2a95f6c3f3eea677571a160..c37da5d534cf2c4946514fe36c65850b6bda365d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -457,7 +457,7 @@ endforeach()
 # message("OTB_MODULES_ENABLED      = ${modules_list_for_summary}")
 # unset(modules_list_for_summary)
 
-list(REMOVE_ITEM option_list "OTB_USE_6S" "OTB_USE_SIFTFAST" "OTB_USE_OPENCV" "OTB_USE_QT4")
+list(REMOVE_ITEM option_list "OTB_USE_6S" "OTB_USE_SIFTFAST" "OTB_USE_QT4")
 foreach(item ${option_list})
   if(NOT ${item})
     list(REMOVE_ITEM option_list "${item}" )
@@ -475,9 +475,6 @@ list(APPEND option_list TINYXML)
 #RK
 #Q: Why these two guys here? we already have option_list
 #A: Because cmake case sensitivity with variables.
-if(OTB_USE_OPENCV)
-  list(APPEND option_list OpenCV)
-endif()
 
 if(OTB_USE_QT4)
   list(APPEND option_list QT)
diff --git a/Examples/DisparityMap/FineRegistrationImageFilterExample.cxx b/Examples/DisparityMap/FineRegistrationImageFilterExample.cxx
index 0808cf5b4c884240491161a95b11b84b09c9499a..d8900a709e65b1a91afef09039ad25f036727e5c 100644
--- a/Examples/DisparityMap/FineRegistrationImageFilterExample.cxx
+++ b/Examples/DisparityMap/FineRegistrationImageFilterExample.cxx
@@ -181,7 +181,7 @@ int main(int argc, char** argv)
   // We need to set the sub-pixel accuracy we want to obtain:
   //
   // Software Guide : EndLatex
-  registrator->SetSubPixelAccuracy(atof(argv[10]));
+  registrator->SetConvergenceAccuracy(atof(argv[10]));
 
   // Software Guide : BeginLatex
   //
diff --git a/Modules/Applications/AppClassification/app/CMakeLists.txt b/Modules/Applications/AppClassification/app/CMakeLists.txt
index 3f46b917da7fa5c1e6d2e17623635bb6cbcd6e38..982bbaedaef870ea5fe5d292b68479aa8e7bc46c 100644
--- a/Modules/Applications/AppClassification/app/CMakeLists.txt
+++ b/Modules/Applications/AppClassification/app/CMakeLists.txt
@@ -125,3 +125,8 @@ otb_create_application(
   NAME           SampleExtraction
   SOURCES        otbSampleExtraction.cxx
   LINK_LIBRARIES ${${otb-module}_LIBRARIES})
+
+otb_create_application(
+  NAME           MultiImageSamplingRate
+  SOURCES        otbMultiImageSamplingRate.cxx
+  LINK_LIBRARIES ${${otb-module}_LIBRARIES})
diff --git a/Modules/Applications/AppClassification/app/otbMultiImageSamplingRate.cxx b/Modules/Applications/AppClassification/app/otbMultiImageSamplingRate.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..0a33c98a8652d209d57418b1dc8cba96352ed38b
--- /dev/null
+++ b/Modules/Applications/AppClassification/app/otbMultiImageSamplingRate.cxx
@@ -0,0 +1,302 @@
+/*=========================================================================
+
+ 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 "otbWrapperApplication.h"
+#include "otbWrapperApplicationFactory.h"
+#include "otbSamplingRateCalculatorList.h"
+#include "otbStatisticsXMLFileReader.h"
+
+namespace otb
+{
+namespace Wrapper
+{
+
+class MultiImageSamplingRate : public Application
+{
+public:
+  /** Standard class typedefs. */
+  typedef MultiImageSamplingRate        Self;
+  typedef Application                   Superclass;
+  typedef itk::SmartPointer<Self>       Pointer;
+  typedef itk::SmartPointer<const Self> ConstPointer;
+
+  /** Standard macro */
+  itkNewMacro(Self);
+
+  itkTypeMacro(MultiImageSamplingRate, otb::Application);
+
+  /** typedef */
+  typedef otb::SamplingRateCalculatorList           RateCalculatorListType;
+  
+  typedef RateCalculatorListType::ClassCountMapType      ClassCountMapType;
+  typedef RateCalculatorListType::MapRateType           MapRateType;
+
+  typedef itk::VariableLengthVector<float> MeasurementType;
+  typedef otb::StatisticsXMLFileReader<MeasurementType> XMLReaderType;
+
+private:
+  MultiImageSamplingRate()
+    {
+    m_CalculatorList = RateCalculatorListType::New();
+    }
+
+  void DoInit()
+  {
+    SetName("MultiImageSamplingRate");
+    SetDescription("Compute sampling rate for an input set of images.");
+
+    // Documentation
+    SetDocName("Multi-image sampling rate estimation");
+    SetDocLongDescription("The application computes sampling rates for a set of"
+      " input images. Before calling this application, each pair of image and "
+      "training vectors has to be analysed with the application "
+      "PolygonClassStatistics. The statistics file is then used to compute the "
+      "sampling rates for each class in each image. Several types of sampling "
+      " are implemented. Each one is a combination of a mono-image strategy "
+      "and a multi-image mode. The mono-image strategies are :\n"
+      "  - smallest (default) : select the same number of sample in each " 
+      "class so that the smallest one is fully sampled.\n"
+      "  - constant : select the same number of samples N in each class " 
+      "(with N below or equal to the size of the smallest class).\n"
+      "  - byclass : set the required number for each class manually, with an "
+      "input CSV file (first column is class name, second one is the required "
+      "samples number).\n"
+      "The multi-image modes (mim) are : proportional, equal and custom. The custom "
+      "mode lets the users choose the distribution of samples among the "
+      "images. The different behaviours are described below. Ti(c) and Ni(c) "
+      " refers resp. to the total number and needed number of samples in "
+      "image i for class c. Let's call L the total number of images.\n"
+      "  > strategy = all\n"
+      "    + Same behaviour for all modes : take all samples\n"
+      "  > strategy = constant\n"
+      "    (let's call M the global number of samples required per class)\n"
+      "    + mim = proportional : For each image i and each class c,\n"
+      "       Ni( c ) = M * Ti( c ) / sum_k( Tk(c) )\n"
+      "    + mim = equal : For each image i and each class c,\n"
+      "       Ni( c ) = M / L\n"
+      "    + mim = custom : For each image i and each class c,\n"
+      "       Ni( c ) = Mi where Mi is the custom requested number of samples for image i\n"
+      "  > strategy = byClass\n"
+      "    (let's call M(c) the global number of samples for class c)\n"
+      "    + mim = proportional : For each image i and each class c\n"
+      "       Ni( c ) = M(c) * Ti( c ) / sum_k( Tk(c) )\n"
+      "    + mim = equal : For each image i and each class c,\n"
+      "       Ni( c ) = M(c) / L\n"
+      "    + mim = custom : For each image i and each class c,\n"
+      "       Ni( c ) = Mi(c) where Mi(c) is the custom requested number of samples for image i and class c\n"
+      "  > strategy = smallest class\n"
+      "    + mim = proportional :\n"
+      "       The smallest class size (computed globally) is used for the strategy constant+proportional\n"
+      "    + mim = equal :\n"
+      "       The smallest class size (computed globally) is used for the strategy constant+equal\n"
+      "    + mim = custom :\n"
+      "       The smallest class is computed and used for each image separately\n"
+      );
+    SetDocLimitations("None");
+    SetDocAuthors("OTB-Team");
+    SetDocSeeAlso(" ");
+
+    AddDocTag(Tags::Learning);
+
+    AddParameter(ParameterType_InputFilenameList,  "il",   "Input statistics");
+    SetParameterDescription("il", "List of statistics files for each input image.");
+
+    AddParameter(ParameterType_OutputFilename, "out", "Output sampling rates");
+    SetParameterDescription("out","Output filename storing sampling rates (CSV "
+      "format with class name, required samples, total samples, and rate). "
+      "The given filename will be used with a suffix to indicate the "
+      "corresponding input index (for instance: rates.csv will give rates_1.csv"
+      ", rates_2.csv, ...).");
+
+    AddParameter(ParameterType_Choice, "strategy", "Sampling strategy");
+
+    AddChoice("strategy.byclass","Set samples count for each class");
+    SetParameterDescription("strategy.byclass","Set samples count for each class");
+
+    AddParameter(ParameterType_InputFilenameList, "strategy.byclass.in", "Number of samples by class");
+    SetParameterDescription("strategy.byclass.in", "Number of samples by class "
+      "(CSV format with class name in 1st column and required samples in the 2nd)."
+      "In the case of the custom multi-image mode, several inputs may be given for each image.");
+
+    AddChoice("strategy.constant","Set the same samples counts for all classes");
+    SetParameterDescription("strategy.constant","Set the same samples counts for all classes");
+
+    AddParameter(ParameterType_String, "strategy.constant.nb", "Number of samples for all classes");
+    SetParameterDescription("strategy.constant.nb", "Number of samples for all classes."
+      "In the case of the custom multi-image mode, several values can be given for each image.");
+
+    AddChoice("strategy.smallest","Set same number of samples for all classes, with the smallest class fully sampled");
+    SetParameterDescription("strategy.smallest","Set same number of samples for all classes, with the smallest class fully sampled");
+
+    AddChoice("strategy.all","Take all samples");
+    SetParameterDescription("strategy.all","Take all samples");
+
+    // Default strategy : smallest
+    SetParameterString("strategy","smallest");
+
+    AddParameter(ParameterType_Choice, "mim", "Multi-Image Mode");
+
+    AddChoice("mim.proportional", "Proportional");
+    SetParameterDescription("mim.proportional","Split proportionally the required number of samples");
+
+    AddChoice("mim.equal", "equal");
+    SetParameterDescription("mim.equal","Split equally the required number of samples");
+
+    AddChoice("mim.custom", "Custom");
+    SetParameterDescription("mim.custom","Split the required number of samples following user choice.");
+
+    // Doc example parameter settings
+    SetDocExampleParameterValue("il", "stats_1.xml stats_2.xml");
+    SetDocExampleParameterValue("out", "rates.csv");
+    SetDocExampleParameterValue("strategy", "smallest");
+    SetDocExampleParameterValue("mode","proportional");
+  }
+
+  void DoUpdateParameters()
+  {
+  }
+
+  void DoExecute()
+    {
+    // Clear state
+    m_CalculatorList->Clear();
+    std::vector<std::string> inputs = this->GetParameterStringList("il");
+    unsigned int nbInputs = inputs.size();
+    XMLReaderType::Pointer statReader = XMLReaderType::New();
+    for (unsigned int i=0 ; i<nbInputs ; i++ )
+      {
+      m_CalculatorList->PushBack(otb::SamplingRateCalculator::New());
+      statReader->SetFileName(inputs[i]);
+      ClassCountMapType classCount = statReader->GetStatisticMapByName<ClassCountMapType>("samplesPerClass");
+      m_CalculatorList->SetNthClassCount(i,classCount);
+      }
+
+    // Cautions : direct mapping between the enum PartitionType and the choice order
+    RateCalculatorListType::PartitionType partitionMode =
+      static_cast<RateCalculatorListType::PartitionType>(this->GetParameterInt("mim"));
+
+    unsigned int minParamSize = 1;
+    if (partitionMode == RateCalculatorListType::CUSTOM)
+      {
+      // Check we have enough inputs for the custom mode
+      minParamSize = nbInputs;
+      }
+    
+    switch (this->GetParameterInt("strategy"))
+      {
+      // byclass
+      case 0:
+        {
+        std::vector<std::string> requiredFiles = this->GetParameterStringList("strategy.byclass.in");
+        std::vector<ClassCountMapType> requiredCounts;
+        if (requiredFiles.size() < minParamSize)
+          {
+          otbAppLogFATAL("Missing arguments in strategy.byclass.in to process sampling rates");
+          }
+        otbAppLogINFO("Sampling strategy : set number of samples for each class");
+        for (unsigned int i=0 ; i<minParamSize ; i++)
+          {
+          requiredCounts.push_back(otb::SamplingRateCalculator::ReadRequiredSamples(requiredFiles[i]));
+          }
+        m_CalculatorList->SetNbOfSamplesByClass(requiredCounts, partitionMode);
+        }
+      break;
+      // constant
+      case 1:
+        {
+        std::vector<itksys::String> parts = itksys::SystemTools::SplitString(this->GetParameterString("strategy.constant.nb"),' ');
+        std::vector<unsigned long> countList;
+        for (unsigned int i=0 ; i<parts.size() ; i++)
+          {
+          if (!parts[i].empty())
+            {
+            std::string::size_type pos1 = parts[i].find_first_not_of(" \t");
+            std::string::size_type pos2 = parts[i].find_last_not_of(" \t");
+            std::string value(parts[i].substr(pos1, pos2 - pos1 + 1));
+            countList.push_back(boost::lexical_cast<unsigned long>(parts[i]));
+            }
+          }
+        if (countList.size() < minParamSize)
+          {
+          otbAppLogFATAL("Missing arguments in strategy.constant.nb to process sampling rates");
+          }
+        otbAppLogINFO("Sampling strategy : set a constant number of samples for all classes");
+        m_CalculatorList->SetNbOfSamplesAllClasses(countList, partitionMode);
+        }
+      break;
+      // smallest class
+      case 2:
+        {
+        otbAppLogINFO("Sampling strategy : fit the number of samples based on the smallest class");
+        m_CalculatorList->SetMinimumNbOfSamplesByClass(partitionMode);
+        }
+      break;
+      // all samples
+      case 3:
+        {
+        otbAppLogINFO("Sampling strategy : take all samples");
+        m_CalculatorList->SetAllSamples(partitionMode);
+        }
+      break;
+      default:
+        otbAppLogFATAL("Strategy mode unknown :"<<this->GetParameterString("strategy"));
+      break;
+      }
+
+    std::ostringstream oss;    
+    std::string outputPath(this->GetParameterString("out"));
+    std::string outputBase = outputPath.substr(0, outputPath.find_last_of('.'));
+    std::string outputExt = outputPath.substr(outputPath.find_last_of('.'), std::string::npos);
+    unsigned int overflowCount = 0;
+    for (unsigned int i=0 ; i<nbInputs ; i++ )
+      {
+      // Print results
+      oss.str(std::string(""));
+      oss << " className  requiredSamples  totalSamples  rate" << std::endl;
+      MapRateType rates = m_CalculatorList->GetRatesByClass(i);
+      MapRateType::const_iterator itRates = rates.begin();
+      for(; itRates != rates.end(); ++itRates)
+        {
+        otb::SamplingRateCalculator::TripletType tpt = itRates->second;
+        oss << itRates->first << "\t" << tpt.Required << "\t" << tpt.Tot << "\t" << tpt.Rate;
+        if (tpt.Required > tpt.Tot)
+          {
+          overflowCount++;
+          oss << "\t[OVERFLOW]";
+          }
+        oss << std::endl;
+        }
+      otbAppLogINFO("Sampling rates for image "<< i+1 <<" : " << oss.str());
+      // Output results to disk
+      oss.str(std::string(""));
+      oss << outputBase << "_" << i+1 << outputExt;
+      m_CalculatorList->GetNthElement(i)->Write(oss.str());
+      }
+    if (overflowCount)
+      {
+      std::string plural(overflowCount>1?"s":"");
+      otbAppLogWARNING(<< overflowCount << " case"<<plural<<" of overflow detected! (requested number of samples higher than total available samples)");
+      }
+  }
+
+  RateCalculatorListType::Pointer m_CalculatorList;
+};
+
+} // end namespace Wrapper
+} // end namespace otb
+
+OTB_APPLICATION_EXPORT(otb::Wrapper::MultiImageSamplingRate)
diff --git a/Modules/Applications/AppClassification/app/otbSampleSelection.cxx b/Modules/Applications/AppClassification/app/otbSampleSelection.cxx
index 4b401889674b4dee94cb15bb01ad974fecc290d1..35a70a2673d1fd3ae2f4388fdf6505fae667c9f8 100644
--- a/Modules/Applications/AppClassification/app/otbSampleSelection.cxx
+++ b/Modules/Applications/AppClassification/app/otbSampleSelection.cxx
@@ -201,63 +201,6 @@ private:
   {
   }
 
-  ClassCountMapType ReadRequiredSamples(std::string filename)
-    {
-    ClassCountMapType output;
-    std::ifstream ifs(filename.c_str());
-
-    if (ifs)
-      {
-      std::string line;
-      std::string sep("");
-    
-      while(!ifs.eof())
-        {
-        std::getline(ifs,line);
-        if (line.empty()) continue;
-        std::string::size_type pos = line.find_first_not_of(" \t");
-        if (pos != std::string::npos && line[pos] == '#') continue;
-        
-        if (sep.size() == 0)
-          {
-          // Try to detect the separator
-          std::string separators("\t;,");
-          for (unsigned int k=0 ; k<separators.size() ; k++)
-            {
-            std::vector<itksys::String> words = itksys::SystemTools::SplitString(line,separators[k]);
-            if (words.size() >= 2)
-              {
-              sep.push_back(separators[k]);
-              break;
-              }
-            }
-          if (sep.size() == 0) continue;
-          }
-        // parse the line
-        std::vector<itksys::String> parts = itksys::SystemTools::SplitString(line,sep[0]);
-        if (parts.size() >= 2)
-          {
-          std::string::size_type pos1 = parts[0].find_first_not_of(" \t");
-          std::string::size_type pos2 = parts[0].find_last_not_of(" \t");
-          std::string::size_type pos3 = parts[1].find_first_not_of(" \t");
-          std::string::size_type pos4 = parts[1].find_last_not_of(" \t");
-          if (pos1 != std::string::npos && pos3 != std::string::npos)
-            {
-            std::string name = parts[0].substr(pos1, pos2 - pos1 + 1);
-            std::string value = parts[1].substr(pos3, pos4 - pos3 + 1);
-            output[name] = boost::lexical_cast<unsigned long>(value);
-            }
-          }
-        }
-      ifs.close();
-      }
-    else
-      {
-      otbAppLogFATAL(<< " Couldn't open " << filename);
-      }
-    return output;
-    }
-
   void DoExecute()
     {
     // Clear state
@@ -280,7 +223,7 @@ private:
         {
         otbAppLogINFO("Sampling strategy : set number of samples for each class");
         ClassCountMapType requiredCount = 
-          this->ReadRequiredSamples(this->GetParameterString("strategy.byclass.in"));
+          otb::SamplingRateCalculator::ReadRequiredSamples(this->GetParameterString("strategy.byclass.in"));
         m_RateCalculator->SetNbOfSamplesByClass(requiredCount);
         }
       break;
@@ -319,12 +262,24 @@ private:
     std::ostringstream oss;
     oss << " className  requiredSamples  totalSamples  rate" << std::endl;
     MapRateType::const_iterator itRates = rates.begin();
+    unsigned int overflowCount = 0;
     for(; itRates != rates.end(); ++itRates)
       {
       otb::SamplingRateCalculator::TripletType tpt = itRates->second;
-      oss << itRates->first << "\t" << tpt.Required << "\t" << tpt.Tot << "\t" << tpt.Rate << std::endl;
+      oss << itRates->first << "\t" << tpt.Required << "\t" << tpt.Tot << "\t" << tpt.Rate;
+      if (tpt.Required > tpt.Tot)
+        {
+        overflowCount++;
+        oss << "\t[OVERFLOW]";
+        }
+      oss << std::endl;
       }
     otbAppLogINFO("Sampling rates : " << oss.str());
+    if (overflowCount)
+      {
+      std::string plural(overflowCount>1?"s":"");
+      otbAppLogWARNING(<< overflowCount << " case"<<plural<<" of overflow detected! (requested number of samples higher than total available samples)");
+      }
 
     // Open input geometries
     otb::ogr::DataSource::Pointer vectors =
diff --git a/Modules/Applications/AppClassification/app/otbTrainVectorClassifier.cxx b/Modules/Applications/AppClassification/app/otbTrainVectorClassifier.cxx
index 7c9c6d91d8aff60477d5e2a74cf4c3645730def5..09edbc6cf385cb8397ca166d4c9394081e1f6019 100644
--- a/Modules/Applications/AppClassification/app/otbTrainVectorClassifier.cxx
+++ b/Modules/Applications/AppClassification/app/otbTrainVectorClassifier.cxx
@@ -92,7 +92,7 @@ private:
     AddParameter(ParameterType_Group, "io", "Input and output data");
     SetParameterDescription("io", "This group of parameters allows setting input and output data.");
 
-    AddParameter(ParameterType_InputVectorData, "io.vd", "Input Vector Data");
+    AddParameter(ParameterType_InputVectorDataList, "io.vd", "Input Vector Data");
     SetParameterDescription("io.vd", "Input geometries used for training (note : all geometries from the layer will be used)");
 
     AddParameter(ParameterType_InputFilename, "io.stats", "Input XML image statistics file");
@@ -122,7 +122,7 @@ private:
     AddParameter(ParameterType_Group, "valid", "Validation data");
     SetParameterDescription("valid", "This group of parameters defines validation data.");
 
-    AddParameter(ParameterType_InputVectorData, "valid.vd", "Validation Vector Data");
+    AddParameter(ParameterType_InputVectorDataList, "valid.vd", "Validation Vector Data");
     SetParameterDescription("valid.vd", "Geometries used for validation "
       "(must contain the same fields used for training, all geometries from the layer will be used)");
     MandatoryOff("valid.vd");
@@ -148,9 +148,9 @@ private:
   {
     if ( HasValue("io.vd") )
       {
-      std::string vectorFile = GetParameterString("io.vd");
+      std::vector<std::string> vectorFileList = GetParameterStringList("io.vd");
       ogr::DataSource::Pointer ogrDS =
-        ogr::DataSource::New(vectorFile, ogr::DataSource::Modes::Read);
+        ogr::DataSource::New(vectorFileList[0], ogr::DataSource::Modes::Read);
       ogr::Layer layer = ogrDS->GetLayer(this->GetParameterInt("layer"));
       ogr::Feature feature = layer.ogr().GetNextFeature();
 
@@ -242,13 +242,30 @@ void LogConfusionMatrix(ConfusionMatrixCalculatorType* confMatCalc)
 
 void DoExecute()
   {
-  std::string shapefile = GetParameterString("io.vd");
-  std::string modelfile = GetParameterString("io.out");
   typedef int LabelPixelType;
   typedef itk::FixedArray<LabelPixelType,1> LabelSampleType;
   typedef itk::Statistics::ListSample <LabelSampleType> LabelListSampleType;
 
-  const int nbFeatures = GetSelectedItems("feat").size();
+  // Prepare selected field names (their position may change between two inputs)
+  std::vector<int> selectedIdx = GetSelectedItems("feat");
+  const unsigned int nbFeatures = selectedIdx.size();
+  std::vector<std::string> fieldNames = GetChoiceNames("feat");
+  std::vector<std::string> selectedNames(nbFeatures);
+  for (unsigned int i=0 ; i<nbFeatures ; i++)
+    {
+    selectedNames[i] = fieldNames[selectedIdx[i]];
+    }
+  std::vector<int> featureFieldIndex(nbFeatures, -1);
+  int cFieldIndex = -1;
+
+  // List of available fields
+  std::ostringstream oss;
+  for (unsigned int i=0 ; i<fieldNames.size() ; i++)
+    {
+    if (i) oss << ", ";
+    oss << fieldNames[i];
+    }
+  std::string availableFields(oss.str());
 
   // Statistics for shift/scale
   MeasurementType meanMeasurementVector;
@@ -269,50 +286,55 @@ void DoExecute()
     stddevMeasurementVector.Fill(1.);
     }
 
-  ogr::DataSource::Pointer source = ogr::DataSource::New(shapefile, ogr::DataSource::Modes::Read);
-  ogr::Layer layer = source->GetLayer(this->GetParameterInt("layer"));
-  ogr::Feature feature = layer.ogr().GetNextFeature();
-  bool goesOn = feature.addr() != 0;
-
   ListSampleType::Pointer input = ListSampleType::New();
   LabelListSampleType::Pointer target = LabelListSampleType::New();
   input->SetMeasurementVectorSize(nbFeatures);
 
-  int cFieldIndex=-1;
-  std::vector<int> featureFieldIndex = GetSelectedItems("feat");
-  if (feature.addr())
+  std::vector<std::string> vectorFileList = GetParameterStringList("io.vd");
+  for (unsigned int k=0 ; k<vectorFileList.size() ; k++)
     {
-    cFieldIndex = feature.ogr().GetFieldIndex(GetParameterString("cfield").c_str());
-    }
+    otbAppLogINFO("Reading input vector file "<<k+1<<"/"<<vectorFileList.size());
+    ogr::DataSource::Pointer source = ogr::DataSource::New(vectorFileList[k], ogr::DataSource::Modes::Read);
+    ogr::Layer layer = source->GetLayer(this->GetParameterInt("layer"));
+    ogr::Feature feature = layer.ogr().GetNextFeature();
+    bool goesOn = feature.addr() != 0;
+    if (!goesOn)
+      {
+      otbAppLogWARNING("The layer "<<GetParameterInt("layer")<<" of "
+        <<vectorFileList[k]<<" is empty, input is skipped.");
+      continue;
+      }
 
-  // Check that the class field exists
-  if (cFieldIndex < 0)
-    {
-    std::ostringstream oss;
-    std::vector<std::string> names = GetChoiceNames("feat");
-    for (unsigned int i=0 ; i<names.size() ; i++)
+    // Check all needed fields are present :
+    //   - check class field
+    cFieldIndex = feature.ogr().GetFieldIndex(GetParameterString("cfield").c_str());
+    if (cFieldIndex < 0)
+      otbAppLogFATAL("The field name for class label ("<<GetParameterString("cfield")
+        <<") has not been found in the input vector file! Choices are "<< availableFields);
+    //   - check feature fields
+    for (unsigned int i=0 ; i<nbFeatures ; i++)
       {
-      if (i) oss << ", ";
-      oss << names[i];
+      featureFieldIndex[i] = feature.ogr().GetFieldIndex(selectedNames[i].c_str());
+      if (featureFieldIndex[i] < 0)
+        otbAppLogFATAL("The field name for feature "<<selectedNames[i]
+        <<" has not been found in the input vector file! Choices are "<< availableFields);
       }
-    otbAppLogFATAL("The field name for class label ("<<GetParameterString("cfield")
-      <<") has not been found in the input vector file! Choices are "<< oss.str());
-    }
 
-  while(goesOn)
-    {
-    if(feature.ogr().IsFieldSet(cFieldIndex))
+    while(goesOn)
       {
-      MeasurementType mv;
-      mv.SetSize(nbFeatures);
-      for(int idx=0; idx < nbFeatures; ++idx)
-        mv[idx] = feature.ogr().GetFieldAsDouble(featureFieldIndex[idx]);
+      if(feature.ogr().IsFieldSet(cFieldIndex))
+        {
+        MeasurementType mv;
+        mv.SetSize(nbFeatures);
+        for(unsigned int idx=0; idx < nbFeatures; ++idx)
+          mv[idx] = feature.ogr().GetFieldAsDouble(featureFieldIndex[idx]);
 
-      input->PushBack(mv);
-      target->PushBack(feature.ogr().GetFieldAsInteger(cFieldIndex));
+        input->PushBack(mv);
+        target->PushBack(feature.ogr().GetFieldAsInteger(cFieldIndex));
+        }
+      feature = layer.ogr().GetNextFeature();
+      goesOn = feature.addr() != 0;
       }
-    feature = layer.ogr().GetNextFeature();
-    goesOn = feature.addr() != 0;
     }
 
   ShiftScaleFilterType::Pointer trainingShiftScaleFilter = ShiftScaleFilterType::New();
@@ -321,14 +343,8 @@ void DoExecute()
   trainingShiftScaleFilter->SetScales(stddevMeasurementVector);
   trainingShiftScaleFilter->Update();
 
-  ListSampleType::Pointer listSample;
-  LabelListSampleType::Pointer labelListSample;
-
-  listSample = trainingShiftScaleFilter->GetOutput();
-  labelListSample = target;
-
-  ListSampleType::Pointer trainingListSample = listSample;
-  LabelListSampleType::Pointer trainingLabeledListSample = labelListSample;
+  ListSampleType::Pointer trainingListSample= trainingShiftScaleFilter->GetOutput();
+  TargetListSampleType::Pointer trainingLabeledListSample = target;
 
   //--------------------------
   // Estimate model
@@ -344,34 +360,55 @@ void DoExecute()
   // Import validation data
   if (HasValue("valid.vd") && IsParameterEnabled("valid.vd"))
     {
-    std::string validFile = this->GetParameterString("valid.vd");
-    source = ogr::DataSource::New(validFile, ogr::DataSource::Modes::Read);
-    layer = source->GetLayer(this->GetParameterInt("valid.layer"));
-    feature = layer.ogr().GetNextFeature();
-    goesOn = feature.addr() != 0;
-
-    // find useful field indexes
-
-    // TODO : detect corresponding indexes in validation data set, for the moment
-    // Assume they have the same fields, in the same order.
-
     input = ListSampleType::New();
     target = LabelListSampleType::New();
     input->SetMeasurementVectorSize(nbFeatures);
-    while(goesOn)
+
+    std::vector<std::string> validFileList = this->GetParameterStringList("valid.vd");
+    for (unsigned int k=0 ; k<validFileList.size() ; k++)
       {
-      if(feature.ogr().IsFieldSet(cFieldIndex))
+      otbAppLogINFO("Reading validation vector file "<<k+1<<"/"<<validFileList.size());
+      ogr::DataSource::Pointer source = ogr::DataSource::New(validFileList[k], ogr::DataSource::Modes::Read);
+      ogr::Layer layer = source->GetLayer(this->GetParameterInt("valid.layer"));
+      ogr::Feature feature = layer.ogr().GetNextFeature();
+      bool goesOn = feature.addr() != 0;
+      if (!goesOn)
         {
-        MeasurementType mv;
-        mv.SetSize(nbFeatures);
-        for(int idx=0; idx < nbFeatures; ++idx)
-          mv[idx] = feature.ogr().GetFieldAsDouble(featureFieldIndex[idx]);
+        otbAppLogWARNING("The layer "<<GetParameterInt("valid.layer")<<" of "
+          <<validFileList[k]<<" is empty, input is skipped.");
+        continue;
+        }
 
-        input->PushBack(mv);
-        target->PushBack(feature.ogr().GetFieldAsInteger(cFieldIndex));
+      // Check all needed fields are present :
+      //   - check class field
+      cFieldIndex = feature.ogr().GetFieldIndex(GetParameterString("cfield").c_str());
+      if (cFieldIndex < 0)
+        otbAppLogFATAL("The field name for class label ("<<GetParameterString("cfield")
+          <<") has not been found in the input vector file! Choices are "<< availableFields);
+      //   - check feature fields
+      for (unsigned int i=0 ; i<nbFeatures ; i++)
+        {
+        featureFieldIndex[i] = feature.ogr().GetFieldIndex(selectedNames[i].c_str());
+        if (featureFieldIndex[i] < 0)
+          otbAppLogFATAL("The field name for feature "<<selectedNames[i]
+          <<" has not been found in the input vector file! Choices are "<< availableFields);
+        }
+
+      while(goesOn)
+        {
+        if(feature.ogr().IsFieldSet(cFieldIndex))
+          {
+          MeasurementType mv;
+          mv.SetSize(nbFeatures);
+          for(unsigned int idx=0; idx < nbFeatures; ++idx)
+            mv[idx] = feature.ogr().GetFieldAsDouble(featureFieldIndex[idx]);
+
+          input->PushBack(mv);
+          target->PushBack(feature.ogr().GetFieldAsInteger(cFieldIndex));
+          }
+        feature = layer.ogr().GetNextFeature();
+        goesOn = feature.addr() != 0;
         }
-      feature = layer.ogr().GetNextFeature();
-      goesOn = feature.addr() != 0;
       }
 
     ShiftScaleFilterType::Pointer validShiftScaleFilter = ShiftScaleFilterType::New();
diff --git a/Modules/Applications/AppClassification/test/CMakeLists.txt b/Modules/Applications/AppClassification/test/CMakeLists.txt
index 2cd581340af32dc944aa1b9f8d665e35535fbfb0..5e9109e01b0a8aa3e65c06aefe3d978889a14f7b 100644
--- a/Modules/Applications/AppClassification/test/CMakeLists.txt
+++ b/Modules/Applications/AppClassification/test/CMakeLists.txt
@@ -897,4 +897,23 @@ if(OTB_USE_OPENCV)
     VALID   --compare-ascii ${NOTOL}
     ${OTBAPP_BASELINE_FILES}/apTvClTrainVectorClassifierModel.rf
     ${TEMP}/apTvClTrainVectorClassifierModel.rf)
-endif()
\ No newline at end of file
+endif()
+
+#------------ MultiImageSamplingRate TESTS ----------------
+otb_test_application(NAME apTvClMultiImageSamplingRate
+                     APP MultiImageSamplingRate
+                     OPTIONS -il ${INPUTDATA}/Classification/vector_stats_QB1.xml
+                                 ${INPUTDATA}/Classification/vector_stats_QB2.xml
+                                 ${INPUTDATA}/Classification/vector_stats_QB3.xml
+                             -out ${TEMP}/apTvClMultiImageSamplingRate_out.csv
+                             -strategy constant
+                             -strategy.constant.nb "300"
+                             -mim proportional
+                     VALID   --compare-n-ascii ${NOTOL} 3
+                                ${OTBAPP_BASELINE_FILES}/apTvClMultiImageSamplingRate_out_1.csv
+                                ${TEMP}/apTvClMultiImageSamplingRate_out_1.csv
+                                ${OTBAPP_BASELINE_FILES}/apTvClMultiImageSamplingRate_out_2.csv
+                                ${TEMP}/apTvClMultiImageSamplingRate_out_2.csv
+                                ${OTBAPP_BASELINE_FILES}/apTvClMultiImageSamplingRate_out_3.csv
+                                ${TEMP}/apTvClMultiImageSamplingRate_out_3.csv
+                     )
diff --git a/Modules/Applications/AppStereo/app/otbFineRegistration.cxx b/Modules/Applications/AppStereo/app/otbFineRegistration.cxx
index 33481d3185cb8c5d25ae58798e8315b8dac57d12..8808d6d1cba02fa416808f41559c54472a721146 100644
--- a/Modules/Applications/AppStereo/app/otbFineRegistration.cxx
+++ b/Modules/Applications/AppStereo/app/otbFineRegistration.cxx
@@ -205,6 +205,12 @@ private:
     SetMinimumParameterFloatValue("spa", 0.0);
     MandatoryOff("spa");
 
+    AddParameter(ParameterType_Float,  "cva",   "ConvergenceAccuracy");
+    SetParameterDescription( "cva", "Metric extrema will be refined up to the given accuracy. Default is 0.01" );
+    SetDefaultParameterFloat("cva", 0.01);
+    SetMinimumParameterFloatValue("cva", 0.0);
+    MandatoryOff("cva");
+
     AddParameter(ParameterType_Float,  "vmlt",   "Validity Mask Lower Threshold");
     SetParameterDescription( "vmlt", "Lower threshold to obtain a validity mask." );
     MandatoryOff("vmlt");
@@ -249,8 +255,6 @@ private:
     radius[0] = GetParameterInt("mrx");
     radius[1] = GetParameterInt("mry");
 
-    double accuracy = static_cast<double>(GetParameterFloat("spa"));
-
     ssrate[0] = GetParameterFloat("ssrx");
     ssrate[1] = GetParameterFloat("ssry");
 
@@ -265,12 +269,22 @@ private:
     otbAppLogINFO("Metric radius     : "<<radius<<" (pixels)");
     otbAppLogINFO("Sub-sampling rate : "<<ssrate<<" (pixels)");
     otbAppLogINFO("Coarse offset     : "<<initialOffset<<" (physical unit)");
-    otbAppLogINFO("Accuracy          : "<<accuracy<<" (physical unit)");
 
     m_Registration = RegistrationFilterType::New();
     m_Registration->SetRadius(radius);
     m_Registration->SetSearchRadius(sradius);
-    m_Registration->SetSubPixelAccuracy(accuracy);
+    if (IsParameterEnabled("cva") && HasValue("cva"))
+    {
+        double convAccuracy = static_cast<double>(GetParameterFloat("cva"));
+        m_Registration->SetConvergenceAccuracy(convAccuracy);
+        otbAppLogINFO("Convergence Accuracy          : "<<convAccuracy<<" (physical unit)");
+    }
+    if (IsParameterEnabled("spa") && HasValue("spa"))
+    {
+        double subPixAccuracy = static_cast<double>(GetParameterFloat("spa"));
+        m_Registration->SetSubPixelAccuracy(subPixAccuracy);
+        otbAppLogINFO("SubPixel Accuracy          : "<<subPixAccuracy<<" (physical unit)");
+    }
     m_Registration->SetGridStep(ssrate);
     m_Registration->SetInitialOffset(initialOffset);
 
diff --git a/Modules/Applications/AppStereo/test/CMakeLists.txt b/Modules/Applications/AppStereo/test/CMakeLists.txt
index fa2da88605e0afbba9394deaac40281ab7219cc2..36883cd248fda8d6269cc7a4eb2e3de7ae0007b5 100644
--- a/Modules/Applications/AppStereo/test/CMakeLists.txt
+++ b/Modules/Applications/AppStereo/test/CMakeLists.txt
@@ -85,6 +85,7 @@ otb_test_application(NAME apTvDmFineRegistrationTest
                              -ssrx 8
                              -ssry 8
                              -spa 0.1
+                             -cva 0.01
                              -cox -2
                              -vmlt 0.999
                      VALID   --compare-image ${EPSILON_10}
diff --git a/Modules/Filtering/Statistics/src/otbSamplerBase.cxx b/Modules/Filtering/Statistics/src/otbSamplerBase.cxx
index 45ed4efe3820b2ff9f1ff147bbe07812891bac9f..8d84acaa395ff202cfccd4924b2e05ccb55e6f1b 100644
--- a/Modules/Filtering/Statistics/src/otbSamplerBase.cxx
+++ b/Modules/Filtering/Statistics/src/otbSamplerBase.cxx
@@ -18,6 +18,8 @@
 
 #include "otbSamplerBase.h"
 #include "otbMath.h"
+#include "itkMath.h"
+#include <cmath>
 
 namespace otb
 {
@@ -33,14 +35,16 @@ void
 SamplerBase::SetNumberOfElements(unsigned long needed, unsigned long total)
 {
   bool modified = false;
+  unsigned long neededChecked = needed;
   if (needed > total)
     {
-    itkExceptionMacro(<< "Needed elements (" << needed << 
-      ") greater than total elements" << total << ")." << std::endl);
+    itkWarningMacro(<< "Needed elements (" << needed <<
+      ") will be clamped to total elements (" << total << ")" << std::endl);
+    neededChecked = total;
     }
-  if (m_NeededElements != needed)
+  if (m_NeededElements != neededChecked)
     {
-    m_NeededElements = needed;
+    m_NeededElements = neededChecked;
     modified = true;
     }
   if (m_TotalElements != total)
@@ -66,9 +70,22 @@ void
 SamplerBase::SetRate(double rate, unsigned long total)
 {
   bool modified = false;
-  if (m_Rate != rate)
+  double rateChecked = rate;
+  if (rate > 1.0)
     {
-    m_Rate = rate;
+    itkWarningMacro(<< "Rate (" << rate <<
+      ") will be clamped to 1.0" << std::endl);
+    rateChecked = 1.0;
+    }
+  if (rate < 0.0)
+    {
+    itkWarningMacro(<< "Rate (" << rate <<
+      ") will be clamped to 0.0" << std::endl);
+    rateChecked = 0.0;
+    }
+  if (std::fabs(m_Rate-rateChecked) > 1e-12)
+    {
+    m_Rate = rateChecked;
     modified = true;
     }
   if (m_TotalElements != total)
diff --git a/Modules/Learning/Sampling/include/otbSamplingRateCalculator.h b/Modules/Learning/Sampling/include/otbSamplingRateCalculator.h
index bb66f69478be08073eeca38b12294ba3745de5f6..8743a95553695f3f3e5bff34a1e5ab0378f30bbf 100644
--- a/Modules/Learning/Sampling/include/otbSamplingRateCalculator.h
+++ b/Modules/Learning/Sampling/include/otbSamplingRateCalculator.h
@@ -38,7 +38,7 @@ class ITK_EXPORT SamplingRateCalculator
 {
 public:
   /** Standard typedefs */
-  typedef SamplingRateCalculator                     Self;
+  typedef SamplingRateCalculator        Self;
   typedef itk::Object                   Superclass;
   typedef itk::SmartPointer<Self>       Pointer;
   typedef itk::SmartPointer<const Self> ConstPointer;
@@ -94,6 +94,8 @@ public:
   /** Clear internal data */
   void ClearRates(void);
 
+  static ClassCountMapType ReadRequiredSamples(const std::string& filename);
+
 protected:
   /** Constructor */
   SamplingRateCalculator();
diff --git a/Modules/Learning/Sampling/include/otbSamplingRateCalculatorList.h b/Modules/Learning/Sampling/include/otbSamplingRateCalculatorList.h
new file mode 100644
index 0000000000000000000000000000000000000000..2e1b622efa8e9c9db7f4fca98f58eff96c92ca0d
--- /dev/null
+++ b/Modules/Learning/Sampling/include/otbSamplingRateCalculatorList.h
@@ -0,0 +1,103 @@
+/*=========================================================================
+
+  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.
+
+=========================================================================*/
+#ifndef otbSamplingRateCalculatorList_h
+#define otbSamplingRateCalculatorList_h
+
+#include "otbSamplingRateCalculator.h"
+#include "otbObjectList.h"
+
+namespace otb
+{
+/** \class SamplingRateCalculatorList
+ *  \brief This class is a list of sampling rate calculators.
+ *
+ * It computes sampling rates for each image and each class, given input
+ * statistics on available samples, and a sampling strategy. The sampling
+ * strategies are made from the combination of :
+ *   - the sampling strategies of otb::SamplingRateCalculator  (mono-image)
+ *   - a multi-image behaviour : proportional / constant / custom
+ *
+ * \ingroup OTBSampling
+ */
+class ITK_EXPORT SamplingRateCalculatorList
+  : public ObjectList<SamplingRateCalculator>
+{
+public:
+  /** Standard typedefs */
+  typedef SamplingRateCalculatorList          Self;
+  typedef ObjectList<SamplingRateCalculator>  Superclass;
+  typedef itk::SmartPointer<Self>             Pointer;
+  typedef itk::SmartPointer<const Self>       ConstPointer;
+
+  typedef SamplingRateCalculator::ClassCountMapType   ClassCountMapType;
+  typedef SamplingRateCalculator::MapRateType         MapRateType;
+
+  enum PartitionType
+    {
+    PROPORTIONAL,
+    EQUAL,
+    CUSTOM
+    };
+
+  /** Type macro */
+  itkNewMacro(Self);
+
+  /** Creation through object factory macro */
+  itkTypeMacro(SamplingRateCalculatorList, ObjectList);
+
+  /** Set the class counts for input 'index' */
+  void SetNthClassCount(unsigned int index,const ClassCountMapType &map);
+
+  /** Get the sampling rates computed for input 'index' */
+  const MapRateType & GetRatesByClass(unsigned int index);
+
+  /** Clear internal data */
+  void ClearRates(void);
+
+  /** Method to select all available samples */
+  void SetAllSamples(PartitionType t);
+
+  /** Method to choose a sampling strategy based on the smallest class.
+   * The number of samples in each class is set to this minimum size*/
+  void SetMinimumNbOfSamplesByClass(PartitionType t);
+
+  /** Method to set the same number of required samples in each class */
+  void SetNbOfSamplesAllClasses(std::vector<unsigned long> &nb, PartitionType t);
+
+  /** Method to manually set the number of samples required in each class */
+  void SetNbOfSamplesByClass(const std::vector<ClassCountMapType> &required, PartitionType t);
+
+protected:
+  /** Constructor */
+  SamplingRateCalculatorList(){}
+
+  /** Destructor */
+  ~SamplingRateCalculatorList() ITK_OVERRIDE {}
+
+private:
+  SamplingRateCalculatorList(const Self &);    //purposely not implemented
+  void operator =(const Self&);    //purposely not implemented
+
+  void UpdateGlobalCounts();
+
+  ClassCountMapType m_GlobalCountMap;
+
+};
+} // end namespace otb
+
+#endif
diff --git a/Modules/Learning/Sampling/src/CMakeLists.txt b/Modules/Learning/Sampling/src/CMakeLists.txt
index 90087a2744a9e007261d971e807d54ca7cca3d23..2ffa8f935110bfe23da6f70abca35219fd31c2a2 100644
--- a/Modules/Learning/Sampling/src/CMakeLists.txt
+++ b/Modules/Learning/Sampling/src/CMakeLists.txt
@@ -1,5 +1,6 @@
 set(OTBSampling_SRC
   otbSamplingRateCalculator.cxx
+  otbSamplingRateCalculatorList.cxx
 )
 
 add_library(OTBSampling ${OTBSampling_SRC})
diff --git a/Modules/Learning/Sampling/src/otbSamplingRateCalculator.cxx b/Modules/Learning/Sampling/src/otbSamplingRateCalculator.cxx
index 2378ff1e42bc4e76dea516b9526050f7160b0bbf..65a85589b9450b7d33d3c801d5a03ae3816369c5 100644
--- a/Modules/Learning/Sampling/src/otbSamplingRateCalculator.cxx
+++ b/Modules/Learning/Sampling/src/otbSamplingRateCalculator.cxx
@@ -90,8 +90,8 @@ SamplingRateCalculator
     else
       {
       TripletType triplet;
-      triplet.Tot = it->second;
-      triplet.Required = 0UL;
+      triplet.Tot = 0UL;
+      triplet.Required = it->second;
       triplet.Rate = 0.0;
       m_RatesByClass[it->first] = triplet;
       }
@@ -134,56 +134,65 @@ SamplingRateCalculator
 {
   std::ifstream ifs(filename.c_str());
 
+  typedef std::vector<boost::iterator_range<std::string::const_iterator> > ListType;
+
   if (ifs)
     {
     this->ClearRates();
     std::string line;
     TripletType tpt;
     std::string sep("");
-    while(!ifs.eof())
+    ListType parts;
+    while(std::getline(ifs,line))
       {
-      std::getline(ifs,line);
       if (line.empty()) continue;
       std::string::size_type pos = line.find_first_not_of(" \t");
       if (pos != std::string::npos && line[pos] == '#') continue;
 
-      if (sep.size() == 0)
+      if (sep.empty())
         {
         // Try to detect the separator
-        std::string separators("\t;,");
+        std::vector<std::string> separators(4);
+        separators[0] = "\t";
+        separators[1] = ";";
+        separators[2] = ",";
+        separators[3] = " ";
+        ListType words;
         for (unsigned int k=0 ; k<separators.size() ; k++)
           {
-          std::vector<itksys::String> words = itksys::SystemTools::SplitString(line,separators[k]);
+          boost::split(words, line, boost::is_any_of(separators[k]));
           if (words.size() == 4)
             {
-            sep.push_back(separators[k]);
+            sep = separators[k];
             break;
             }
           }
-        if (sep.size() == 0) continue;
+        if (sep.empty()) continue;
         }
       // parse the line
-      std::vector<itksys::String> parts = itksys::SystemTools::SplitString(line,sep[0]);
+      boost::split(parts, line, boost::is_any_of(sep));
       if (parts.size() == 4)
         {
-        std::string::size_type pos1 = parts[0].find_first_not_of(" \t");
-        std::string::size_type pos2 = parts[0].find_last_not_of(" \t");
-        std::string::size_type pos3 = parts[1].find_first_not_of(" \t");
-        std::string::size_type pos4 = parts[1].find_last_not_of(" \t");
-        std::string::size_type pos5 = parts[2].find_first_not_of(" \t");
-        std::string::size_type pos6 = parts[2].find_last_not_of(" \t");
-        std::string::size_type pos7 = parts[3].find_first_not_of(" \t");
-        std::string::size_type pos8 = parts[3].find_last_not_of(" \t");
-        if (pos1 != std::string::npos && pos3 != std::string::npos &&
-            pos5 != std::string::npos && pos7 != std::string::npos)
+        std::string::size_type pos1 = line.find_first_not_of(" \t", parts[0].begin() - line.begin());
+        std::string::size_type pos2 = line.find_last_not_of(" \t", parts[0].end() - line.begin() -1);
+        std::string::size_type pos3 = line.find_first_not_of(" \t", parts[1].begin() - line.begin());
+        std::string::size_type pos4 = line.find_last_not_of(" \t", parts[1].end() - line.begin() -1);
+        std::string::size_type pos5 = line.find_first_not_of(" \t", parts[2].begin() - line.begin());
+        std::string::size_type pos6 = line.find_last_not_of(" \t", parts[2].end() - line.begin() -1);
+        std::string::size_type pos7 = line.find_first_not_of(" \t", parts[3].begin() - line.begin());
+        std::string::size_type pos8 = line.find_last_not_of(" \t", parts[3].end() - line.begin() -1);
+        if (pos2 != std::string::npos && pos1 <= pos2 &&
+            pos4 != std::string::npos && pos3 <= pos4 &&
+            pos6 != std::string::npos && pos5 <= pos6 &&
+            pos8 != std::string::npos && pos7 <= pos8)
           {
-          std::string name = parts[0].substr(pos1, pos2 - pos1 + 1);
-          std::string val1 = parts[1].substr(pos3, pos4 - pos3 + 1);
-          std::string val2 = parts[2].substr(pos5, pos6 - pos5 + 1);
-          std::string val3 = parts[3].substr(pos7, pos8 - pos7 + 1);
-          tpt.Required = boost::lexical_cast<unsigned long>(val1);
-          tpt.Tot = boost::lexical_cast<unsigned long>(val2);
-          tpt.Rate = boost::lexical_cast<double>(val3);
+          std::string name = line.substr(pos1, pos2 - pos1 + 1);
+          std::string val1 = line.substr(pos3, pos4 - pos3 + 1);
+          std::string val2 = line.substr(pos5, pos6 - pos5 + 1);
+          std::string val3 = line.substr(pos7, pos8 - pos7 + 1);
+          tpt.Required = Utils::LexicalCast<unsigned long>(val1, "number of samples");
+          tpt.Tot = Utils::LexicalCast<unsigned long>(val2, "number of samples");
+          tpt.Rate = Utils::LexicalCast<double>(val3, "rate");
           m_RatesByClass[name] = tpt;
           }
         }
@@ -226,6 +235,73 @@ SamplingRateCalculator
   m_RatesByClass.clear();
 }
 
+SamplingRateCalculator::ClassCountMapType
+SamplingRateCalculator
+::ReadRequiredSamples(const std::string& filename)
+{
+  ClassCountMapType output;
+  std::ifstream ifs(filename.c_str());
+
+  typedef std::vector<boost::iterator_range<std::string::const_iterator> > ListType;
+
+  if (ifs)
+    {
+    std::string line;
+    std::string sep("");
+    ListType parts;
+
+    while(std::getline(ifs,line))
+      {
+      if (line.empty()) continue;
+      std::string::size_type pos = line.find_first_not_of(" \t");
+      if (pos != std::string::npos && line[pos] == '#') continue;
+
+      if (sep.empty())
+        {
+        // Try to detect the separator
+        std::vector<std::string> separators(4);
+        separators[0] = "\t";
+        separators[1] = ";";
+        separators[2] = ",";
+        separators[3] = " ";
+        ListType words;
+        for (unsigned int k=0 ; k<separators.size() ; k++)
+          {
+          boost::split(words, line, boost::is_any_of(separators[k]));
+          if (words.size() >= 2)
+            {
+            sep = separators[k];
+            break;
+            }
+          }
+        if (sep.empty()) continue;
+        }
+      // parse the line
+      boost::split(parts, line, boost::is_any_of(sep));
+      if (parts.size() >= 2)
+        {
+        std::string::size_type pos1 = line.find_first_not_of(" \t", parts[0].begin() - line.begin());
+        std::string::size_type pos2 = line.find_last_not_of(" \t", parts[0].end() - line.begin() -1);
+        std::string::size_type pos3 = line.find_first_not_of(" \t", parts[1].begin() - line.begin());
+        std::string::size_type pos4 = line.find_last_not_of(" \t", parts[1].end() - line.begin() -1);
+        if (pos2 != std::string::npos && pos1 <= pos2 &&
+            pos4 != std::string::npos && pos3 <= pos4)
+          {
+          std::string name = line.substr(pos1, pos2 - pos1 + 1);
+          std::string value = line.substr(pos3, pos4 - pos3 + 1);
+          output[name] = Utils::LexicalCast<unsigned long>(value, "number of samples");
+          }
+        }
+      }
+    ifs.close();
+    }
+  else
+    {
+    itkGenericExceptionMacro(<< " Couldn't open " << filename);
+    }
+  return output;
+}
+
 void
 SamplingRateCalculator
 ::UpdateRate(const std::string &name)
diff --git a/Modules/Learning/Sampling/src/otbSamplingRateCalculatorList.cxx b/Modules/Learning/Sampling/src/otbSamplingRateCalculatorList.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..829e3aefd6b3a2468826d8772c24eb7bdd3aa81a
--- /dev/null
+++ b/Modules/Learning/Sampling/src/otbSamplingRateCalculatorList.cxx
@@ -0,0 +1,304 @@
+/*=========================================================================
+
+  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 "otbSamplingRateCalculatorList.h"
+#include "otbMacro.h"
+
+namespace otb
+{
+
+void
+SamplingRateCalculatorList
+::SetNthClassCount(unsigned int index,const ClassCountMapType &map)
+{
+  if (index >= this->Size())
+    {
+    unsigned int currentSize = this->Size();
+    for (unsigned int i = currentSize ; i < (index+1) ; i++ )
+      {
+      this->PushBack(SamplingRateCalculator::New());
+      }
+    }
+  this->GetNthElement(index)->SetClassCount(map);
+}
+
+const SamplingRateCalculatorList::MapRateType &
+SamplingRateCalculatorList
+::GetRatesByClass(unsigned int index)
+{
+  if (index >= this->Size())
+    {
+    itkGenericExceptionMacro("Requesting an index ("<<index<<") larger than list size ("<<this->Size()<<")");
+    }
+  return this->GetNthElement(index)->GetRatesByClass();
+}
+
+void
+SamplingRateCalculatorList
+::ClearRates(void)
+{
+  for (unsigned int i=0 ; i<this->Size() ; i++)
+    {
+    this->GetNthElement(i)->ClearRates();
+    }
+}
+
+void
+SamplingRateCalculatorList
+::SetAllSamples(PartitionType t)
+{
+  this->UpdateGlobalCounts();
+  switch (t)
+    {
+    case PROPORTIONAL:
+    case EQUAL:
+    case CUSTOM:
+      {
+      for (unsigned int i=0 ; i<this->Size() ; i++)
+        {
+        this->GetNthElement(i)->SetAllSamples();
+        }
+      break;
+      }
+    default:
+      itkGenericExceptionMacro("Unknown partition mode");
+      break;  
+    }
+}
+
+void
+SamplingRateCalculatorList
+::SetMinimumNbOfSamplesByClass(PartitionType t)
+{
+  this->UpdateGlobalCounts();
+  switch (t)
+    {
+    case PROPORTIONAL:
+    case EQUAL:
+      {
+      // Use the smallest class globally to derive the constant needed 
+      unsigned long smallest = itk::NumericTraits<unsigned long>::max();
+      ClassCountMapType::iterator it = m_GlobalCountMap.begin();
+      for (; it != m_GlobalCountMap.end() ; ++it)
+        {
+        if (smallest > it->second && it->second > 0UL)
+          {
+          smallest = it->second;
+          }
+        }
+      if (smallest == itk::NumericTraits<unsigned long>::max())
+        {
+        otbWarningMacro("All classes are empty !");
+        smallest = 0UL;
+        }
+      std::vector<unsigned long> needed;
+      needed.push_back(smallest);
+      this->SetNbOfSamplesAllClasses(needed,t);
+      break;
+      }
+    case CUSTOM:
+      {
+      // Use the smallest class in each input
+      for (unsigned int i=0 ; i<this->Size() ; i++)
+        {
+        this->GetNthElement(i)->SetMinimumNbOfSamplesByClass();
+        }
+      break;
+      }
+    default:
+      itkGenericExceptionMacro("Unknown partition mode");
+      break;  
+    }
+}
+
+void
+SamplingRateCalculatorList
+::SetNbOfSamplesAllClasses(std::vector<unsigned long> &nb, PartitionType t)
+{
+  if (nb.empty())
+    {
+    itkGenericExceptionMacro("No number of samples given");
+    }
+  this->UpdateGlobalCounts();
+  ClassCountMapType::const_iterator it;
+  ClassCountMapType needed;
+  switch (t)
+    {
+    case PROPORTIONAL:
+      {
+      for (unsigned int i=0 ; i<this->Size() ; i++)
+        {
+        needed.clear();
+        for (it = m_GlobalCountMap.begin(); it != m_GlobalCountMap.end() ; ++it)
+          {
+          const MapRateType& rates = this->GetNthElement(i)->GetRatesByClass();
+          MapRateType::const_iterator curIt = rates.find(it->first);
+          if (curIt != rates.end() &&
+              it->second > 0UL)
+            {
+            unsigned long curTotal = (curIt->second).Tot;
+            needed[it->first] = static_cast<unsigned long>(vcl_floor(
+              static_cast<double>(nb[0]) *
+              static_cast<double>(curTotal) /
+              static_cast<double>(it->second)));
+            }
+          else
+            {
+            needed[it->first] = 0UL;
+            }
+          }
+        this->GetNthElement(i)->SetNbOfSamplesByClass(needed);
+        }
+      break;
+      }
+    case EQUAL:
+      {
+      for (unsigned int i=0 ; i<this->Size() ; i++)
+        {
+        this->GetNthElement(i)->SetNbOfSamplesAllClasses(
+          static_cast<unsigned long>(vcl_floor(
+            (double)nb[0] / (double)this->Size())));
+        }
+      break;
+      }
+    case CUSTOM:
+      {
+      if (nb.size() < this->Size())
+        {
+        itkGenericExceptionMacro("Not enough values present to set custom requested numbers in all inputs");
+        }
+      for (unsigned int i=0 ; i<this->Size() ; i++)
+        {
+        this->GetNthElement(i)->SetNbOfSamplesAllClasses(nb[i]);
+        }
+      break;
+      }
+    default:
+      itkGenericExceptionMacro("Unknown partition mode");
+      break;  
+    }
+}
+
+void
+SamplingRateCalculatorList
+::SetNbOfSamplesByClass(const std::vector<ClassCountMapType> &required, PartitionType t)
+{
+  if (required.empty())
+    {
+    itkGenericExceptionMacro("No number of samples given");
+    }
+  this->UpdateGlobalCounts();
+  ClassCountMapType::const_iterator it;
+  ClassCountMapType::const_iterator inputIt;
+  ClassCountMapType needed;
+  switch (t)
+    {
+    case PROPORTIONAL:
+      {
+      for (unsigned int i=0 ; i<this->Size() ; i++)
+        {
+        needed.clear();
+        for (it = m_GlobalCountMap.begin(); it != m_GlobalCountMap.end() ; ++it)
+          {
+          const MapRateType &rates = this->GetNthElement(i)->GetRatesByClass();
+          MapRateType::const_iterator curIt = rates.find(it->first);
+          inputIt = required[0].find(it->first);
+          if (curIt != rates.end() &&
+              inputIt != required[0].end() &&
+              it->second > 0UL)
+            {
+            unsigned long curTotal = (curIt->second).Tot;
+            needed[it->first] = static_cast<unsigned long>(vcl_floor(
+              static_cast<double>(inputIt->second) *
+              static_cast<double>(curTotal) /
+              static_cast<double>(it->second)));
+            }
+          else
+            {
+            needed[it->first] = 0UL;
+            }
+          }
+        this->GetNthElement(i)->SetNbOfSamplesByClass(needed);
+        }
+      break;
+      }
+    case EQUAL:
+      {
+      for (unsigned int i=0 ; i<this->Size() ; i++)
+        {
+        needed.clear();
+        for (it = m_GlobalCountMap.begin(); it != m_GlobalCountMap.end() ; ++it)
+          {
+          const MapRateType &rates = this->GetNthElement(i)->GetRatesByClass();
+          MapRateType::const_iterator curIt = rates.find(it->first);
+          inputIt = required[0].find(it->first);
+          if (curIt != rates.end() &&
+              inputIt != required[0].end() &&
+              it->second > 0UL)
+            {
+            unsigned long curTotal = (curIt->second).Tot;
+            unsigned long curNeeded = static_cast<unsigned long>(vcl_floor(
+              static_cast<double>(inputIt->second) /
+              static_cast<double>(this->Size())));
+            needed[it->first] = std::min(curTotal,curNeeded);
+            }
+          else
+            {
+            needed[it->first] = 0UL;
+            }
+          }
+        this->GetNthElement(i)->SetNbOfSamplesByClass(needed);
+        }
+      break;
+      }
+    case CUSTOM:
+      {
+      if (required.size() < this->Size())
+        {
+        itkGenericExceptionMacro("Not enough values present to set custom requested numbers in all inputs");
+        }
+      for (unsigned int i=0 ; i<this->Size() ; i++)
+        {
+        this->GetNthElement(i)->SetNbOfSamplesByClass(required[i]);
+        }
+      break;
+      }
+    default:
+      itkGenericExceptionMacro("Unknown partition mode");
+      break;  
+    }
+}
+
+void
+SamplingRateCalculatorList
+::UpdateGlobalCounts()
+{
+  m_GlobalCountMap.clear();
+  for (unsigned int i=0 ; i<this->Size() ; i++)
+    {
+    const MapRateType &rates = this->GetNthElement(i)->GetRatesByClass();
+    MapRateType::const_iterator it = rates.begin();
+    for (; it != rates.end() ; ++it)
+      {
+      m_GlobalCountMap[it->first] += it->second.Tot;
+      }
+    }
+}
+
+} // end of namespace otb
+
diff --git a/Modules/Learning/Sampling/test/CMakeLists.txt b/Modules/Learning/Sampling/test/CMakeLists.txt
index 7c7fd77347377ad6c7265285b0004834b2455632..e3273eec8205c16aaaaf638941c919cc1d09b40d 100644
--- a/Modules/Learning/Sampling/test/CMakeLists.txt
+++ b/Modules/Learning/Sampling/test/CMakeLists.txt
@@ -6,6 +6,7 @@ otbOGRDataToSamplePositionFilterTest.cxx
 otbSamplingRateCalculatorTest.cxx
 otbOGRDataToClassStatisticsFilterTest.cxx
 otbImageSampleExtractorFilterTest.cxx
+otbSamplingRateCalculatorListTest.cxx
 )
 
 add_executable(otbSamplingTestDriver ${OTBSamplingTests})
@@ -92,3 +93,16 @@ otb_add_test(NAME leTvImageSampleExtractorFilterUpdate COMMAND otbSamplingTestDr
   otbImageSampleExtractorFilterUpdate
   ${INPUTDATA}/variousVectors.sqlite
   ${TEMP}/leTvImageSampleExtractorFilterUpdateTest.shp)
+
+# ---------------- SamplingRateCalculatorList ---------------------------------
+otb_add_test(NAME leTuSamplingRateCalculatorListNew COMMAND otbSamplingTestDriver
+            otbSamplingRateCalculatorListNew 
+  
+  )
+
+otb_add_test(NAME leTvSamplingRateCalculatorList COMMAND otbSamplingTestDriver
+  --compare-ascii ${NOTOL}
+  ${BASELINE_FILES}/leTvSamplingRateCalculatorList.txt
+  ${TEMP}/leTvSamplingRateCalculatorList.txt
+  otbSamplingRateCalculatorList
+  ${TEMP}/leTvSamplingRateCalculatorList.txt)
diff --git a/Modules/Learning/Sampling/test/otbSamplingRateCalculatorListTest.cxx b/Modules/Learning/Sampling/test/otbSamplingRateCalculatorListTest.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..6210ed101e99f7e87cbdc28f2aba332aada775d1
--- /dev/null
+++ b/Modules/Learning/Sampling/test/otbSamplingRateCalculatorListTest.cxx
@@ -0,0 +1,188 @@
+/*=========================================================================
+
+  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 "otbSamplingRateCalculatorList.h"
+
+#include "otbStatisticsXMLFileReader.h"
+#include "itkVariableLengthVector.h"
+#include <fstream>
+
+int otbSamplingRateCalculatorListNew(int itkNotUsed(argc), char* itkNotUsed(argv) [])
+{
+  typedef otb::SamplingRateCalculatorList RateCalculatorListType;
+  
+  RateCalculatorListType::Pointer rateCalculator = RateCalculatorListType::New();
+  std::cout << rateCalculator << std::endl;
+  return EXIT_SUCCESS;
+}
+
+int otbSamplingRateCalculatorList(int itkNotUsed(argc), char* argv[])
+{
+  std::ofstream file(argv[1], std::ios::out | std::ios::trunc);
+
+  if (!file)
+    {
+    std::cout << " Couldn't open " << argv[1];
+    return EXIT_FAILURE;
+    }
+
+  itk::Indent indent_1(1);
+
+  typedef otb::SamplingRateCalculatorList::ClassCountMapType  ClassCountMapType;
+  typedef otb::SamplingRateCalculatorList::PartitionType      PartitionType;
+
+  PartitionType typeProportional = otb::SamplingRateCalculatorList::PROPORTIONAL;
+  PartitionType typeEqual = otb::SamplingRateCalculatorList::EQUAL;
+  PartitionType typeCustom = otb::SamplingRateCalculatorList::CUSTOM;
+
+  std::string c1("1");
+  std::string c2("2");
+  std::string c3("3");
+  std::string c4("4");
+
+  ClassCountMapType classCount1, classCount2, classCount3;
+  // input 1
+  classCount1[c1] = 104;
+  classCount1[c2] = 160;
+  classCount1[c3] = 211;
+  // input 2
+  classCount2[c1] = 98;
+  classCount2[c2] = 190;
+  classCount2[c3] = 178;
+  // input 3
+  classCount3[c1] = 130;
+  classCount3[c2] = 144;
+  classCount3[c4] = 250;
+
+  std::vector<unsigned long> nbSamplesCst;
+  nbSamplesCst.push_back(151);
+
+  std::vector<unsigned long> nbSamplesCstCustom;
+  nbSamplesCstCustom.push_back(70);
+  nbSamplesCstCustom.push_back(80);
+  nbSamplesCstCustom.push_back(90);
+
+  ClassCountMapType needed1;
+  needed1[c1] = 140;
+  needed1[c2] = 130;
+  needed1[c3] = 124;
+
+  std::vector<ClassCountMapType> nbByClass;
+  nbByClass.push_back(needed1);
+
+  ClassCountMapType needed2;
+  needed2[c1] = 67;
+  needed2[c2] = 55;
+  needed2[c3] = 72;
+
+  ClassCountMapType needed3;
+  needed3[c1] = 77;
+  needed3[c2] = 69;
+  needed3[c3] = 34;
+
+  ClassCountMapType needed4;
+  needed4[c1] = 86;
+  needed4[c2] = 43;
+  needed4[c4] = 98;
+
+  std::vector<ClassCountMapType> nbByClassCustom;
+  nbByClassCustom.push_back(needed2);
+  nbByClassCustom.push_back(needed3);
+  nbByClassCustom.push_back(needed4);
+
+  typedef otb::SamplingRateCalculatorList RateCalculatorListType;
+  RateCalculatorListType::Pointer rateCalcList = RateCalculatorListType::New();
+  rateCalcList->SetNthClassCount(0,classCount1);
+  rateCalcList->SetNthClassCount(2,classCount3);
+  rateCalcList->SetNthClassCount(1,classCount2);
+
+  file << "# Test the strategy : smallest - equal" << std::endl;
+  rateCalcList->SetMinimumNbOfSamplesByClass(typeEqual);
+  for (unsigned int i=0 ; i<rateCalcList->Size() ; i++)
+    {
+    file << "# Input "<< i << std::endl;
+    rateCalcList->GetNthElement(i)->Print(file, indent_1);
+    }
+
+  file << "# Test the strategy : smallest - custom" << std::endl;
+  rateCalcList->SetMinimumNbOfSamplesByClass(typeCustom);
+  for (unsigned int i=0 ; i<rateCalcList->Size() ; i++)
+    {
+    file << "# Input "<< i << std::endl;
+    rateCalcList->GetNthElement(i)->Print(file, indent_1);
+    }
+
+  file << "# Test the strategy : constant - proportional" << std::endl;
+  rateCalcList->SetNbOfSamplesAllClasses(nbSamplesCst,typeProportional);
+  for (unsigned int i=0 ; i<rateCalcList->Size() ; i++)
+    {
+    file << "# Input "<< i << std::endl;
+    rateCalcList->GetNthElement(i)->Print(file, indent_1);
+    }
+
+  file << "# Test the strategy : constant - equal" << std::endl;
+  rateCalcList->SetNbOfSamplesAllClasses(nbSamplesCst,typeEqual);
+  for (unsigned int i=0 ; i<rateCalcList->Size() ; i++)
+    {
+    file << "# Input "<< i << std::endl;
+    rateCalcList->GetNthElement(i)->Print(file, indent_1);
+    }
+
+  file << "# Test the strategy : constant - custom" << std::endl;
+  rateCalcList->SetNbOfSamplesAllClasses(nbSamplesCstCustom,typeCustom);
+  for (unsigned int i=0 ; i<rateCalcList->Size() ; i++)
+    {
+    file << "# Input "<< i << std::endl;
+    rateCalcList->GetNthElement(i)->Print(file, indent_1);
+    }
+
+  file << "# Test the strategy : byClass - proportional" << std::endl;
+  rateCalcList->SetNbOfSamplesByClass(nbByClass,typeProportional);
+  for (unsigned int i=0 ; i<rateCalcList->Size() ; i++)
+    {
+    file << "# Input "<< i << std::endl;
+    rateCalcList->GetNthElement(i)->Print(file, indent_1);
+    }
+
+  file << "# Test the strategy : byClass - equal" << std::endl;
+  rateCalcList->SetNbOfSamplesByClass(nbByClass,typeEqual);
+  for (unsigned int i=0 ; i<rateCalcList->Size() ; i++)
+    {
+    file << "# Input "<< i << std::endl;
+    rateCalcList->GetNthElement(i)->Print(file, indent_1);
+    }
+
+  file << "# Test the strategy : byClass - custom" << std::endl;
+  rateCalcList->SetNbOfSamplesByClass(nbByClassCustom,typeCustom);
+  for (unsigned int i=0 ; i<rateCalcList->Size() ; i++)
+    {
+    file << "# Input "<< i << std::endl;
+    rateCalcList->GetNthElement(i)->Print(file, indent_1);
+    }
+
+  file << "# Test the strategy : all - equal" << std::endl;
+  rateCalcList->SetAllSamples(typeEqual);
+  for (unsigned int i=0 ; i<rateCalcList->Size() ; i++)
+    {
+    file << "# Input "<< i << std::endl;
+    rateCalcList->GetNthElement(i)->Print(file, indent_1);
+    }
+
+  file.close();
+  return EXIT_SUCCESS;
+}
diff --git a/Modules/Learning/Sampling/test/otbSamplingTestDriver.cxx b/Modules/Learning/Sampling/test/otbSamplingTestDriver.cxx
index 20a48dc1de860e25d0a0eb78326ad4a9b277d77b..c051e9a7dad8e71ab75bf69db4d370ab2142df37 100644
--- a/Modules/Learning/Sampling/test/otbSamplingTestDriver.cxx
+++ b/Modules/Learning/Sampling/test/otbSamplingTestDriver.cxx
@@ -11,4 +11,6 @@ void RegisterTests()
   REGISTER_TEST(otbImageSampleExtractorFilterNew);
   REGISTER_TEST(otbImageSampleExtractorFilter);
   REGISTER_TEST(otbImageSampleExtractorFilterUpdate);
+  REGISTER_TEST(otbSamplingRateCalculatorListNew);
+  REGISTER_TEST(otbSamplingRateCalculatorList);
 }
diff --git a/Modules/Registration/DisparityMap/include/otbFineRegistrationImageFilter.h b/Modules/Registration/DisparityMap/include/otbFineRegistrationImageFilter.h
index e964838baeebaa7c92c7f4aecc8c50701b837969..8aa20aab3dab7935a498087b3cfe072dd0b4f8d5 100644
--- a/Modules/Registration/DisparityMap/include/otbFineRegistrationImageFilter.h
+++ b/Modules/Registration/DisparityMap/include/otbFineRegistrationImageFilter.h
@@ -39,8 +39,8 @@ namespace otb
  * deriving from the itk::ImageToImageMetric. The MinimizeOn()/MinimizeOff() flag allows searching for
  * minimum or maximum depending on the metric (default is On).
  *
- * Once a coarse (pixel wise) offset has been found, this match is further refined using dichotomic search
- * until sub-pixel accuracy given by the SetSubPixelAccuracy() is reached.
+ * Once a coarse (pixel wise) offset has been found, this match is further refined using golden section search search
+ * until convergence accuracy (given by the SetConvergenceAccuracy()) is reached, or when the max number of iteration () is reached.
  *
  * The filter proposes two outputs: GetOutput() return the image of the metric optimum at each location, and
  * the GetOutputDisplacementField() method returns the corresponding offset.
@@ -132,9 +132,17 @@ public:
   itkSetMacro(SearchRadius, SizeType);
   itkGetMacro(SearchRadius, SizeType);
 
+  /** Set/Get convergence accuracy */
+  itkSetMacro(ConvergenceAccuracy, double);
+  itkGetMacro(ConvergenceAccuracy, double);
+  
   /** Set/Get subpixel accuracy */
   itkSetMacro(SubPixelAccuracy, double);
   itkGetMacro(SubPixelAccuracy, double);
+  
+  /** Set/Get max number of iterations */
+  itkSetMacro(MaxIter, int);
+  itkGetMacro(MaxIter, int);
 
   /** True if metric should be minimized. False otherwise */
   itkSetMacro(Minimize, bool);
@@ -192,6 +200,13 @@ protected:
 private:
   FineRegistrationImageFilter(const Self&); //purposely not implemented
   void operator=(const Self&); //purposely not implemented
+  
+  inline double callMetric(double val1,double val2,double &oldRes,bool &flag);
+  inline void updateOptParams(double potBestVal,double parx,double pary,                             //inputs
+                              double &bestVal, typename TranslationType::ParametersType& optParams); //outputs
+  inline void updatePoints(double& gn, double& in1, double& in2, double &in3,      //inputs
+                           double& out1, double& out2, double& out3, double& out4); //outputs
+  inline void updateMinimize(double& a, double& b);
 
   /** The radius for correlation */
   SizeType                      m_Radius;
@@ -206,7 +221,11 @@ private:
   bool                          m_UseSpacing;
 
   /** Search step */
+  double                        m_ConvergenceAccuracy;
   double                        m_SubPixelAccuracy;
+  
+  /** Max number of iterations */
+  int                           m_MaxIter;
 
   /** The interpolator */
   InterpolatorPointerType       m_Interpolator;
diff --git a/Modules/Registration/DisparityMap/include/otbFineRegistrationImageFilter.txx b/Modules/Registration/DisparityMap/include/otbFineRegistrationImageFilter.txx
index 1eb1d442f6a49debc4d3a631e8ec9e3cb138945e..41c1719a80623ae2345a4379657f64a2b4fefe0f 100644
--- a/Modules/Registration/DisparityMap/include/otbFineRegistrationImageFilter.txx
+++ b/Modules/Registration/DisparityMap/include/otbFineRegistrationImageFilter.txx
@@ -45,6 +45,10 @@ FineRegistrationImageFilter<TInputImage, T0utputCorrelation, TOutputDisplacement
 
   // Default sub-pixel precision
   m_SubPixelAccuracy = 0.1;
+  m_ConvergenceAccuracy = 0.01;
+  
+  // Max number of iterations
+  m_MaxIter = 100;
 
   // Flags
   m_UseSpacing = true;
@@ -282,6 +286,72 @@ FineRegistrationImageFilter<TInputImage, TOutputCorrelation, TOutputDisplacement
     }
   return;
  }
+ 
+template <class TInputImage, class TOutputCorrelation, class TOutputDisplacementField>
+double
+FineRegistrationImageFilter<TInputImage, TOutputCorrelation, TOutputDisplacementField>
+::callMetric(double val1,double val2,double &oldRes,bool &flag)
+{
+   typename TranslationType::ParametersType paramsgn(2);
+   paramsgn[0]=val1;
+   paramsgn[1]=val2;
+   
+   double res=oldRes;
+   flag=false;
+   
+   try
+   {
+      res=m_Metric->GetValue(paramsgn);
+   }
+   catch(itk::ExceptionObject& err)
+   {
+      flag=true;
+      itkWarningMacro(<< err.GetDescription());
+   }
+        
+   return res;
+} 
+
+template <class TInputImage, class TOutputCorrelation, class TOutputDisplacementField>
+void
+FineRegistrationImageFilter<TInputImage, TOutputCorrelation, TOutputDisplacementField>
+::updateOptParams(double potBestVal,double parx,double pary,double &bestVal, typename TranslationType::ParametersType& optParams)
+{
+    if (bestVal>potBestVal)
+    {
+        bestVal=potBestVal;
+        optParams[0]=parx;
+        optParams[1]=pary;
+    }
+}
+
+
+template <class TInputImage, class TOutputCorrelation, class TOutputDisplacementField>
+void
+FineRegistrationImageFilter<TInputImage, TOutputCorrelation, TOutputDisplacementField>
+::updatePoints(double& gn, double& in1, double& in2, double &in3,  
+               double& out1, double& out2, double& out3, double& out4)
+{
+    out1=out2;
+    out2=in3;
+    out3=in1+gn*(in2-in1);
+    out4=in2-gn*(in2-in1);
+    
+} 
+
+
+template <class TInputImage, class TOutputCorrelation, class TOutputDisplacementField>
+void
+FineRegistrationImageFilter<TInputImage, TOutputCorrelation, TOutputDisplacementField>
+::updateMinimize(double& a, double& b)
+{
+    if(!m_Minimize)
+    {
+        a = -a;
+        b = -b;
+    }
+}
+
 
 template <class TInputImage, class TOutputCorrelation, class TOutputDisplacementField>
 void
@@ -322,7 +392,7 @@ FineRegistrationImageFilter<TInputImage, TOutputCorrelation, TOutputDisplacement
   double currentMetric, optMetric;
 
   // Optimal translation parameters
-  typename TranslationType::ParametersType params(2), optParams(2), tmpOptParams(2);
+  typename TranslationType::ParametersType params(2), optParams(2);
 
   // Final displacement value
   DisplacementValueType displacementValue;
@@ -335,6 +405,7 @@ FineRegistrationImageFilter<TInputImage, TOutputCorrelation, TOutputDisplacement
   // Get fixed image spacing
   SpacingType fixedSpacing = fixedPtr->GetSpacing();
 
+
   // Walk the images
   while (!outputIt.IsAtEnd() && !outputDfIt.IsAtEnd() )
     {
@@ -367,6 +438,7 @@ FineRegistrationImageFilter<TInputImage, TOutputCorrelation, TOutputDisplacement
     m_Metric->SetFixedImageRegion(currentMetricRegion);
     m_Metric->Initialize();
 
+
     // Compute the local offset if required (and the transform was specified)
     if (m_Transform.IsNotNull())
       {
@@ -408,45 +480,90 @@ FineRegistrationImageFilter<TInputImage, TOutputCorrelation, TOutputDisplacement
         }
         }
       }
+  
+    
 
-    // Dichotomic sub-pixel
+    //golden section search
+    typename TranslationType::ParametersType paramsgn(2);
+    double gn=(sqrt(5.0)-1.0)/2.0;
     SpacingType subPixelSpacing = fixedSpacing;
-    while(subPixelSpacing[0] > m_SubPixelAccuracy || subPixelSpacing[1] > m_SubPixelAccuracy)
-      {
-      // Perform 1 step of dichotomic search
-      subPixelSpacing /= 2.;
-
-      // Store last opt params
-      tmpOptParams = optParams;
-
-      for(int i = -1; i <= 1; i+=2)
+    double ax=optParams[0]-static_cast<double>(subPixelSpacing[0]);
+    double ay=optParams[1]-static_cast<double>(subPixelSpacing[1]);
+    double bx=optParams[0]+static_cast<double>(subPixelSpacing[0]);
+    double by=optParams[1]+static_cast<double>(subPixelSpacing[1]);
+
+    
+    double cx=bx-gn*(bx-ax);
+    double cy=optParams[1];//by-gn*(by-ay);
+    double dx=ax+gn*(bx-ax);
+    double dy=optParams[1];//ay+gn*(by-ay);
+    double fc=0,fd=0;
+    bool exitWhile=false;
+    int nbIter=0;
+    double bestvalold=itk::NumericTraits<double>::max(),bestval=optMetric;
+    double diff=itk::NumericTraits<double>::max();
+    double diffx=itk::NumericTraits<double>::max();
+    double diffy=itk::NumericTraits<double>::max();
+    
+    //init
+    fc=callMetric(cx,cy,fc,exitWhile);
+    fd=callMetric(dx,dy,fd,exitWhile);
+    updateMinimize(fc,fd);
+
+    //loop
+    while (  (diffx > m_SubPixelAccuracy || diffy > m_SubPixelAccuracy) 
+             && (diff>m_ConvergenceAccuracy) 
+             && (!exitWhile) 
+             && (nbIter<=m_MaxIter)) 
+    {
+        nbIter++;
+    
+        // x direction
+        if (fc<fd)
         {
-        for(int j = -1; j <= 1; j+=2)
-          {
-          params = tmpOptParams;
-          params[0] += static_cast<double>(i*subPixelSpacing[0]);
-          params[1] += static_cast<double>(j*subPixelSpacing[1]);
-
-          try
-          {
-            // compute currentMetric
-            currentMetric = m_Metric->GetValue(params);
-
-            // Check for maximum
-            if((m_Minimize && (currentMetric < optMetric)) || (!m_Minimize && (currentMetric > optMetric)))
-              {
-              optMetric = currentMetric;
-              optParams = params;
-              }
-          }
-          catch(itk::ExceptionObject& err)
-          {
-            itkWarningMacro(<<err.GetDescription());
-
-          }
-          }
+            updateOptParams(fc,cx,cy,bestval,optParams);   
+            updatePoints(gn,ay,by,cx,bx,dx,dy,cy);
+            fc=callMetric(cx,cy,fc,exitWhile);
+            fd=callMetric(dx,dy,fd,exitWhile);
         }
-      }
+        else
+        {
+            updateOptParams(fd,dx,dy,bestval,optParams);
+            updatePoints(gn,by,ay,dx,ax,cx,cy,dy);
+            fc=callMetric(cx,cy,fc,exitWhile);
+            fd=callMetric(dx,dy,fd,exitWhile);
+        }
+        updateMinimize(fc,fd);
+        
+        // y direction
+        if (fc<fd)
+        {
+            updateOptParams(fc,cx,cy,bestval,optParams);
+            updatePoints(gn,ax,bx,cy,by,dy,dx,cx);
+            fc=callMetric(cx,cy,fc,exitWhile);
+            fd=callMetric(dx,dy,fd,exitWhile);
+        }
+        else
+        {
+            updateOptParams(fd,dx,dy,bestval,optParams);
+            updatePoints(gn,bx,ax,dy,ay,cy,cx,dx);
+            fc=callMetric(cx,cy,fc,exitWhile);
+            fd=callMetric(dx,dy,fd,exitWhile);
+        }
+        updateMinimize(fc,fd);
+        
+        // Before eventual exit, take benefit from the last evaluations of fd and fc
+        updateOptParams(fd,dx,dy,bestval,optParams);
+        updateOptParams(fc,cx,cy,bestval,optParams);
+        
+        if(!m_Minimize)
+            bestval=-bestval;
+            
+        diff= fabs(bestval-bestvalold);
+        bestvalold=bestval;
+        diffx=fabs(bx-ax);
+        diffy=fabs(by-ay);
+	}
 
     // Store the offset and the correlation value
     outputIt.Set(optMetric);
@@ -461,6 +578,8 @@ FineRegistrationImageFilter<TInputImage, TOutputCorrelation, TOutputDisplacement
       displacementValue[1] = optParams[1]/fixedSpacing[1];
       }
     outputDfIt.Set(displacementValue);
+    
+    
     // Update iterators
     ++outputIt;
     ++outputDfIt;
diff --git a/Modules/Registration/DisparityMap/test/CMakeLists.txt b/Modules/Registration/DisparityMap/test/CMakeLists.txt
index eea166fe1b2ede6202d219c3eb9da4241864acce..26d170da988976fcbf729ee2c241e4b9fb4222f7 100644
--- a/Modules/Registration/DisparityMap/test/CMakeLists.txt
+++ b/Modules/Registration/DisparityMap/test/CMakeLists.txt
@@ -168,7 +168,7 @@ otb_add_test(NAME dmTvFineRegistrationImageFilterTestWithMeanSquare COMMAND otbD
   ${TEMP}/feTvFineRegistrationImageFilterTestWithMeanSquareField.tif  # output fieldFileName
   3 # radius
   2 # sradius
-  0.1 # precision
+  0.01 # precision
   2 # Mean square
   1 # Grid step
   0 # Initial offset x
@@ -188,7 +188,7 @@ otb_add_test(NAME dmTvFineRegistrationImageFilterTestWithMeanReciprocalDifferenc
   ${TEMP}/feTvFineRegistrationImageFilterTestWithMeanReciprocalDifferenceField.tif  # output fieldFileName
   3 # radius
   2 # sradius
-  0.1 # precision
+  0.01 # precision
   3 # Mean reciprocal difference
   1 # Grid step
   0 # Initial offset x
@@ -208,7 +208,7 @@ otb_add_test(NAME dmTvFineRegistrationImageFilterTestWithNormalizedCorrelation C
   ${TEMP}/feTvFineRegistrationImageFilterTestWithNormalizedCorrelationField.tif  # output fieldFileName
   3 # radius
   2 # sradius
-  0.1 # precision
+  0.01 # precision
   1 # Normalized Correlation
   1 # Grid step
   0 # Initial offset x
@@ -228,7 +228,7 @@ otb_add_test(NAME dmTvFineRegistrationImageFilterTestWithCorrelation COMMAND otb
   ${TEMP}/feTvFineRegistrationImageFilterTestWithCorrelationField.tif  # output fieldFileName
   3 # radius
   2 # sradius
-  0.1 # precision
+  0.01 # precision
   0 # Correlation
   1 # Grid step
   0 # Initial offset x
diff --git a/Modules/Registration/DisparityMap/test/otbFineRegistrationImageFilterTest.cxx b/Modules/Registration/DisparityMap/test/otbFineRegistrationImageFilterTest.cxx
index 9f0fb19aad883b3580baaa9ef663cad3c4f6c59a..bf849a5209d3451e0d88b0011eda17e8340e88ba 100644
--- a/Modules/Registration/DisparityMap/test/otbFineRegistrationImageFilterTest.cxx
+++ b/Modules/Registration/DisparityMap/test/otbFineRegistrationImageFilterTest.cxx
@@ -94,7 +94,7 @@ int otbFineRegistrationImageFilterTest( int argc, char * argv[] )
   registration->SetMovingInput(/*mreader*/mextract->GetOutput());
   registration->SetRadius(radius);
   registration->SetSearchRadius(sradius);
-  registration->SetSubPixelAccuracy(precision);
+  registration->SetConvergenceAccuracy(precision);
   registration->SetGridStep(gridStep);
 
   RegistrationFilterType::SpacingType offset;
diff --git a/Modules/ThirdParty/6S/src/CMakeLists.txt b/Modules/ThirdParty/6S/src/CMakeLists.txt
index 7c2b3f496722924079ca714b3a31c527f726f74c..bcf7063d09a15b51a474dc48b332a6a3aaf16453 100644
--- a/Modules/ThirdParty/6S/src/CMakeLists.txt
+++ b/Modules/ThirdParty/6S/src/CMakeLists.txt
@@ -73,6 +73,15 @@ if(OTB_LIBRARY_PROPERTIES)
   set_target_properties(otb6S PROPERTIES ${OTB_LIBRARY_PROPERTIES})
 endif()
 
+# Below "extra" compile flags are needed for proper functioning of 6S
+# library. Without these flags especially /Oy- OpticalCalibration tests
+# are failing. the flags are automatially added by VS generator.
+# But due to time constraints and processing power available on testing VMs,
+# using Visual Studio generator is not possible.
+if(MSVC_VERSION GREATER 1800)
+  set_target_properties(otb6S PROPERTIES COMPILE_FLAGS "/Ob1 /Oy- /GS")
+endif()
+
 install(TARGETS otb6S
   EXPORT ${OTB3P_INSTALL_EXPORT_NAME}
   RUNTIME DESTINATION ${OTB3P_INSTALL_RUNTIME_DIR} COMPONENT RuntimeLibraries
diff --git a/Modules/ThirdParty/OssimPlugins/src/ossim/ossimWin32FindFileHandle.cpp b/Modules/ThirdParty/OssimPlugins/src/ossim/ossimWin32FindFileHandle.cpp
index 9c76477470466ac48a8d4059f6843f2508561dc1..cc1209ab9bc058b63cf1b863e52f798f605db674 100644
--- a/Modules/ThirdParty/OssimPlugins/src/ossim/ossimWin32FindFileHandle.cpp
+++ b/Modules/ThirdParty/OssimPlugins/src/ossim/ossimWin32FindFileHandle.cpp
@@ -16,7 +16,7 @@ ossimWin32FindFileHandle::ossimWin32FindFileHandle(std::string const& path)
     s_printf(
        err_msg,
        "ossimSentinel1Model: cannot list files in directory '%s' : '%d'",
-       path,
+       path.c_str(),
        GetLastError()
       );
 		throw std::runtime_error( err_msg );
diff --git a/Modules/Visualization/Mapla/src/mvdMaplaApplication.cxx b/Modules/Visualization/Mapla/src/mvdMaplaApplication.cxx
index b3c587aa64761afee21628e45ba67969b7c022e5..4a1a871a2765d59d932c377223b97e22f0433a24 100644
--- a/Modules/Visualization/Mapla/src/mvdMaplaApplication.cxx
+++ b/Modules/Visualization/Mapla/src/mvdMaplaApplication.cxx
@@ -86,8 +86,10 @@ MaplaApplication
   setObjectName( "MaplaApplication" );
 
   InitializeCore(
-    "Monteverdi Application Launcher", Monteverdi_VERSION_STRING,
-    "OrfeoToolBox", "orfeo-toolbox.org"
+    "Monteverdi Application Launcher",
+    QString( "OTB %1" ).arg( OTB_VERSION_STRING ),
+    "OrfeoToolBox",
+    "orfeo-toolbox.org"
   );
 }
 
diff --git a/Modules/Visualization/Monteverdi/src/mvdApplication.cxx b/Modules/Visualization/Monteverdi/src/mvdApplication.cxx
index 5768bf4b3bb7095e841246c3f53ff6b60892e428..e42c38f39ab21199b0e4e0d3346581fc1b9ea0b8 100644
--- a/Modules/Visualization/Monteverdi/src/mvdApplication.cxx
+++ b/Modules/Visualization/Monteverdi/src/mvdApplication.cxx
@@ -128,7 +128,7 @@ Application
   setObjectName( "Application" );
 
   InitializeCore(
-    PROJECT_NAME, Monteverdi_VERSION_STRING,
+    PROJECT_NAME, QString( "OTB %1" ).arg(  OTB_VERSION_STRING ),
     "OrfeoToolBox", "orfeo-toolbox.org"
   );
 
diff --git a/Modules/Visualization/MonteverdiCore/include/mvdHistogramModel.h b/Modules/Visualization/MonteverdiCore/include/mvdHistogramModel.h
index d8db32ffece7847f0418843b9c274606377ac32a..adc0e3f1aee0bccbdeeef81870ebe42cb39cdd1d 100644
--- a/Modules/Visualization/MonteverdiCore/include/mvdHistogramModel.h
+++ b/Modules/Visualization/MonteverdiCore/include/mvdHistogramModel.h
@@ -37,6 +37,7 @@
 
 //
 // System includes (sorted by alphabetic order)
+#include <boost/type_traits/is_floating_point.hpp>
 
 //
 // ITK includes (sorted by alphabetic order)
@@ -102,8 +103,13 @@ class OTBMonteverdiCore_EXPORT HistogramModel :
   /*-[ PUBLIC SECTION ]------------------------------------------------------*/
 
 //
-// Public types.
+// Public types & constants.
 public:
+
+  /**
+   */
+  static const int PRECISION = 4;
+
   /** */
   typedef
     // itk::NumericTraits< T >::FloatType and
@@ -160,6 +166,9 @@ public:
 //
 // Public methods.
 public:
+  /**
+   */
+  static RealType GetEpsilon();
 
   /** \brief Constructor. */
   HistogramModel( QObject* p =NULL );
@@ -171,11 +180,15 @@ public:
    */
   bool IsValid() const;
 
+  /**
+   */
+  bool IsMonoValue() const;
+
   /** */
-  inline MeasurementType Quantile( CountType band, double p ) const;
+  MeasurementType Quantile( CountType band, double p ) const;
 
   /** */
-  inline MeasurementType Quantile( CountType band, double p, Bound bound ) const;
+  MeasurementType Quantile( CountType band, double p, Bound bound ) const;
 
   /** */
   double
@@ -326,34 +339,6 @@ HistogramModel
   return m_MaxPixel;
 }
 
-/*******************************************************************************/
-inline
-HistogramModel::MeasurementType
-HistogramModel
-::Quantile( unsigned int band,
-	    double p ) const
-{
-  assert( band<m_Histograms->Size() );
-
-  return m_Histograms->GetNthElement( band )->Quantile( 0, p );
-}
-
-/*******************************************************************************/
-inline
-HistogramModel::MeasurementType
-HistogramModel
-::Quantile( unsigned int band,
-	    double p,
-	    Bound bound ) const
-{
-  assert( band<m_Histograms->Size() );
-
-  return m_Histograms->GetNthElement( band )->Quantile(
-    0,
-    bound==BOUND_UPPER ? 1.0 - p : p
-  );
-}
-
 /*******************************************************************************/
 inline
 size_t
@@ -580,6 +565,10 @@ HistogramModel
     m_MinPixel = filterStats->GetMinimum();
     m_MaxPixel = filterStats->GetMaximum();
 
+    // Define corrected min/MAX pixels.
+    DefaultImageType::PixelType minPixel( m_MinPixel );
+    DefaultImageType::PixelType maxPixel( m_MaxPixel );
+
     // Extract sigmas for each band from covariance matrix.
     typename StatisticsFilter::MatrixType covariance(
       filterStats->GetFilter()->GetCovariance()
@@ -630,9 +619,26 @@ HistogramModel
 	    << ceil( ( m_MaxPixel[ i ] - m_MinPixel[ i ] ) / h );
 	  */
 
-	  bins[ i ] = ceil( ( m_MaxPixel[ i ] - m_MinPixel[ i ] ) / h );
+	  bins[ i ] = ceil( ( maxPixel[ i ] - minPixel[ i ] ) / h );
 	  }
 	}
+
+      // MANTIS-1275
+      // {
+      if( minPixel[ i ]==maxPixel[ i ] )	
+	{
+	double epsilon = HistogramModel::GetEpsilon();
+
+	if( minPixel[ i ] >=
+	    std::numeric_limits< DefaultImageType::PixelType::ValueType >::min() + epsilon )
+	  minPixel[ i ] -= epsilon;
+
+	if( maxPixel[ i ] <=
+	      std::numeric_limits< DefaultImageType::PixelType::ValueType >::max() - epsilon )
+	    maxPixel[ i ] += epsilon;
+	}
+      // }
+      //
       }
 
     // std::cout << bins;
@@ -656,8 +662,8 @@ HistogramModel
     histogramFilter->SetInput( imageModel->ToImage() );
 
     // Setup histogram filter.
-    histogramFilter->GetFilter()->SetHistogramMin( m_MinPixel );
-    histogramFilter->GetFilter()->SetHistogramMax( m_MaxPixel );
+    histogramFilter->GetFilter()->SetHistogramMin( minPixel );
+    histogramFilter->GetFilter()->SetHistogramMax( maxPixel );
     histogramFilter->GetFilter()->SetNumberOfBins( bins );
     histogramFilter->GetFilter()->SetSubSamplingRate( 1 );
     histogramFilter->GetFilter()->SetNoDataFlag(
diff --git a/Modules/Visualization/MonteverdiCore/otb-module.cmake b/Modules/Visualization/MonteverdiCore/otb-module.cmake
index 1a988f2d047bb2158fd3418ca72c79d72be717e2..e18fe5d07133cefbe35e44c30c4ceb34c3bc3eec 100644
--- a/Modules/Visualization/MonteverdiCore/otb-module.cmake
+++ b/Modules/Visualization/MonteverdiCore/otb-module.cmake
@@ -5,6 +5,7 @@ set(DOCUMENTATION
 otb_module( OTBMonteverdiCore
   ENABLE_SHARED
   DEPENDS
+    OTBBoost
     OTBCarto
     OTBCommon
     OTBImageBase
diff --git a/Modules/Visualization/MonteverdiCore/src/mvdHistogramModel.cxx b/Modules/Visualization/MonteverdiCore/src/mvdHistogramModel.cxx
index 046e0517c93528508291838535d0a7e58f5394da..2b59b02b7dcaa7a2afa5e3dd0ceb2d86a2e6e8fc 100644
--- a/Modules/Visualization/MonteverdiCore/src/mvdHistogramModel.cxx
+++ b/Modules/Visualization/MonteverdiCore/src/mvdHistogramModel.cxx
@@ -60,12 +60,26 @@ namespace
 
 /*****************************************************************************/
 /* STATIC IMPLEMENTATION SECTION                                             */
-
+/*****************************************************************************/
+HistogramModel::RealType
+HistogramModel
+::GetEpsilon()
+{
+  if( boost::is_floating_point< DefaultImageType::PixelType::ValueType >::value )
+    return
+      std::pow(
+	10.0,
+	static_cast< DefaultImageType::PixelType::ValueType >(
+	  -HistogramModel::PRECISION - 1
+	)
+      );
+  else
+    return 1;
+}
 
 /*****************************************************************************/
 /* CLASS IMPLEMENTATION SECTION                                              */
-
-/*******************************************************************************/
+/*****************************************************************************/
 HistogramModel
 ::HistogramModel( QObject* p ) :
   AbstractModel( p ),
@@ -93,6 +107,51 @@ HistogramModel
   return !m_Histograms.IsNull() && m_Histograms->Size()>0;
 }
 
+/*******************************************************************************/
+bool
+HistogramModel
+::IsMonoValue() const
+{
+  // qDebug() << this << "::IsMonoValue() ->" << m_MinPixel==m_MaxPixel;
+
+  return m_MinPixel==m_MaxPixel;
+}
+
+/*******************************************************************************/
+HistogramModel::MeasurementType
+HistogramModel
+::Quantile( unsigned int band,
+	    double p ) const
+{
+  assert( band<m_Histograms->Size() );
+
+  // qDebug()
+  //   << "Quantile" << p << ":" <<
+  //   ( IsMonoValue()
+  //     ? m_MinPixel[ band ]
+  //     : m_Histograms->GetNthElement( band )->Quantile( 0, p ) );
+
+  return
+    IsMonoValue()
+    ? m_MinPixel[ band ]
+    : m_Histograms->GetNthElement( band )->Quantile( 0, p );
+}
+
+/*******************************************************************************/
+HistogramModel::MeasurementType
+HistogramModel
+::Quantile( unsigned int band,
+	    double p,
+	    Bound bound ) const
+{
+  return Quantile(
+    band, 
+    bound==BOUND_UPPER
+    ? 1.0 - p
+    : p
+  );
+}
+
 /*******************************************************************************/
 double
 HistogramModel
@@ -104,19 +163,28 @@ HistogramModel
   // Construct 1D measurement vector.
   assert( histogram->GetMeasurementVectorSize()==1 );
   Histogram::MeasurementVectorType measurement( 1 );
-  measurement[ 0 ] = intensity;
-
-  // Due to float/double conversion, it can happen
-  // that the minimum or maximum value go slightly outside the histogram
-  // Clamping the value solves the issue and avoid RangeError
- // itk::NumericsTraits<>::Clamp(...) was removed
-  // TODO : when otb::Clamp will be developed, use this function
-  measurement[0]  =
-    measurement[0] < histogram->GetBinMin(0, 0)
-    ? histogram->GetBinMin(0, 0)
-    : ( measurement[0] > histogram->GetBinMax(0, histogram->GetSize(0) - 1)
-	? histogram->GetBinMax(0, histogram->GetSize(0) - 1)
-	: measurement[0] );
+
+  {
+    assert( histogram->GetSize( 0 ) > 0 );
+
+    Histogram::MeasurementType binMin( histogram->GetBinMin( 0, 0 ) );
+
+    Histogram::MeasurementType binMax(
+      histogram->GetBinMax( 0, histogram->GetSize( 0 ) - 1 )
+    );
+
+    // Due to float/double conversion, it can happen
+    // that the minimum or maximum value go slightly outside the histogram
+    // Clamping the value solves the issue and avoid RangeError
+    // itk::NumericsTraits<>::Clamp(...) was removed
+    // TODO : when otb::Clamp will be developed, use this function
+    measurement[ 0 ]  =
+      intensity < binMin
+      ? binMin
+      : ( intensity > binMax
+	  ? binMax
+	  : intensity );
+  }
 
   // Get the index of measurement in 1D-histogram.
   Histogram::IndexType index;
@@ -129,19 +197,24 @@ HistogramModel
   MeasurementType minI = histogram->GetBinMin( 0, index[ 0 ] );
   MeasurementType maxI = histogram->GetBinMax( 0, index[ 0 ] );
 
-  // Frequency of current bin
-  Histogram::AbsoluteFrequencyType frequency( histogram->GetFrequency( index ) );
+  assert( minI <= maxI );
 
-  // Initialize result (contribution of current bin)
-  const MeasurementType epsilon = 1.0E-6;
-  double percent = 0.;
+  MeasurementType rangeI = vcl_abs( maxI - minI );
 
-  if ( vcl_abs(maxI - minI) > epsilon )
-    {
-    percent = frequency
-      * (bound == BOUND_LOWER ? (intensity - minI) : (maxI - intensity) )
-      / ( maxI - minI );
-    }
+  // Frequency of current bin
+  Histogram::AbsoluteFrequencyType frequency(
+    histogram->GetFrequency( index )
+  );
+
+  double percent =
+    ( IsMonoValue() ||
+      rangeI <= std::numeric_limits< MeasurementType >::epsilon() )
+    ? 0.0
+    : frequency
+      * ( bound == BOUND_LOWER
+	  ? ( intensity - minI )
+	  : ( maxI - intensity ) )
+      / rangeI;
 
   // Number of bins of histogram.
   Histogram::SizeType::SizeValueType binCount = histogram->Size();
diff --git a/Modules/Visualization/MonteverdiCore/src/mvdVectorImageModel.cxx b/Modules/Visualization/MonteverdiCore/src/mvdVectorImageModel.cxx
index ee81cf3e4b9dc96b3ecc11520432ff41897b0911..02e935debaa6eed00b7c31c12046b0db65f64c21 100644
--- a/Modules/Visualization/MonteverdiCore/src/mvdVectorImageModel.cxx
+++ b/Modules/Visualization/MonteverdiCore/src/mvdVectorImageModel.cxx
@@ -421,16 +421,18 @@ VectorImageModel
     VectorImageSettings::ChannelVector::value_type band =
       GetSettings().GetRgbwChannel( channel );
 
+    bool isInvalid = !histogramModel->IsValid() /* || histogramModel->IsMonoValue() */;
+
     GetSettings().SetLowIntensity(
       channel,
-      !histogramModel->IsValid()
+      isInvalid
       ? min[ band ]
       : histogramModel->Quantile( band , 0.02, BOUND_LOWER )
     );
 
     GetSettings().SetHighIntensity(
       channel,
-      !histogramModel->IsValid()
+      isInvalid
       ? max[ band ]
       : histogramModel->Quantile( band , 0.02, BOUND_UPPER )
     );
diff --git a/Modules/Visualization/MonteverdiGui/include/mvdHistogramWidget.h b/Modules/Visualization/MonteverdiGui/include/mvdHistogramWidget.h
index ddd4dd355e7990cb28b80b68cd13671f6350b70b..d41059107d219cb89459686dc7e5349f4cd04ae9 100644
--- a/Modules/Visualization/MonteverdiGui/include/mvdHistogramWidget.h
+++ b/Modules/Visualization/MonteverdiGui/include/mvdHistogramWidget.h
@@ -159,6 +159,14 @@ public:
    */
   void Clear();
 
+  /**
+   */
+  void SetPrecision( double );
+
+  /**
+   */
+  double GetPrecision() const;
+
   /*-[ PUBLIC SLOTS SECTION ]------------------------------------------------*/
 
 //
@@ -291,6 +299,10 @@ private:
    */
   Bounds m_Bounds[ CURVE_COUNT ];
 
+  /**
+   */
+  double m_Precision;
+
   /**
    */
   bool m_IsGrayscaleActivated;
diff --git a/Modules/Visualization/MonteverdiGui/src/mvdAboutDialog.ui b/Modules/Visualization/MonteverdiGui/src/mvdAboutDialog.ui
index 9edead10086cfebcc5761ebbf19806675f23beeb..3affacf899429573beedef1fdc2b5dc7104bb338 100644
--- a/Modules/Visualization/MonteverdiGui/src/mvdAboutDialog.ui
+++ b/Modules/Visualization/MonteverdiGui/src/mvdAboutDialog.ui
@@ -80,7 +80,7 @@
           </font>
          </property>
          <property name="text">
-          <string>Version M.m.pl (codename)</string>
+          <string>OTB version M.m.pl (codename)</string>
          </property>
         </widget>
        </item>
diff --git a/Modules/Visualization/MonteverdiGui/src/mvdColorBandDynamicsWidget.ui b/Modules/Visualization/MonteverdiGui/src/mvdColorBandDynamicsWidget.ui
index 1e6c6b20b20a9bfb9d0ffff0e745c82d8ec6f827..dd697ccb77c7f316937a185e2effa32c335876be 100644
--- a/Modules/Visualization/MonteverdiGui/src/mvdColorBandDynamicsWidget.ui
+++ b/Modules/Visualization/MonteverdiGui/src/mvdColorBandDynamicsWidget.ui
@@ -304,9 +304,9 @@
         <string/>
        </property>
        <property name="icon">
-        <iconset resource="mvdIcons.qrc">
-         <normaloff>:/icons/Data/Icons/unlocked.png</normaloff>
-         <normalon>:/icons/Data/Icons/locked.png</normalon>:/icons/Data/Icons/unlocked.png</iconset>
+        <iconset>
+         <normaloff>:/icons/Utilities/Data/Icons/unlocked.png</normaloff>
+         <normalon>:/icons/Utilities/Data/Icons/locked.png</normalon>:/icons/Utilities/Data/Icons/unlocked.png</iconset>
        </property>
        <property name="iconSize">
         <size>
@@ -342,7 +342,7 @@
       <string/>
      </property>
      <property name="icon">
-      <iconset resource="mvdIcons.qrc">
+      <iconset>
        <normaloff>:/icons/Data/Icons/execute.png</normaloff>:/icons/Data/Icons/execute.png</iconset>
      </property>
      <property name="iconSize">
diff --git a/Modules/Visualization/MonteverdiGui/src/mvdColorDynamicsController.cxx b/Modules/Visualization/MonteverdiGui/src/mvdColorDynamicsController.cxx
index 396af201034cef1348c584d1b34505295741a2a3..718441879df60d3dbdba0ee2bfe6159a75752452 100644
--- a/Modules/Visualization/MonteverdiGui/src/mvdColorDynamicsController.cxx
+++ b/Modules/Visualization/MonteverdiGui/src/mvdColorDynamicsController.cxx
@@ -699,8 +699,12 @@ ColorDynamicsController
 
   //
   // Access histogram-model.
-  assert( imageModel->GetHistogramModel()!=NULL );
-  bool hasValidHistogram = imageModel->GetHistogramModel()->IsValid();
+  const HistogramModel * histogramModel = imageModel->GetHistogramModel();
+  assert( histogramModel!=NULL );
+
+  bool hasValidHistogram =
+    histogramModel->IsValid() &&
+    !histogramModel->IsMonoValue();
 
   // Block this controller's signals to prevent display refreshed
   // but let let widget(s) signal their changes so linked values
diff --git a/Modules/Visualization/MonteverdiGui/src/mvdHistogramController.cxx b/Modules/Visualization/MonteverdiGui/src/mvdHistogramController.cxx
index 9b8b15f0140740e8c44a3c4690ba3a9cddaaaf86..888a54aa56ac167e2cf83eeaa14c1db486e7ce04 100644
--- a/Modules/Visualization/MonteverdiGui/src/mvdHistogramController.cxx
+++ b/Modules/Visualization/MonteverdiGui/src/mvdHistogramController.cxx
@@ -167,6 +167,7 @@ HistogramController
 
     widget->SetData( chan, x, y, size, xMin, yMin, xMax, yMax );
 
+    widget->SetPrecision( HistogramModel::GetEpsilon() );
     widget->SetLowMarker( chan, settings.GetLowIntensity( chan ) );
     widget->SetHighMarker( chan, settings.GetHighIntensity( chan ) );
 
diff --git a/Modules/Visualization/MonteverdiGui/src/mvdHistogramWidget.cxx b/Modules/Visualization/MonteverdiGui/src/mvdHistogramWidget.cxx
index 88f3d66de2e59aa43175e3b9f97fc5980ce2ef2e..577f507494697de56b6b1a316f846c59bb014296 100644
--- a/Modules/Visualization/MonteverdiGui/src/mvdHistogramWidget.cxx
+++ b/Modules/Visualization/MonteverdiGui/src/mvdHistogramWidget.cxx
@@ -65,6 +65,7 @@ namespace mvd
 /*****************************************************************************/
 /* CONSTANTS                                                                 */
 
+#define PRECISION_MARGIN 4
 
 /**
  * \brief Array of enhanced band names that OTB can return.
@@ -146,6 +147,7 @@ HistogramWidget
   // m_LowPlotMarkers(),
   // m_HighPlotMarkers(),
   m_Bounds(),
+  m_Precision( 0.0 ),
   m_IsGrayscaleActivated( false )
 {
   m_UI->setupUi( this );
@@ -323,6 +325,22 @@ HistogramWidget
   m_UI = NULL;
 }
 
+/*******************************************************************************/
+void
+HistogramWidget
+::SetPrecision( double p )
+{
+  m_Precision = p;
+}
+
+/*******************************************************************************/
+double
+HistogramWidget
+::GetPrecision() const
+{
+  return m_Precision;
+}
+
 /*******************************************************************************/
 void
 HistogramWidget
@@ -576,11 +594,20 @@ HistogramWidget
       yMax = m_Bounds[ i ].m_YMax;
     }
 
-  /*
-  qDebug()
-    << "[" << xMin << "; " << xMax << "]"
-    << "x [" << yMin << "; " << yMax << "]";
-  */
+  if( xMin==xMax )
+    {
+    double epsilon = PRECISION_MARGIN * m_Precision;
+
+    if( xMin >= std::numeric_limits< double >::min() + epsilon )
+      xMin -= epsilon;
+
+    if( xMax <= std::numeric_limits< double >::max() - epsilon )
+      xMax += epsilon;
+    }
+
+  // qDebug()
+  //   << "[" << xMin << "; " << xMax << "]"
+  //   << "x [" << yMin << "; " << yMax << "]";
 
   m_UI->histogramPlot->setAxisScale( QwtPlot::xBottom, xMin, xMax );
   m_UI->histogramPlot->setAxisScale( QwtPlot::yLeft, yMin, yMax );
diff --git a/Modules/Visualization/MonteverdiGui/src/mvdIcons.qrc b/Modules/Visualization/MonteverdiGui/src/mvdIcons.qrc
index 9f9236089a34a49e8f81eb96bc8958c2d93db0db..835ed7133726a2cc2d89f0f6b2f5cba01b3c3314 100644
--- a/Modules/Visualization/MonteverdiGui/src/mvdIcons.qrc
+++ b/Modules/Visualization/MonteverdiGui/src/mvdIcons.qrc
@@ -1,5 +1,5 @@
 <RCC>
-  <qresource prefix="/icons">
+  <qresource prefix="/">
     <file>../../../../Utilities/Data/Icons/execute.png</file>
     <file>../../../../Utilities/Data/Icons/locked.png</file>
     <file>../../../../Utilities/Data/Icons/unlocked.png</file>
diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt
index 4dbab71b71477a9dabd49c9fd90949153e4dc0b7..388df1334256117f4f9fffac32cc5ed4fa356122 100644
--- a/Utilities/Doxygen/CMakeLists.txt
+++ b/Utilities/Doxygen/CMakeLists.txt
@@ -109,10 +109,7 @@ find_package( Perl )
 
 if( PERL_FOUND )
   set( OTB_DOXYGEN_INPUT_FILTER
-    "${PERL_EXECUTABLE} ${OTB_BINARY_DIR}/Utilities/Doxygen/otbdoxygen.pl" )
-
-  configure_file(${OTB_SOURCE_DIR}/Utilities/Doxygen/otbdoxygen.pl.in
-               ${OTB_BINARY_DIR}/Utilities/Doxygen/otbdoxygen.pl)
+    "${PERL_EXECUTABLE} ${OTB_SOURCE_DIR}/Utilities/Doxygen/otbgroup.pl" )
 else()
   set( OTB_DOXYGEN_INPUT_FILTER )
 endif()
@@ -154,7 +151,6 @@ if (BUILD_DOCUMENTATION)
     #COMMAND ${CMAKE_COMMAND} -E copy
     #  ${OTB_SOURCE_DIR}/Utilities/Doxygen/favicon.ico
     #  ${OTB_BINARY_DIR}/Documentation/Doxygen/html
-    DEPENDS         ${OTB_BINARY_DIR}/Utilities/Doxygen/otbdoxygen.pl
    # DEPENDS         ${OTB_BINARY_DIR}/Documentation/Doxygen/Examples.dox
     WORKING_DIRECTORY ${OTB_BINARY_DIR}/Utilities/Doxygen
     )
diff --git a/Utilities/Doxygen/otbdoxygen.pl.in b/Utilities/Doxygen/otbdoxygen.pl.in
deleted file mode 100644
index 18fc1a0663e4cb39e847dae243d09883982f3767..0000000000000000000000000000000000000000
--- a/Utilities/Doxygen/otbdoxygen.pl.in
+++ /dev/null
@@ -1,9 +0,0 @@
-# for vxl files run the vxl_doxy.pl script, and use otbgroup.pl for all other files
-if ( $ARGV[0] =~ /(vxl|vcl|vnl)/)
-{
-    system ("perl @OTB_SOURCE_DIR@/Utilities/Doxygen/vxl_doxy.pl $ARGV[0]");
-}
-else
-{
-    system ("perl @OTB_SOURCE_DIR@/Utilities/Doxygen/otbgroup.pl $ARGV[0]");
-}
diff --git a/Utilities/Doxygen/vxl_doxy.pl b/Utilities/Doxygen/vxl_doxy.pl
deleted file mode 100644
index 87458fe6852553a0c8a93134ea638424c5c508be..0000000000000000000000000000000000000000
--- a/Utilities/Doxygen/vxl_doxy.pl
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/bin/sh
-# -*- perl -*-
-exec perl -w -x $0 ${1+"$@"}
-#!perl
-#line 6
-# If Windows barfs at line 3 here, you will need to run perl -x vxl_doxy.pl
-# You can set up as a permanent file association using the following commands
-#  >assoc .pl-PerlScript
-#  >ftype PerlScript=Perl=C:\Perl\bin\Perl.exe -x "%1" %*
-
-# Script to change the perceps documentation format to Doxygen (JavaDoc) format
-# Authors:
-#         Dave Cooper
-#         Maarten Vergauwen
-# Date:
-#      17/02/2000
-# Modified:
-# 11 April 2001 Ian Scott.   Remove support for old perceps commands
-#  5 May   2001 Geoff Cross. Correctly handle end of verbatim blocks. Allow two contiguous comments
-#  10 May  2001 Ian Scott. Merged Geoffs and my changes
-
-
-# patterns to be matched
-$verbpatt = '\\\\verbatim';
-$endverbpatt = '\\\\endverbatim';
-$slashslashpatt = '^\\s*//';
-$slashslashcolonpatt = '^\\s*//:';
-$slashstarstarpatt = '/**';
-$spacespacepatt = '  ';
-$starpatt = '*';
-$starslashpatt = '*/';
-
-# variables that keep state:
-
-# comment found -> first line should start with /**, next lines with *, last line with */
-$comment = 0;
-
-# verbatim found -> lines should not start with * (visible in Doxygen)
-$verbatim = 0;
-# finish verbatim mode at the end of this line.
-$should_end_verbatim = 0;
-
-$debug = 0;
-
-# mainloop
-while (<>)
-{
-    # preprocessing
-    s/\bVCL_SUNPRO_CLASS_SCOPE_HACK\s*\([^()]*\)//g;
-    s/\bVCL_SUNPRO_ALLOCATOR_HACK\s*\(([^()]*)\)/$1/g;
-    s/\bVCL_CAN_STATIC_CONST_INIT_(INT|FLOAT)\b/1/g;
-    s/\bVCL_STATIC_CONST_INIT_(INT|FLOAT)\s*\(([^()]*)\)/= $2/g;
-    s/\bVCL_DFL_TYPE_PARAM_STLDECL\s*\(([^,()]*),([^,()]*)\)/class $1 = $2 /g;
-    s/\bDECLARE_DYNCREATE\s*\([^()]*\)//g; # for MFC
-
-    if ( $should_end_verbatim )
-    {
-        $verbatim = 0;
-        $should_end_verbatim = 0;
-    }
-
-    # found verbatim ?
-    if ( m/$verbpatt/ ) { $verbatim = 1; };
-
-    # found endverbatim ?
-    if ( m/$endverbpatt/ ) { $should_end_verbatim = 1; };
-
-    # found start of comment: "//:"  ?
-    if ( s!$slashslashcolonpatt!$slashstarstarpatt! )
-    {
-        chomp; s/\s*$//;
-        # escape a space following a dot, add a dot at the end,
-#       # and finish brief doc, unless the line is empty or only has '\file':
-        unless (m!^\s*\/\*\*\s*(\\file)?\s*$!) {
-#         s/\. /.\\ /g; s/(\.)?\s*$/. \*\/\n\/\*/;
-          s/\. /.\\ /g; s/(\.)?\s*$/.\n/;
-        }
-        else { s/$/\n/; }
-
-        if ($comment)
-        {
-            # Previous comment hasn't ended--two contiguous comment blocks.
-            # (Should not happen.)
-            print STDERR "Two contiguous comment blocks -- this should not happen\n";
-            print "*/\n";
-        }
-        $comment = 1;
-        print; next;
-    }
-
-    # Replace '$' with '\f$' (TeX math mode)
-    s/(\\f)?\$(.+?)(\\f)?\$/\\f\$$2\\f\$/g if ($comment);
-
-    # found continuation of comment WITH verbatim -> no "*"
-    if ( m!$slashslashpatt! && $verbatim && $comment)
-    {
-        s!$slashslashpatt!$spacespacepatt!;
-#       # Make 'Modifications' a section title:
-#       s!\b(Modifications?)\b\:?!\<H2\>$1\<\/H2\>!;
-        # remove lines of the form ========= or +-+-+-+-+ or ********* or longer:
-        print unless m/^\s*[*=+-]{9,}\s*$/; next;
-    }
-
-    # found continuation of comment WITHOUT verbatim -> start line with "*"
-    if ( m!$slashslashpatt! && $comment )
-    {
-        s!$slashslashpatt!$starpatt!;
-        # remove lines of the form ========= or +-+-+-+-+ or ********* or longer:
-        print unless m/^\s*[*=+-]{9,}\s*$/; next;
-    }
-
-    # found end of comment -> start line with */
-    # NOTE that *every* line within a comment (also empty lines) *must* start with // !
-    # (In an earlier version of this script, empty lines were allowed inside comments.)
-    if ( $comment && ! m!$slashslashpatt!  )
-    {
-        print "$starslashpatt\n";
-        $comment = 0;
-        print; next;
-    }
-
-    # just print line if not in comment or in file
-    if ( !$comment ) { print; next; }
-
-    # debug - print unprocessed lines (s.b. none)
-    if ($debug) { print "LNP:\t"; print; }
-}