diff --git a/Data/Baseline/OTB/Images/apTvChDimensionalityReductionPCA.tif b/Data/Baseline/OTB/Images/apTvChDimensionalityReductionPCA.tif
new file mode 100644
index 0000000000000000000000000000000000000000..c694726c2717746b6b9dbc678830a5f2723bcd0a
--- /dev/null
+++ b/Data/Baseline/OTB/Images/apTvChDimensionalityReductionPCA.tif
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c12364434ffad8319d964d79a467f6eee094c2472a72234bb6b86a9673bec437
+size 180416
diff --git a/Data/Baseline/OTB/Images/bfTvPCAImageFilter3Norm.tif b/Data/Baseline/OTB/Images/bfTvPCAImageFilter3Norm.tif
index 466bd1d886ae000064b0a0208177d079c97f9cf1..2d918a952e15a63f4bf4e6b09e38e533473f8ef9 100644
--- a/Data/Baseline/OTB/Images/bfTvPCAImageFilter3Norm.tif
+++ b/Data/Baseline/OTB/Images/bfTvPCAImageFilter3Norm.tif
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:1cd38ed0a735e6e7e332237b02982d955a44759565c5892381e508a9859f1628
-size 450331
+oid sha256:7f42429c4f3375ba587c64078a8ebfd08f8b864d104fd14efb8bd9285f074b06
+size 360816
diff --git a/Data/Baseline/OTB/Images/bfTvPCAImageFilter4InvNorm.tif b/Data/Baseline/OTB/Images/bfTvPCAImageFilter4InvNorm.tif
index f01499d2690a5498128e939f3b2b499c5c97f10c..884d6b1670fb03a5d108316d832b9af17a3822d2 100644
--- a/Data/Baseline/OTB/Images/bfTvPCAImageFilter4InvNorm.tif
+++ b/Data/Baseline/OTB/Images/bfTvPCAImageFilter4InvNorm.tif
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:3f8a7ac9f4e604573cb693afe0208adfd09af409be9446c42626453574de6993
-size 429742
+oid sha256:5bfcdfb81cff472ceb447e39fc5a6718224805de34106ecb477535fec8506b84
+size 360816
diff --git a/Data/Baseline/OTB/Images/bfTvPCAImageFilter4Norm.tif b/Data/Baseline/OTB/Images/bfTvPCAImageFilter4Norm.tif
index 253afa7ec9d0b3fda9468201a9d08eff61c6430d..6b36f055b2d5745b5e6056b34a052d85f6503dbe 100644
--- a/Data/Baseline/OTB/Images/bfTvPCAImageFilter4Norm.tif
+++ b/Data/Baseline/OTB/Images/bfTvPCAImageFilter4Norm.tif
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:b071be1eae39fa5a77f9c0851cfa5b02e459e29b351a13da995db7174c5d4412
-size 181939
+oid sha256:538cd26eb6c8a6da6fff2799f090e6d5ef28cad9aca0d0aa813c35c33507b24d
+size 144332
diff --git a/Modules/Applications/AppDimensionalityReduction/app/otbDimensionalityReduction.cxx b/Modules/Applications/AppDimensionalityReduction/app/otbDimensionalityReduction.cxx
index cecb7e9045780d5011ed840afb4a4b679469c352..7ceb4f578efe22251d448e753e602430eed83d5f 100644
--- a/Modules/Applications/AppDimensionalityReduction/app/otbDimensionalityReduction.cxx
+++ b/Modules/Applications/AppDimensionalityReduction/app/otbDimensionalityReduction.cxx
@@ -90,31 +90,33 @@ private:
     SetName("DimensionalityReduction");
     SetDescription("Perform Dimension reduction of the input image.");
     SetDocLongDescription("Performs dimensionality reduction on input image. PCA,NA-PCA,MAF,ICA methods are available. It is also possible to compute the inverse transform to reconstruct the image and to optionally export the transformation matrix to a text file.");
-    SetDocLimitations("This application does not provide the inverse transform and the transformation matrix export for the MAF.");
+    SetDocLimitations("This application does not provide the inverse transform and the transformation matrix export for the MAF. the background value option is not supported for MAF and ICA.");
     SetDocAuthors("OTB-Team");
     SetDocSeeAlso(
                   "\"Kernel maximum autocorrelation factor and minimum noise fraction transformations,\" IEEE Transactions on Image Processing, vol. 20, no. 3, pp. 612-624, (2011)");
 
     AddDocTag(Tags::Filter);
-	AddDocTag(Tags::DimensionReduction);
+    AddDocTag(Tags::DimensionReduction);
 
     AddParameter(ParameterType_InputImage, "in", "Input Image");
     SetParameterDescription("in", "The input image to apply dimensionality reduction.");
     AddParameter(ParameterType_OutputImage, "out", "Output Image");
     SetParameterDescription("out", "output image. Components are ordered by decreasing eigenvalues.");
     MandatoryOff("out");
