diff --git a/Code/Hyperspectral/otbVcaImageFilter.h b/Code/Hyperspectral/otbVcaImageFilter.h
index 2622906cf58d711823039947b190273eeafe27b7..ed4f8e9064cb70db696d6eac8b4fd6adbab31926 100644
--- a/Code/Hyperspectral/otbVcaImageFilter.h
+++ b/Code/Hyperspectral/otbVcaImageFilter.h
@@ -27,9 +27,12 @@
 #include "otbProjectiveProjectionImageFilter.h"
 #include "otbMatrixMultiplyImageFilter.h"
 #include "otbVectorImageToMatrixImageFilter.h"
-#include "otbStreamingMinMaxImageFilter2.h"
+#include "otbStreamingMinMaxImageFilter.h"
 #include "otbStreamingStatisticsImageFilter.h"
-#include "otbStreamingStatisticsVectorImageFilter2.h"
+#include "otbStreamingStatisticsVectorImageFilter.h"
+#include "otbPCAImageFilter.h"
+#include "otbVectorImageToAmplitudeImageFilter.h"
+#include "otbConcatenateScalarValueImageFilter.h"
 
 #include "itkMersenneTwisterRandomVariateGenerator.h"
 #include "vnl/algo/vnl_svd.h"
@@ -68,17 +71,21 @@ public:
   typedef typename VectorImageType::InternalPixelType  InternalPixelType;
   typedef InternalPixelType                            PrecisionType;
 
-  typedef otb::Image<InternalPixelType>       ImageType;
+  typedef otb::Image<InternalPixelType>                ImageType;
 
   typedef itk::AbsImageFilter<ImageType, ImageType>                                           AbsImageFilterType;
   typedef otb::ProjectiveProjectionImageFilter<VectorImageType,VectorImageType,PrecisionType> ProjectiveProjectionImageFilterType;
   typedef otb::DotProductImageFilter<VectorImageType,ImageType>                               DotProductImageFilterType;
   typedef otb::MatrixMultiplyImageFilter<VectorImageType,VectorImageType,PrecisionType>       MatrixMultiplyImageFilterType;
   typedef otb::VectorImageToMatrixImageFilter<VectorImageType>                                VectorImageToMatrixImageFilterType;
-  typedef otb::StreamingMinMaxImageFilter2<ImageType>                                         StreamingMinMaxImageFilterType;
-  typedef otb::StreamingStatisticsVectorImageFilter2<VectorImageType,PrecisionType>           StreamingStatisticsVectorImageFilterType;
+  typedef otb::StreamingMinMaxImageFilter<ImageType>                                          StreamingMinMaxImageFilterType;
+  typedef otb::StreamingStatisticsVectorImageFilter<VectorImageType,PrecisionType>            StreamingStatisticsVectorImageFilterType;
   typedef otb::StreamingStatisticsImageFilter<ImageType>                                      StreamingStatisticsImageFilterType;
   typedef itk::Statistics::MersenneTwisterRandomVariateGenerator                              RandomVariateGeneratorType;
+  typedef otb::PCAImageFilter< VectorImageType, VectorImageType, otb::Transform::FORWARD >    ForwardPCAImageFilterType;
+  typedef otb::PCAImageFilter< VectorImageType, VectorImageType, otb::Transform::INVERSE >    InversePCAImageFilterType;
+  typedef otb::VectorImageToAmplitudeImageFilter< VectorImageType, ImageType >                VectorImageToAmplitudeImageFilterType;
+  typedef otb::ConcatenateScalarValueImageFilter< VectorImageType, VectorImageType >          ConcatenateScalarValueImageFilterType;
 
   // creation of SmartPointer
   itkNewMacro(Self);
diff --git a/Code/Hyperspectral/otbVcaImageFilter.txx b/Code/Hyperspectral/otbVcaImageFilter.txx
index 1e99e1755062d32604f53ca2902f2ba7c88c532c..f639c21474bbebea8076442bb841a8287b47fc90 100644
--- a/Code/Hyperspectral/otbVcaImageFilter.txx
+++ b/Code/Hyperspectral/otbVcaImageFilter.txx
@@ -21,11 +21,14 @@
 #ifndef __otbVCAImageFilter_txx
 #define __otbVCAImageFilter_txx
 