-    AddParameter(ParameterType_Group, "rescale", "Rescale Output");
+
+    AddParameter(ParameterType_Choice, "rescale", "Rescale Output");
+    SetParameterDescription("rescale", "Enable rescaling of the reduced output image.");
 
     MandatoryOff("rescale");
-    //  AddChoice("rescale.no","No rescale");
-    // AddChoice("rescale.minmax","rescale to min max value");
+    AddChoice("rescale.no", "No rescale");
+    AddChoice("rescale.minmax", "rescale to min max value");
 
-    AddParameter(ParameterType_Float, "rescale.outmin", "Output min value");
-    AddParameter(ParameterType_Float, "rescale.outmax", "Output max value");
-    SetDefaultParameterFloat("rescale.outmin", 0.0);
-    SetParameterDescription("rescale.outmin", "Minimum value of the output image.");
-    SetDefaultParameterFloat("rescale.outmax", 255.0);
-    SetParameterDescription("rescale.outmax", "Maximum value of the output image.");
+    AddParameter(ParameterType_Float, "rescale.minmax.outmin", "Output min value");
+    AddParameter(ParameterType_Float, "rescale.minmax.outmax", "Output max value");
+    SetDefaultParameterFloat("rescale.minmax.outmin", 0.0);
+    SetParameterDescription("rescale.minmax.outmin", "Minimum value of the output image.");
+    SetDefaultParameterFloat("rescale.minmax.outmax", 255.0);
+    SetParameterDescription("rescale.minmax.outmax", "Maximum value of the output image.");
 
     AddParameter(ParameterType_OutputImage, "outinv", " Inverse Output Image");
     SetParameterDescription("outinv", "reconstruct output image.");
@@ -125,6 +127,14 @@ private:
 
     AddChoice("method.pca", "PCA");
     SetParameterDescription("method.pca", "Principal Component Analysis.");
+    AddParameter(ParameterType_OutputFilename, "method.pca.outeigenvalues", "Output file containing eigenvalues (txt format)");
+    SetParameterDescription("method.pca.outeigenvalues", "Output file containing eigenvalues (txt format).");
+    MandatoryOff("method.pca.outeigenvalues");
+    AddParameter(ParameterType_Bool, "method.pca.whiten", "Perform pca whitening");
+    SetParameterDescription("method.pca.whiten", "Perform whitening and ensure uncorrelated outputs with unit component wise variances");
+    SetParameterInt("method.pca.whiten", 1);
+    MandatoryOff("method.pca.whiten");
+
     AddChoice("method.napca", "NA-PCA");
     SetParameterDescription("method.napca", "Noise Adjusted Principal Component Analysis.");
     AddParameter(ParameterType_Int, "method.napca.radiusx", "Set the x radius of the sliding window");
@@ -136,6 +146,7 @@ private:
 
     AddChoice("method.maf", "MAF");
     SetParameterDescription("method.maf", "Maximum Autocorrelation Factor.");
+
     AddChoice("method.ica", "ICA");
     SetParameterDescription("method.ica", "Independent Component Analysis using a stabilized fixed point FastICA algorithm.");
     AddParameter(ParameterType_Int, "method.ica.iter", "number of iterations");
@@ -164,14 +175,17 @@ private:
     MandatoryOff("nbcomp");
     SetMinimumParameterIntValue("nbcomp", 0);
 
-    AddParameter(ParameterType_Bool, "normalize", "Normalize");
-    SetParameterDescription("normalize", "Center and reduce data before Dimensionality reduction.");
+    AddParameter(ParameterType_Bool, "normalize", "Center and reduce data");
+    SetParameterDescription("normalize", "Center and reduce data before Dimensionality reduction (if this parameter is set to false, the data will be centered but not reduced.");
 
     AddParameter(ParameterType_OutputFilename, "outmatrix", "Transformation matrix output (text format)");
     SetParameterDescription("outmatrix", "Filename to store the transformation matrix (csv format)");
     MandatoryOff("outmatrix");
     DisableParameter("outmatrix");
     
+    AddParameter(ParameterType_Float, "bv", "Background Value");
+    SetParameterDescription( "bv", "Background value to ignore in computation of the transformation matrix. Note that all pixels will still be processed when applying the transformation." );
+    MandatoryOff("bv");
 
     AddRAMParameter();
 
@@ -237,74 +251,111 @@ private:
     // Get Parameters
     int nbComp = GetParameterInt("nbcomp");
     bool normalize = GetParameterInt("normalize");
-    bool rescale = IsParameterEnabled("rescale");
-
     bool invTransform = HasValue("outinv") && IsParameterEnabled("outinv");
     switch (GetParameterInt("method"))
       {
       // PCA Algorithm
       case 0:
         {
+          otbAppLogINFO("Using the PCA Algorithm ");
+          PCAForwardFilterType::Pointer filter    = PCAForwardFilterType::New();
+          m_ForwardFilter                         = filter;
+          PCAInverseFilterType::Pointer invFilter = PCAInverseFilterType::New();
+          m_InverseFilter                         = invFilter;
 
-        otbAppLogDEBUG( << "PCA Algorithm ");
-        PCAForwardFilterType::Pointer filter = PCAForwardFilterType::New();
-        m_ForwardFilter = filter;
-        PCAInverseFilterType::Pointer invFilter = PCAInverseFilterType::New();
-        m_InverseFilter = invFilter;
-
+          filter->SetInput(GetParameterFloatVectorImage("in"));
+          filter->SetNumberOfPrincipalComponentsRequired(nbComp);
+          filter->SetWhitening(GetParameterInt("method.pca.whiten"));
 
-        filter->SetInput(GetParameterFloatVectorImage("in"));
-        filter->SetNumberOfPrincipalComponentsRequired(nbComp);
-        filter->SetUseNormalization(normalize);        
-        m_ForwardFilter->GetOutput()->UpdateOutputInformation();
-        
-        if (invTransform)
-          {  
-          invFilter->SetInput(m_ForwardFilter->GetOutput());
+          // Center AND reduce the input data.
           if (normalize)
+          {
+            filter->SetUseNormalization(true);
+            filter->SetUseVarianceForNormalization(true);
+          }
+          // Only center the input data.
+          else
+          {
+            filter->SetUseNormalization(true);
+            filter->SetUseVarianceForNormalization(false);
+          }
+
+          if( HasValue( "bv" ) )
+          {
+            filter->SetStatisticsUserIgnoredValue(GetParameterFloat("bv"));
+          }
+          
+          m_ForwardFilter->GetOutput()->UpdateOutputInformation();
+
+          // Write eigenvalues
+          std::ofstream outFile;
+          outFile.open(this->GetParameterString("method.pca.outeigenvalues"));
+          if (outFile.is_open())
+          {
+            outFile << std::fixed;
+            outFile.precision(10);
+
+            outFile << filter->GetEigenValues() << std::endl;
+            ;
+            outFile.close();
+          }
+
+          if (invTransform)
+          {
+            invFilter->SetInput(m_ForwardFilter->GetOutput());
+            // Data has been centered and reduced by the forward filter
+            if (normalize)
             {
             otbAppLogINFO( << "Normalization MeanValue:"<<filter->GetMeanValues() );
             invFilter->SetMeanValues(filter->GetMeanValues());
-            // By default normalization by std dev is deactivated in
-            //forward filter, and GetStdDevValues() returns an empty
-            //vector, which confuses the invFilter.
-            //invFilter->SetStdDevValues(filter->GetStdDevValues());
+            invFilter->SetStdDevValues(filter->GetStdDevValues());
+            }
+            // Data has been centered by the forward filter
+            else
+            {
+              invFilter->SetMeanValues(filter->GetMeanValues());
             }
 
-          invFilter->SetTransformationMatrix(filter->GetTransformationMatrix());
-          m_TransformationMatrix = invFilter->GetTransformationMatrix();
+            invFilter->SetTransformationMatrix(filter->GetTransformationMatrix());
+            m_TransformationMatrix = invFilter->GetTransformationMatrix();
           }
 
         m_TransformationMatrix = filter->GetTransformationMatrix();
 
+        otbAppLogINFO("PCA transform has been computed.");
         break;
         }
       case 1:
         {
-        otbAppLogDEBUG( << "NA-PCA Algorithm ");
+          otbAppLogINFO("Using the NA-PCA Algorithm ");
 
-        // NA-PCA
+          // NA-PCA
 
-        unsigned int radiusX = static_cast<unsigned int> (GetParameterInt("method.napca.radiusx"));
-        unsigned int radiusY = static_cast<unsigned int> (GetParameterInt("method.napca.radiusy"));
+          unsigned int radiusX = static_cast<unsigned int>(GetParameterInt("method.napca.radiusx"));
+          unsigned int radiusY = static_cast<unsigned int>(GetParameterInt("method.napca.radiusy"));
 
-        // Noise filtering
-        NoiseFilterType::RadiusType radius = { { radiusX, radiusY } };
+          // Noise filtering
+          NoiseFilterType::RadiusType radius = {{radiusX, radiusY}};
 
-        NAPCAForwardFilterType::Pointer filter = NAPCAForwardFilterType::New();
-        m_ForwardFilter = filter;
-        NAPCAInverseFilterType::Pointer invFilter = NAPCAInverseFilterType::New();
-        m_InverseFilter = invFilter;
+          NAPCAForwardFilterType::Pointer filter    = NAPCAForwardFilterType::New();
+          m_ForwardFilter                           = filter;
+          NAPCAInverseFilterType::Pointer invFilter = NAPCAInverseFilterType::New();
+          m_InverseFilter                           = invFilter;
 
 
-        filter->SetInput(GetParameterFloatVectorImage("in"));
-        filter->SetNumberOfPrincipalComponentsRequired(nbComp);
-        filter->SetUseNormalization(normalize);
-        filter->GetNoiseImageFilter()->SetRadius(radius);
+          filter->SetInput(GetParameterFloatVectorImage("in"));
+          filter->SetNumberOfPrincipalComponentsRequired(nbComp);
+          filter->SetUseNormalization(normalize);
+          filter->GetNoiseImageFilter()->SetRadius(radius);
 
-        m_ForwardFilter->GetOutput()->UpdateOutputInformation();
-        
-        if (invTransform)
+          if( HasValue( "bv" ) )
+          {
+            filter->SetStatisticsUserIgnoredValue(GetParameterFloat("bv"));
+          }
+          
+          m_ForwardFilter->GetOutput()->UpdateOutputInformation();
+
+          if (invTransform)
           {
           otbAppLogDEBUG( << "Compute Inverse Transform");
           invFilter->SetInput(m_ForwardFilter->GetOutput());
@@ -322,37 +373,37 @@ private:
           }
 
         m_TransformationMatrix = filter->GetTransformationMatrix();
-
+        otbAppLogINFO("NA-PCA transform has been computed.");
         break;
         }
       case 2:
         {
-        otbAppLogDEBUG( << "MAF Algorithm ");
-        MAFForwardFilterType::Pointer filter = MAFForwardFilterType::New();
-        m_ForwardFilter = filter;
-        filter->SetInput(GetParameterFloatVectorImage("in"));
-        otbAppLogINFO( << "V :"<<std::endl<<filter->GetV()<<"Auto-Correlation :"<<std::endl <<filter->GetAutoCorrelation() );
+          otbAppLogINFO("Using the MAF Algorithm ");
+          MAFForwardFilterType::Pointer filter = MAFForwardFilterType::New();
+          m_ForwardFilter                      = filter;
+          filter->SetInput(GetParameterFloatVectorImage("in"));
+          otbAppLogINFO(<< "V :" << std::endl << filter->GetV() << "Auto-Correlation :" << std::endl << filter->GetAutoCorrelation());
 
-        break;
+          break;
         }
       case 3:
         {
-        otbAppLogDEBUG( << "Fast ICA Algorithm ");
+          otbAppLogINFO("Using the fast ICA Algorithm ");
 
-        unsigned int nbIterations = static_cast<unsigned int> (GetParameterInt("method.ica.iter"));
-        double mu = static_cast<double> (GetParameterFloat("method.ica.mu"));
+          unsigned int nbIterations = static_cast<unsigned int>(GetParameterInt("method.ica.iter"));
+          double       mu           = static_cast<double>(GetParameterFloat("method.ica.mu"));
 
-        ICAForwardFilterType::Pointer filter = ICAForwardFilterType::New();
-        m_ForwardFilter = filter;
-        ICAInverseFilterType::Pointer invFilter = ICAInverseFilterType::New();
-        m_InverseFilter = invFilter;
+          ICAForwardFilterType::Pointer filter    = ICAForwardFilterType::New();
+          m_ForwardFilter                         = filter;
+          ICAInverseFilterType::Pointer invFilter = ICAInverseFilterType::New();
+          m_InverseFilter                         = invFilter;
 
-        filter->SetInput(GetParameterFloatVectorImage("in"));
-        filter->SetNumberOfPrincipalComponentsRequired(nbComp);
-        filter->SetNumberOfIterations(nbIterations);
-        filter->SetMu(mu);
-        
-        switch (GetParameterInt("method.ica.g"))
+          filter->SetInput(GetParameterFloatVectorImage("in"));
+          filter->SetNumberOfPrincipalComponentsRequired(nbComp);
+          filter->SetNumberOfIterations(nbIterations);
+          filter->SetMu(mu);
+
+          switch (GetParameterInt("method.ica.g"))
           {
           // tanh
           case 0:
@@ -406,10 +457,10 @@ private:
           invFilter->SetPCATransformationMatrix(filter->GetPCATransformationMatrix());
           invFilter->SetTransformationMatrix(filter->GetTransformationMatrix());
           }
+          otbAppLogINFO("ICA transform has been computed.");
+          m_TransformationMatrix = filter->GetTransformationMatrix();
 
-        m_TransformationMatrix = filter->GetTransformationMatrix();
-
-        break;
+          break;
         }
 
       default:
@@ -443,52 +494,54 @@ private:
         //Write transformation matrix
         std::ofstream outFile;
         outFile.open(this->GetParameterString("outmatrix"));
-        outFile << std::fixed;
-        outFile.precision(10);
+        if (outFile.is_open())
+        {
+          outFile << std::fixed;
+          outFile.precision(10);
 
-        outFile << m_TransformationMatrix;
-        outFile.close();
+          outFile << m_TransformationMatrix;
+          outFile.close();
+        }
         }
       }
 