-#define otbMsgDevMacroVCA(p) std::cout << p << std::endl;
 
 #include "otbVcaImageFilter.h"
 #include "otbStandardWriterWatcher.h"
 
+
+#define otbMsgDevMacroVCA(p) std::cout << p << std::endl;
+//#define otbMsgDevMacroVCA(p) ;
+
 namespace otb {
 
 template<class TImage>
@@ -75,7 +78,8 @@ void VCAImageFilter<TImage>::GenerateData()
   VectorImageType* input = const_cast<VectorImageType*>(this->GetInput());
   const unsigned int nbBands = this->GetInput()->GetNumberOfComponentsPerPixel();
 
-  otbMsgDevMacroVCA( "Computing image stats" );
+
+  otbMsgDevMacroVCA( "Computing image stats" )
   typename StreamingStatisticsVectorImageFilterType::Pointer statsInput =
       StreamingStatisticsVectorImageFilterType::New();
 
@@ -84,7 +88,8 @@ void VCAImageFilter<TImage>::GenerateData()
   statsInput->SetEnableMinMax(false);
   statsInput->Update();
 
-  otbMsgDevMacroVCA( "Computing SVD of correlation matrix" );
+/*
+//  otbMsgDevMacroVCA( "Computing SVD of correlation matrix" );
   // Take the correlation matrix
   vnl_matrix<PrecisionType> R = statsInput->GetCorrelation().GetVnlMatrix();
 
@@ -93,16 +98,131 @@ void VCAImageFilter<TImage>::GenerateData()
   vnl_matrix<PrecisionType> U = svd.U();
   vnl_matrix<PrecisionType> Ud = U.get_n_columns(0, m_NumberOfEndmembers);
   vnl_matrix<PrecisionType> UdT = Ud.transpose();
+*/
+  vnl_matrix<PrecisionType> Ud;
+
+  // TODO : temporary hack. implement SNR estimation formula here
+  double SNR = 40;
+  double SNRth = 30;
 
+  typename VectorImageType::Pointer Xd;
+  typename VectorImageType::Pointer Y;
+
+  std::vector<itk::ProcessObject::Pointer> refHolder;
+  typename ForwardPCAImageFilterType::Pointer pca = ForwardPCAImageFilterType::New();
+  typedef typename ForwardPCAImageFilterType::NormalizeFilterType NormalizeFilterType;
+  typename NormalizeFilterType::Pointer normalize = NormalizeFilterType::New();
+
+  if (SNR > SNRth)
+    {
+    otbMsgDevMacroVCA( "Using projective projection for dimensionnality reduction" )
+
+    otbMsgDevMacroVCA( "Computing SVD of correlation matrix" )
+    // Take the correlation matrix
+    vnl_matrix<PrecisionType> R = statsInput->GetCorrelation().GetVnlMatrix();
+
+    // Apply SVD
+    vnl_svd<PrecisionType> svd(R);
+    vnl_matrix<PrecisionType> U = svd.U();
+    Ud = U.get_n_columns(0, m_NumberOfEndmembers);
+    vnl_matrix<PrecisionType> UdT = Ud.transpose();
+
+    otbMsgDevMacroVCA( "Apply dimensionality reduction" )
+    // Xd = Ud.'*M;
+    typename MatrixMultiplyImageFilterType::Pointer mulUd = MatrixMultiplyImageFilterType::New();
+    mulUd->SetInput(this->GetInput());
+    mulUd->SetMatrix(UdT);
+    mulUd->UpdateOutputInformation();
+    refHolder.push_back(mulUd.GetPointer());
+
+    Xd = mulUd->GetOutput();
+
+    // Compute mean(Xd)
+    otbMsgDevMacroVCA( "Compute mean(Xd)" )
+    typename StreamingStatisticsVectorImageFilterType::Pointer
+        statsXd = StreamingStatisticsVectorImageFilterType::New();
+    statsXd->SetEnableSecondOrderStats(false);
+    statsXd->SetInput(Xd);
+    // statsXd->GetStreamer()->SetNumberOfDivisionsStrippedStreaming(10);
+    statsXd->Update();
+    typename VectorImageType::PixelType Xdmean = statsXd->GetMean();
+    otbMsgDevMacroVCA( "mean(Xd) = " << Xdmean)
+
+    // Projective projection
+    // Xd ./ repmat( sum( Xd .* repmat(u,[1 N]) ) ,[d 1]);
+    otbMsgDevMacroVCA( "Compute projective projection" )
+    typename ProjectiveProjectionImageFilterType::Pointer proj = ProjectiveProjectionImageFilterType::New();
+    proj->SetInput(Xd);
+    proj->SetProjectionDirection(Xdmean);
+    refHolder.push_back(proj.GetPointer());
+
+    Xd = proj->GetOutput();
+    Y = Xd;
+
+    }
+  else
+    {
+    otbMsgDevMacroVCA( "Using PCA for dimensionnality reduction" )
+
+    normalize->SetInput(input);
+    normalize->SetMean(statsInput->GetMean());
+    normalize->SetUseMean(true);
+    normalize->SetUseStdDev(false);
+
+    // Take the correlation matrix
+    vnl_matrix<PrecisionType> R = statsInput->GetCovariance().GetVnlMatrix();
+
+    // Apply SVD
+    vnl_svd<PrecisionType> svd(R);
+    vnl_matrix<PrecisionType> U = svd.U();
+    Ud = U.get_n_columns(0, m_NumberOfEndmembers - 1);
+    vnl_matrix<PrecisionType> UdT = Ud.transpose();
+
+    typename MatrixMultiplyImageFilterType::Pointer mulUd = MatrixMultiplyImageFilterType::New();
+    mulUd->SetInput(normalize->GetOutput());
+    mulUd->SetMatrix(UdT);
+    mulUd->UpdateOutputInformation();
+    refHolder.push_back(mulUd.GetPointer());
+
+    Xd = mulUd->GetOutput();
+
+    typename VectorImageToAmplitudeImageFilterType::Pointer normComputer = VectorImageToAmplitudeImageFilterType::New();
+    normComputer->SetInput(Xd);
+
+    typename StreamingMinMaxImageFilterType::Pointer maxNormComputer = StreamingMinMaxImageFilterType::New();
+    maxNormComputer->SetInput(normComputer->GetOutput());
+    maxNormComputer->Update();
+    typename ImageType::PixelType maxNorm = maxNormComputer->GetMaximum();
+
+    typename ConcatenateScalarValueImageFilterType::Pointer concat = ConcatenateScalarValueImageFilterType::New();
+    concat->SetInput(Xd);
+    concat->SetScalarValue(maxNorm);
+    refHolder.push_back(concat.GetPointer());
+
+    Y = concat->GetOutput();
+    Y->UpdateOutputInformation();
+
+    /*
+     pca->SetInput(normalize->GetOutput());
+     pca->SetNumberOfPrincipalComponentsRequired( m_NumberOfEndmembers - 1 );
+     pca->SetCovarianceMatrix(statsInput->GetCovariance());
+     //    refHolder.push_back(pca.GetPointer());
+     //    pca->GetTransformationMatrix() is not up to date at this point...
+     //    Ud = pca->GetTransformationMatrix().GetVnlMatrix().transpose();
+     Xd = pca->GetOutput();
+     */
+
+    }
+/*
   otbMsgDevMacroVCA( "Apply dimensionality reduction" );
   // Xd = Ud.'*M;
   typename MatrixMultiplyImageFilterType::Pointer mulUd = MatrixMultiplyImageFilterType::New();
   mulUd->SetInput(this->GetInput());
   mulUd->SetMatrix(UdT);
   mulUd->UpdateOutputInformation();
-
   typename VectorImageType::Pointer Xd = mulUd->GetOutput();
 
+
   // Compute mean(Xd)
   otbMsgDevMacroVCA( "Compute mean(Xd)" );
   typename StreamingStatisticsVectorImageFilterType::Pointer statsXd = \
@@ -110,7 +230,7 @@ void VCAImageFilter<TImage>::GenerateData()
   statsXd->SetEnableMinMax(false);
   statsXd->SetEnableSecondOrderStats(false);
   statsXd->SetInput(Xd);
-//  statsXd->GetStreamer()->SetBufferNumberOfLinesDivisions(10);
+//  statsXd->GetStreamer()->SetNumberOfDivisionsStrippedStreaming(10);
   statsXd->Update();
   typename VectorImageType::PixelType Xdmean = statsXd->GetMean();
 
@@ -121,7 +241,7 @@ void VCAImageFilter<TImage>::GenerateData()
   proj->SetInput(Xd);
   proj->SetProjectionDirection(Xdmean);
   typename  VectorImageType::Pointer Y = proj->GetOutput();
-
+*/
   // E : result, will contain the endmembers
   vnl_matrix<PrecisionType> E(nbBands, m_NumberOfEndmembers);
 
@@ -134,21 +254,22 @@ void VCAImageFilter<TImage>::GenerateData()
 
   for (unsigned int i = 0; i < m_NumberOfEndmembers; ++i)
     {
-    otbMsgDevMacroVCA( "Iteration " << i );
+    otbMsgDevMacroVCA( "----------------------------------------" )
+    otbMsgDevMacroVCA( "Iteration " << i )
 
     // w = rand(q,1)
-    otbMsgDevMacroVCA( "Random vector generation " );
+    otbMsgDevMacroVCA( "Random vector generation " )
     vnl_vector<PrecisionType> w(m_NumberOfEndmembers);
-    for (unsigned int j = 0; j < m_NumberOfEndmembers; ++j)
+    for (unsigned int j = 0; j < w.size(); ++j)
       {
       w(j) = randomGen->GetVariateWithOpenRange();
       }
 
     // f = ((I - A*pinv(A))*w) / (norm(I - A*pinv(A))*w))
-    otbMsgDevMacroVCA( "f = ((I - A*pinv(A))*w) /(norm(I - A*pinv(A))*w))" );
-    vnl_matrix<PrecisionType> tmpMat(m_NumberOfEndmembers,m_NumberOfEndmembers);
+    otbMsgDevMacroVCA( "f = ((I - A*pinv(A))*w) /(norm(I - A*pinv(A))*w))" )
+    vnl_matrix<PrecisionType> tmpMat(m_NumberOfEndmembers, m_NumberOfEndmembers);
     tmpMat.set_identity();
-    otbMsgDevMacroVCA( "A" << std::endl << A );
+    otbMsgDevMacroVCA( "A" << std::endl << A )
     vnl_svd<PrecisionType> Asvd(A);
     tmpMat -= A * Asvd.inverse();
 
@@ -156,9 +277,11 @@ void VCAImageFilter<TImage>::GenerateData()
     vnl_vector<PrecisionType> f = tmpNumerator / tmpNumerator.two_norm();
 
     // v = f.'*Y
+    otbMsgDevMacroVCA( "f = " << f );
     otbMsgDevMacroVCA( "v = f.'*Y" );
     typename DotProductImageFilterType::Pointer dotfY = DotProductImageFilterType::New();
     dotfY->SetInput(Y);
+
     typename VectorImageType::PixelType fV(f.data_block(), f.size());
     dotfY->SetVector(typename VectorImageType::PixelType(fV));
     typename ImageType::Pointer v = dotfY->GetOutput();
@@ -172,17 +295,17 @@ void VCAImageFilter<TImage>::GenerateData()
     otbMsgDevMacroVCA( "max(abs(v))" );
     typename StreamingMinMaxImageFilterType::Pointer maxAbs = StreamingMinMaxImageFilterType::New();
     maxAbs->SetInput(absVFilter->GetOutput());
-//    maxAbs->GetStreamer()->SetBufferNumberOfLinesDivisions(10);
+//    maxAbs->GetStreamer()->SetNumberOfDivisionsStrippedStreaming(10);
     maxAbs->Update();
 
     // k = arg_max( max(abs(v)) )
-    otbMsgDevMacroVCA( "k = arg_max( max(abs(v)) )" );
+    otbMsgDevMacroVCA( "k = arg_max( max(abs(v)) )" )
     IndexType maxIdx = maxAbs->GetMaximumIndex();
-    otbMsgDevMacroVCA( "max : " << maxAbs->GetMaximum()  );
-    otbMsgDevMacroVCA( "maxIdx : " << maxIdx  );
+    otbMsgDevMacroVCA( "max : " << maxAbs->GetMaximum() )
+    otbMsgDevMacroVCA( "maxIdx : " << maxIdx )
 
     // extract Y(:,k)
-    otbMsgDevMacroVCA( "Y(:,k)" );
+    otbMsgDevMacroVCA( "Y(:,k)" )
     RegionType region;
     region.SetIndex( maxIdx );
     SizeType size;
@@ -193,33 +316,49 @@ void VCAImageFilter<TImage>::GenerateData()
 
     // store new endmember in A
     // A(:,i) = Y(:,k)
-    otbMsgDevMacroVCA( "A(:,i) = Y(:,k)" );
+    otbMsgDevMacroVCA( "A(:,i) = Y(:,k)" )
     typename VectorImageType::PixelType e = Y->GetPixel(maxIdx);
     otbMsgDevMacroVCA( "e = " << e )
     A.set_column(i, e.GetDataPointer());
-    otbMsgDevMacroVCA( "A" << std::endl << A );
 
-    // reproject in original space
-    // u = Ud * Xd(:,k)
-    otbMsgDevMacroVCA( "u = Ud * Xd(:,k)" );
-    Xd->SetRequestedRegion(region);
-    Xd->Update();
-    typename VectorImageType::PixelType xd = Xd->GetPixel(maxIdx);
-    vnl_vector<PrecisionType> xdV(xd.GetDataPointer(), xd.GetSize());
-    vnl_vector<PrecisionType> u = Ud * xdV;
+    otbMsgDevMacroVCA( "A" << std::endl << A )
+
+    // reproject new endmember in original space
+    vnl_vector<PrecisionType> u;
+    if (SNR > SNRth)
+      {
+      // u = Ud * Xd(:,k)
+      otbMsgDevMacroVCA( "u = Ud * Xd(:,k)" )
+      Xd->SetRequestedRegion(region);
+      Xd->Update();
+      typename VectorImageType::PixelType xd = Xd->GetPixel(maxIdx);
+      vnl_vector<PrecisionType> xdV(xd.GetDataPointer(), xd.GetSize());
+      u = Ud * xdV;
+      }
+    else
+      {
+      // u = invPCA( Xd(:,k) )
+      otbMsgDevMacroVCA( "u = Ud * Xd(:,k)" )
+      Xd->SetRequestedRegion(region);
+      Xd->Update();
+      typename VectorImageType::PixelType xd = Xd->GetPixel(maxIdx);
+      vnl_vector<PrecisionType> xdV(xd.GetDataPointer(), xd.GetSize());
+      //Ud = pca->GetTransformationMatrix().GetVnlMatrix().transpose();
+
+      vnl_vector<PrecisionType> mean(statsInput->GetMean().GetDataPointer(), statsInput->GetMean().GetSize());
+      u = Ud * xdV + mean;
+      }
 
     // E(:, i) = u
-    otbMsgDevMacroVCA( "E(:, i) = u" );
+    otbMsgDevMacroVCA( "E(:, i) = u" )
     otbMsgDevMacroVCA( "u = " << u )
     E.set_column(i, u);
     }
 
   typename VectorImageType::Pointer output = this->GetOutput();
-  otbMsgDevMacroVCA( "output = " << output )
   output->SetRegions(output->GetLargestPossibleRegion());
   //output->SetNumberOfComponentsPerPixel(input->GetNumberOfComponentsPerPixel());
   output->Allocate();
-  otbMsgDevMacroVCA( "output = " << output )
 
   itk::ImageRegionIteratorWithIndex<VectorImageType> it(output, output->GetLargestPossibleRegion());
   unsigned int i;