-    if (!rescale)
+      if (GetParameterString("rescale") == "no")
       {
       SetParameterOutputImage("out", m_ForwardFilter->GetOutput());
       }
     else
       {
-      otbAppLogDEBUG( << "Rescaling " )
-      otbAppLogDEBUG( << "Starting Min/Max computation" )
+        otbAppLogINFO("Starting Min/Max computation for rescaling");
 
-      m_MinMaxFilter = MinMaxFilterType::New();
-      m_MinMaxFilter->SetInput(m_ForwardFilter->GetOutput());
-      //m_MinMaxFilter->GetStreamer()->SetNumberOfLinesStrippedStreaming(50);
-      m_MinMaxFilter->GetStreamer()->SetAutomaticAdaptativeStreaming(GetParameterInt("ram"));
+        m_MinMaxFilter = MinMaxFilterType::New();
+        m_MinMaxFilter->SetInput(m_ForwardFilter->GetOutput());
+        m_MinMaxFilter->GetStreamer()->SetAutomaticAdaptativeStreaming(GetParameterInt("ram"));
 
-      AddProcess(m_MinMaxFilter->GetStreamer(), "Min/Max computing");
-      m_MinMaxFilter->Update();
+        AddProcess(m_MinMaxFilter->GetStreamer(), "Min/Max computing");
+        m_MinMaxFilter->Update();
 
-      otbAppLogDEBUG( << "Min/Max computation done : min=" << m_MinMaxFilter->GetMinimum()
-          << " max=" << m_MinMaxFilter->GetMaximum() )
+        otbAppLogINFO(<< "Min/Max computation done : min=" << m_MinMaxFilter->GetMinimum() << " max=" << m_MinMaxFilter->GetMaximum())
 
-      FloatVectorImageType::PixelType inMin, inMax;
+            FloatVectorImageType::PixelType inMin,
+            inMax;
 
-      m_RescaleFilter = RescaleImageFilterType::New();
-      m_RescaleFilter->SetInput(m_ForwardFilter->GetOutput());
-      m_RescaleFilter->SetInputMinimum(m_MinMaxFilter->GetMinimum());
-      m_RescaleFilter->SetInputMaximum(m_MinMaxFilter->GetMaximum());
+        m_RescaleFilter = RescaleImageFilterType::New();
+        m_RescaleFilter->SetInput(m_ForwardFilter->GetOutput());
+        m_RescaleFilter->SetAutomaticInputMinMaxComputation(false);
+        m_RescaleFilter->SetInputMinimum(m_MinMaxFilter->GetMinimum());
+        m_RescaleFilter->SetInputMaximum(m_MinMaxFilter->GetMaximum());
 
-      FloatVectorImageType::PixelType outMin, outMax;
-      outMin.SetSize(m_ForwardFilter->GetOutput()->GetNumberOfComponentsPerPixel());
-      outMax.SetSize(m_ForwardFilter->GetOutput()->GetNumberOfComponentsPerPixel());
-      outMin.Fill(GetParameterFloat("rescale.outmin"));
-      outMax.Fill(GetParameterFloat("rescale.outmax"));
+        FloatVectorImageType::PixelType outMin, outMax;
+        outMin.SetSize(m_ForwardFilter->GetOutput()->GetNumberOfComponentsPerPixel());
+        outMax.SetSize(m_ForwardFilter->GetOutput()->GetNumberOfComponentsPerPixel());
+        outMin.Fill(GetParameterFloat("rescale.minmax.outmin"));
+        outMax.Fill(GetParameterFloat("rescale.minmax.outmax"));
 
-      m_RescaleFilter->SetOutputMinimum(outMin);
-      m_RescaleFilter->SetOutputMaximum(outMax);
-      m_RescaleFilter->UpdateOutputInformation();
+        m_RescaleFilter->SetOutputMinimum(outMin);
+        m_RescaleFilter->SetOutputMaximum(outMax);
+        m_RescaleFilter->UpdateOutputInformation();
 
-      SetParameterOutputImage("out", m_RescaleFilter->GetOutput());
+        SetParameterOutputImage("out", m_RescaleFilter->GetOutput());
       }
 
 
diff --git a/Modules/Applications/AppDimensionalityReduction/test/CMakeLists.txt b/Modules/Applications/AppDimensionalityReduction/test/CMakeLists.txt
index e4037adcb0a388f34ae1ba4cc49a70200bab4d08..82d8b013b9e79e65ba95b9d872b40cfb5d0d061a 100644
--- a/Modules/Applications/AppDimensionalityReduction/test/CMakeLists.txt
+++ b/Modules/Applications/AppDimensionalityReduction/test/CMakeLists.txt
@@ -35,7 +35,7 @@ otb_test_application(NAME   apTvFEDimensionalityReductionPCA
                              -out ${TEMP}/apTvChDimensionalityReductionPCA.tif
                              -method pca
                      VALID   --compare-image 0.025
-                             ${BASELINE}/bfTvPCAImageFilter3.tif
+                             ${BASELINE}/apTvChDimensionalityReductionPCA.tif
                              ${TEMP}/apTvChDimensionalityReductionPCA.tif)
 
 #-------------------------------------------------------------------------------
diff --git a/Modules/Filtering/DimensionalityReduction/include/otbMNFImageFilter.h b/Modules/Filtering/DimensionalityReduction/include/otbMNFImageFilter.h
index 9d35211893a0519a220620a151dd070721ec4744..94b9b74d9c5eee286ece13ac16222114564da46b 100644
--- a/Modules/Filtering/DimensionalityReduction/include/otbMNFImageFilter.h
+++ b/Modules/Filtering/DimensionalityReduction/include/otbMNFImageFilter.h
@@ -145,6 +145,19 @@ public:
     m_IsTransformationMatrixForward = isForward;
   }
 
+  void SetStatisticsUserIgnoredValue ( RealType value )
+  {
+    /** User ignored value for the normalizer */
+    m_Normalizer->GetCovarianceEstimator()->SetUserIgnoredValue(value);
+    m_Normalizer->GetCovarianceEstimator()->SetIgnoreUserDefinedValue(true);
+    /** User ignored value for the covariance estimator */
+    m_CovarianceEstimator->SetUserIgnoredValue(value);
+    m_CovarianceEstimator->SetIgnoreUserDefinedValue(true);
+    /** User ignored value for the noise covariance estimator */
+    m_NoiseCovarianceEstimator->SetUserIgnoredValue(value);
+    m_NoiseCovarianceEstimator->SetIgnoreUserDefinedValue(true);
+  }
+  
   itkGetConstMacro(EigenValues, VectorType);
 
 protected:
diff --git a/Modules/Filtering/DimensionalityReduction/include/otbMNFImageFilter.hxx b/Modules/Filtering/DimensionalityReduction/include/otbMNFImageFilter.hxx
index d120bbde8ed76bf3efef89be4b33afc55828d5c6..68579a81cf7b9b4e5f6dd5679e36309879b0d3a5 100644
--- a/Modules/Filtering/DimensionalityReduction/include/otbMNFImageFilter.hxx
+++ b/Modules/Filtering/DimensionalityReduction/include/otbMNFImageFilter.hxx
@@ -376,54 +376,6 @@ MNFImageFilter< TInputImage, TOutputImage, TNoiseImageFilter, TDirectionOfTransf
 
   InternalMatrixType transf = Rn_inv * U;
 
-#if 0
-  InternalMatrixType Ax = m_CovarianceMatrix.GetVnlMatrix();
-  InternalMatrixType Ax_inv = vnl_matrix_inverse< MatrixElementType > ( Ax );
-  InternalMatrixType An = m_NoiseCovarianceMatrix.GetVnlMatrix();
-  InternalMatrixType W = An * Ax_inv;
-#endif
-
-#if 0
-  InternalMatrixType transf;
-  vnl_vector< MatrixElementType > vectValP;
-  vnl_symmetric_eigensystem_compute( W, transf, vectValP );
-
-  InternalMatrixType valP ( vectValP.size(), vectValP.size(), vnl_matrix_null );
-  for ( unsigned int i = 0; i < vectValP.size(); ++i )
-    valP(i, i) = vectValP[i];
-#endif
-
-#if 0
-  vnl_svd< MatrixElementType > solver ( W );
-  InternalMatrixType transf = solver.U();
-  InternalMatrixType valP = solver.W();
-#endif
-
-#if 0
-  MatrixType Id ( m_CovarianceMatrix );
-  Id.SetIdentity();
-
-  vnl_generalized_eigensystem solver ( W, Id.GetVnlMatrix() );
-
-  InternalMatrixType transf = solver.V;
-  transf.fliplr();
-
-  InternalMatrixType valP = solver.D;
-  valP.fliplr();
-  valP.flipud();
-#endif
-
-/*
-  InternalMatrixType normMat = transf.transpose() * Ax * transf;
-
-  for ( unsigned int i = 0; i < transf.rows(); ++i )
-  {
-    double norm = 1. / std::sqrt( normMat.get(i, i) );
-    for ( unsigned int j = 0; j < transf.cols(); ++j )
-      transf.put( j, i, transf.get(j, i) * norm );
-  }
-*/
-
   transf.inplace_transpose();
 
   if ( m_NumberOfPrincipalComponentsRequired
diff --git a/Modules/Filtering/DimensionalityReduction/include/otbPCAImageFilter.h b/Modules/Filtering/DimensionalityReduction/include/otbPCAImageFilter.h
index 3368163846bb09339b0fe29eeed9981043f66ac5..6dc5702172e5f2a2240e06e1082e37b9027cdda0 100644
--- a/Modules/Filtering/DimensionalityReduction/include/otbPCAImageFilter.h
+++ b/Modules/Filtering/DimensionalityReduction/include/otbPCAImageFilter.h
@@ -98,6 +98,9 @@ public:
   itkSetMacro(NumberOfPrincipalComponentsRequired, unsigned int);
   itkGetMacro(NumberOfPrincipalComponentsRequired, unsigned int);
 
+  itkSetMacro(Whitening, bool);
+  itkGetMacro(Whitening, bool);
+
   itkGetMacro(CovarianceEstimator, CovarianceEstimatorFilterType *);
   itkGetMacro(Transformer, TransformFilterType *);
 
@@ -158,7 +161,17 @@ public:
     m_StdDevValues = vec;
     this->Modified();
   }
-
+  
+  void SetStatisticsUserIgnoredValue ( RealType value )
+  {
+    /** User ignored value for the normalizer */
+    m_Normalizer->GetCovarianceEstimator()->SetUserIgnoredValue(value);
+    m_Normalizer->GetCovarianceEstimator()->SetIgnoreUserDefinedValue(true);
+    /** User ignored value for the covariance estimator */
+    m_CovarianceEstimator->SetUserIgnoredValue(value);
+    m_CovarianceEstimator->SetIgnoreUserDefinedValue(true);
+  }
+  
 protected:
   PCAImageFilter();
   ~PCAImageFilter() override { }
@@ -197,6 +210,7 @@ protected:
   bool         m_GivenCovarianceMatrix;
   bool         m_GivenTransformationMatrix;
   bool         m_IsTransformationMatrixForward;
+  bool         m_Whitening;
 
   VectorType m_MeanValues;
   VectorType m_StdDevValues;
diff --git a/Modules/Filtering/DimensionalityReduction/include/otbPCAImageFilter.hxx b/Modules/Filtering/DimensionalityReduction/include/otbPCAImageFilter.hxx
index 6e49b249ec8ffd5a589e0f900cee9be387aef40c..51633d1eafda79562947a590da19baaf9a33b7e3 100644
--- a/Modules/Filtering/DimensionalityReduction/include/otbPCAImageFilter.hxx
+++ b/Modules/Filtering/DimensionalityReduction/include/otbPCAImageFilter.hxx
@@ -39,7 +39,7 @@ PCAImageFilter< TInputImage, TOutputImage, TDirectionOfTransformation >
   this->SetNumberOfRequiredInputs(1);
 
   m_NumberOfPrincipalComponentsRequired = 0;
-
+  m_Whitening = true;
   m_UseNormalization = false;
   m_UseVarianceForNormalization = false;
   m_GivenMeanValues = false;
@@ -154,14 +154,43 @@ PCAImageFilter< TInputImage, TOutputImage, TDirectionOfTransformation >
         if ( !m_GivenMeanValues )
         {
           m_MeanValues = m_Normalizer->GetCovarianceEstimator()->GetMean();
+          // Set User mean value so the filter won't recompute the stats
+          m_Normalizer->SetMean( m_MeanValues );
 
           if ( !m_GivenStdDevValues )
+          {
             m_StdDevValues = m_Normalizer->GetFunctor().GetStdDev();
-
+            
+            
+          }
           if ( m_UseVarianceForNormalization )
-            m_CovarianceMatrix = m_Normalizer->GetCovarianceEstimator()->GetCorrelation();
+          {
+            // Set User std value so the filter won't recompute the stats
+            m_Normalizer->SetStdDev( m_StdDevValues );
+            
+            // Compute the correlation matrix, note that GetCovarianceEstimator()->GetCorrelation()
+            // would give us the matrix with component E[XY], which is not what we want., we want
+            // the matrix defined by its component (E[XY]-E[X]E[Y])/(sigmaX*sigmaY)
+            
+            m_CovarianceMatrix = m_Normalizer->GetCovarianceEstimator()->GetCovariance();
+            
+            auto cov = m_Normalizer->GetCovarianceEstimator()->GetCovariance();
+            auto numberOfComponent = this->GetInput()->GetNumberOfComponentsPerPixel();
+            
+            for (unsigned int r = 0; r < numberOfComponent; ++r)
+            {
+              for (unsigned int c = 0; c < numberOfComponent; ++c)
+              {
+                m_CovarianceMatrix(r,c) = cov(r,c) / std::sqrt(cov(r,r)*cov(c,c));
+              }
+            }
+          }
           else
+          {
+            m_Normalizer->SetUseStdDev(false);
             m_CovarianceMatrix = m_Normalizer->GetCovarianceEstimator()->GetCovariance();
+          }
+        
         }
         else
         {
@@ -337,50 +366,6 @@ void
 PCAImageFilter< TInputImage, TOutputImage, TDirectionOfTransformation >
 ::GenerateTransformationMatrix ()
 {
-#if 0
-  /*
-   * Old stuff but did work !
-   */
-
-  MatrixType Id ( m_CovarianceMatrix );
-  Id.SetIdentity();
-
-  typename MatrixType::InternalMatrixType A = m_CovarianceMatrix.GetVnlMatrix();
-  typename MatrixType::InternalMatrixType I = Id.GetVnlMatrix();
-
-  vnl_generalized_eigensystem solver ( A, I );
-
-  typename MatrixType::InternalMatrixType transf = solver.V;
-  transf.fliplr();
-  transf.inplace_transpose();
-
-  vnl_vector< double > valP = solver.D.diagonal();
-  valP.flip();
-
-  /*
-   * We used normalized PCA
-   */
-  for ( unsigned int i = 0; i < valP.size(); ++i )
-  {
-    if (  valP[i] != 0. )
-      valP[i] = 1. / std::sqrt( std::abs( valP[i] ) );
-    else
-      throw itk::ExceptionObject( __FILE__, __LINE__,
-            "Null Eigen value !!", ITK_LOCATION );
-  }
-  valP.post_multiply( transf );
-
-  if ( m_NumberOfPrincipalComponentsRequired
-      != this->GetInput()->GetNumberOfComponentsPerPixel() )
-    m_TransformationMatrix = transf.get_n_rows( 0, m_NumberOfPrincipalComponentsRequired );
-  else
-    m_TransformationMatrix = transf;
-
-
-  m_EigenValues.SetSize( m_NumberOfPrincipalComponentsRequired );
-  for ( unsigned int i = 0; i < m_NumberOfPrincipalComponentsRequired; ++i )
-    m_EigenValues[i] = static_cast< RealType >( valP[i] );
-#else
   InternalMatrixType transf;
   vnl_vector<double> vectValP;
   vnl_symmetric_eigensystem_compute( m_CovarianceMatrix.GetVnlMatrix(), transf, vectValP );
@@ -389,17 +374,25 @@ PCAImageFilter< TInputImage, TOutputImage, TDirectionOfTransformation >
   for ( unsigned int i = 0; i < vectValP.size(); ++i )
     valP(i, i) = vectValP[i];
 
+  m_EigenValues.SetSize( m_NumberOfPrincipalComponentsRequired );
+  for ( unsigned int i = 0; i < m_NumberOfPrincipalComponentsRequired; ++i )
+    m_EigenValues[m_NumberOfPrincipalComponentsRequired - 1 - i] = static_cast< RealType >( vectValP[i] );
+  
   /* We used normalized PCA */
   for ( unsigned int i = 0; i < valP.rows(); ++i )
   {
     if (  valP(i, i) > 0. )
     {
-      valP(i, i) = 1. / std::sqrt( valP(i, i) );
+      if (m_Whitening)
+        valP(i, i) = 1. / std::sqrt( valP(i, i) );
     }
     else if ( valP(i, i) < 0. )
     {
       otbMsgDebugMacro( << "ValP(" << i << ") neg : " << valP(i, i) << " taking abs value" );
-      valP(i, i) = 1. / std::sqrt( std::abs( valP(i, i) ) );
+      if (m_Whitening)
+        valP(i, i) = 1. / std::sqrt( std::abs( valP(i, i) ) );
+      else
+        valP(i, i) = std::abs( valP(i, i));
     }
     else
     {
@@ -415,12 +408,6 @@ PCAImageFilter< TInputImage, TOutputImage, TDirectionOfTransformation >
     m_TransformationMatrix = transf.get_n_rows( 0, m_NumberOfPrincipalComponentsRequired );
   else
     m_TransformationMatrix = transf;
-
-  m_EigenValues.SetSize( m_NumberOfPrincipalComponentsRequired );
-  for ( unsigned int i = 0; i < m_NumberOfPrincipalComponentsRequired; ++i )
-    m_EigenValues[i] = static_cast< RealType >( valP(i, i) );
-
-#endif
 }