diff --git a/Application/CMakeLists.txt b/Application/CMakeLists.txt
index 7d3117c16683e7bc28e99b408e022834e33746f6..0ae28d26fe4b492b3fd3fb097630a50c1befb728 100644
--- a/Application/CMakeLists.txt
+++ b/Application/CMakeLists.txt
@@ -1,3 +1,32 @@
 
 ADD_EXECUTABLE(otbAvirisBandSelection otbAvirisBandSelection.cxx)
 TARGET_LINK_LIBRARIES(otbAvirisBandSelection OTBCommon OTBIO OTBBasicFilters )
+
+ADD_EXECUTABLE(otbHyperspectralUnmixing otbHyperspectralUnmixing.cxx)
+TARGET_LINK_LIBRARIES(otbHyperspectralUnmixing OTBCommon OTBIO OTBBasicFilters )
+
+
+
+
+SET(TESTEXE_DIR ${Hyperspectral_BINARY_DIR}/bin)
+SET(TEMP ${Hyperspectral_BINARY_DIR}/Testing/Temporary)
+SET(DATA ${Hyperspectral_SOURCE_DIR}/Data)
+
+#  parser->AddInputImage(); 
+#  parser->AddOption( "--DimReduceMethod", "Dimensionnality reduction method (NONE,PCA,MCF)", "-dr", 1, false );
+#  parser->AddOption( "--NumEndmembers", "Number of endmembers (if not given or 0, will be estimated with DimensionalityEstimationMethod)", "-ne", 1, false );
+#  parser->AddOption( "--DimensionalityEstimationMethod", "Dimensionality estimation method (ELM)", "-de", 1, false );
+#  parser->AddOption( "--EndmembersEstimationMethod", "Endmembers estimation method (VCA)", "-ee", 1, false );
+#  parser->AddOption( "--InputEndmembers", "Input endmembers image (must have NumComponents components or fit the input image nb of components)", "-ie", 1, false );
+#  parser->AddOption( "--UnmixingAlgorithm", "Unmixing algorithm (NONE, UCLS, ISRA)", "-ua", 1, false );
+#  parser->AddOption( "--OutputEndmembers", "Output estimated endmembers image", "-oe", 1, false );
+#  parser->AddOutputImage();
+
+ADD_TEST(hyTvUnmixApplication
+         ${TESTEXE_DIR}/otbHyperspectralUnmixing
+         otbHyperspectralUnmixing
+         -in ${DATA}/AVIRIS/extract128/extract128_goodbands.hdr
+         
+         8)
+
+         
\ No newline at end of file
diff --git a/Application/otbHyperspectralUnmixing.cxx b/Application/otbHyperspectralUnmixing.cxx
index 9168b17500af2b7751c5c873ed2e7fe5e40d0c31..7e43add3a27bd3d6dd872b4d83f1525e696ac38f 100644
--- a/Application/otbHyperspectralUnmixing.cxx
+++ b/Application/otbHyperspectralUnmixing.cxx
@@ -27,6 +27,8 @@
 #include "otbVcaImageFilter.h"
 #include "otbUnConstrainedLeastSquareImageFilter.h"
 #include "otbISRAUnmixingImageFilter.h"
+#include "otbUnConstrainedLeastSquareImageFilter.h"
+#include "otbVectorImageToMatrixImageFilter.h"
 
 const unsigned int Dimension = 2;
 typedef float PixelType;
@@ -36,25 +38,51 @@ typedef otb::VectorImage<PixelType, Dimension> VectorImageType;
 typedef otb::ImageFileReader<VectorImageType> ReaderType;
 typedef otb::StreamingImageFileWriter<VectorImageType> WriterType;
 
-typedef otb::StreamingStatisticsVectorImageFilter2<VectorImageType> StreamingStatisticsVectorImageFilterType;
+typedef otb::StreamingStatisticsVectorImageFilter2<VectorImageType, PixelType> StreamingStatisticsVectorImageFilterType;
 typedef otb::EigenvalueLikelihoodMaximisation<PixelType> ELMType;
 typedef otb::VCAImageFilter<VectorImageType> VCAFilterType;
 
-typedef enum DimReduction
+typedef otb::UnConstrainedLeastSquareImageFilter<VectorImageType,VectorImageType,PixelType> UCLSUnmixingFilterType;
+typedef otb::ISRAUnmixingImageFilter<VectorImageType,VectorImageType,PixelType>             ISRAUnmixingFilterType;
+
+typedef otb::VectorImageToMatrixImageFilter<VectorImageType> VectorImageToMatrixImageFilterType;
+
+typedef vnl_vector<PixelType> VectorType;
+typedef vnl_matrix<PixelType> MatrixType;
+
+
+
+enum DimReductionMethod
+{
+  DimReductionMethod_NONE,
+  DimReductionMethod_PCA,
+  DimReductionMethod_MNF
+};
+
+enum DimensionalityEstimationMethod
+{
+  DimensionalityEstimationMethod_ELM
+};
+
+enum EndmembersEstimationMethod
 {
-  DimReduction_NONE,
-  DimReduction_PCA,
-  DimReduction_MNF
+  EndmembersEstimationMethod_VCA
 };
 
-typedef enum UnMixingAlgo
+enum UnMixingMethod
 {
-  UnMixingAlgo_UCLS,
-  UnMixingAlgo_ISRA,
+  UnMixingMethod_NONE,
+  UnMixingMethod_UCLS,
+  UnMixingMethod_ISRA
 };
 
 int main(int argc, char * argv[])
 {
+  /*
+   *
+   * DEFINE APPLICATION
+   *
+   */
   typedef otb::CommandLineArgumentParser ParserType;
   ParserType::Pointer parser = ParserType::New();
 
@@ -65,17 +93,15 @@ int main(int argc, char * argv[])
   parser->AddOption( "--DimensionalityEstimationMethod", "Dimensionality estimation method (ELM)", "-de", 1, false );
   parser->AddOption( "--EndmembersEstimationMethod", "Endmembers estimation method (VCA)", "-ee", 1, false );
   parser->AddOption( "--InputEndmembers", "Input endmembers image (must have NumComponents components or fit the input image nb of components)", "-ie", 1, false );
-  parser->AddOption( "--UnmixingAlgorithm", "Unmixing algorithm (UCLS, ISRA)", "-ua", 1, false );
+  parser->AddOption( "--UnmixingAlgorithm", "Unmixing algorithm (NONE, UCLS, ISRA)", "-ua", 1, false );
   parser->AddOption( "--OutputEndmembers", "Output estimated endmembers image", "-oe", 1, false );
   parser->AddOutputImage();
 
-
   /*
    *
    * EXTRACT PARAMETERS
    *
    */
-
   typedef otb::CommandLineArgumentParseResult ParserResultType;
   ParserResultType::Pointer  parseResult = ParserResultType::New();
 
@@ -85,7 +111,6 @@ int main(int argc, char * argv[])
   }
   catch( itk::ExceptionObject & err )
   {
-    //std::cerr << argv[0] << " applies MNF transformations\n";
     std::string descriptionException = err.GetDescription();
     if ( descriptionException.find("ParseCommandLine(): Help Parser")
         != std::string::npos )
@@ -99,23 +124,22 @@ int main(int argc, char * argv[])
   const char * inputImageName = parseResult->GetInputImage().c_str();
   const char * outputImageName = parseResult->GetOutputImage().c_str();
 
-  DimReduction dimReduction = DimReduction_NONE;
+  DimReductionMethod dimReduction = DimReductionMethod_NONE;
   if ( parseResult->IsOptionPresent("--DimReduceMethod") )
     {
     std::string dimReductionStr = parseResult->GetParameterString("--DimReduceMethod");
-    if ( boost::to_upper(dimReductionStr) == "PCA" )
+    if ( boost::to_upper_copy(dimReductionStr) == "PCA" )
       {
-      dimReduction = DimReduction_PCA;
+      dimReduction = DimReductionMethod_PCA;
       }
-    else if ( boost::to_upper(dimReductionStr) == "MNF" )
+    else if ( boost::to_upper_copy(dimReductionStr) == "MNF" )
       {
-      dimReduction = DimReduction_MNF;
+      dimReduction = DimReductionMethod_MNF;
       }
     }
-  otbMsgDevMacro(<< "Using "
-                 << (dimReduction == DimReduction_NONE ? "NONE" : (dimReduction == DimReduction_PCA ? : "PCA" : DimReduction_MNF) )
-                 << " dimensionality reduction method"
-                 );
+  otbMsgDevMacro( << "Using "
+                  << (dimReduction == DimReductionMethod_NONE ? "NONE" : (dimReduction == DimReductionMethod_PCA ? : "PCA" : "MNF") )
+                  << " dimensionality reduction method" );
 
   unsigned int nbEndmembers = 0;
   if ( parseResult->IsOptionPresent("--NumEndmembers") )
@@ -126,7 +150,7 @@ int main(int argc, char * argv[])
   if ( parseResult->IsOptionPresent("--DimensionalityEstimationMethod") )
     {
     std::string dimEstMethodStr = parseResult->GetParameterString("--DimensionalityEstimationMethod");
-    if (boost::to_upper(dimEstMethodStr) != "ELM")
+    if (boost::to_upper_copy(dimEstMethodStr) != "ELM")
       {
       std::cerr << "Only ELM is supported for parameter DimensionalityEstimationMethod" << std::endl;
       return EXIT_FAILURE;
@@ -136,7 +160,7 @@ int main(int argc, char * argv[])
   if ( parseResult->IsOptionPresent("--EndmembersEstimationMethod") )
     {
     std::string eeEstMethodStr = parseResult->GetParameterString("--EndmembersEstimationMethod");
-    if (boost::to_upper(eeEstMethodStr) != "VCA")
+    if (boost::to_upper_copy(eeEstMethodStr) != "VCA")
       {
       std::cerr << "Only VCA is supported for parameter EndmembersEstimationMethod" << std::endl;
       return EXIT_FAILURE;
@@ -146,23 +170,22 @@ int main(int argc, char * argv[])
   const char * inputEndmembers = parseResult->IsOptionPresent("--InputEndmembers") ?
     parseResult->GetParameterString("--InputEndmembers").c_str() : NULL;
 
-  UnMixingAlgo unmixingAlgo = UnMixingAlgo_UCLS;
-  if ( parseResult->IsOptionPresent("--DimReduceMethod") )
+  UnMixingMethod unmixingAlgo = UnMixingMethod_NONE;
+  if ( parseResult->IsOptionPresent("--UnmixingAlgorithm") )
     {
-    std::string unmixingAlgoStr = parseResult->GetParameterString("--DimReduceMethod");
-    if ( boost::to_upper(unmixingAlgoStr) == "UCLS" )
+    std::string unmixingAlgoStr = parseResult->GetParameterString("--UnmixingAlgorithm");
+    if ( boost::to_upper_copy(unmixingAlgoStr) == "UCLS" )
       {
-      unmixingAlgo = UnMixingAlgo_UCLS;
+      unmixingAlgo = UnMixingMethod_UCLS;
       }
-    else if ( boost::to_upper(unmixingAlgoStr) == "ISRA" )
+    else if ( boost::to_upper_copy(unmixingAlgoStr) == "ISRA" )
       {
-      unmixingAlgo = UnMixingAlgo_ISRA;
+      unmixingAlgo = UnMixingMethod_ISRA;
       }
     }
-  otbMsgDevMacro(<< "Using "
-                 << (unmixingAlgo == UnMixingAlgo_UCLS ? "UCLS" : "ISRA" )
-                 << " unmixing algorithm"
-                 );
+  otbMsgDevMacro( << "Using "
+                  << (unmixingAlgo == UnMixingMethod_NONE ? "NONE" : (unmixingAlgo == UnMixingMethod_UCLS ? : "UCLS" : "ISRA") )
+                  << " unmixing algorithm" );
 
   const char * outputEndmembers = parseResult->IsOptionPresent("--OutputEndmembers") ?
     parseResult->GetParameterString("--OutputEndmembers").c_str() : NULL;
@@ -178,10 +201,27 @@ int main(int argc, char * argv[])
    *
    */
 
+  ReaderType::Pointer readerImage = ReaderType::New();
+  readerImage->SetFileName(inputImageName);
+
+  VectorImageType::Pointer inputImage = readerImage->GetOutput();
 
   /*
    * Compute stats of input image, we will need this all along the road
    */
+  std::cout << "Computing stats" << std::endl;
+
+  StreamingStatisticsVectorImageFilterType::Pointer stats = StreamingStatisticsVectorImageFilterType::New();
+
+  stats->SetInput(inputImage);
+  stats->Update();
+
+  VectorType mean (stats->GetMean().GetDataPointer(), stats->GetMean().GetSize());
+  MatrixType covariance  = stats->GetCovariance().GetVnlMatrix();
+  MatrixType correlation = stats->GetCorrelation().GetVnlMatrix();
+
+  VectorImageType::Pointer endmembersImage;
+  itk::ProcessObject::Pointer endmembersRef;
 
   if ( inputEndmembers == NULL )
     {
@@ -190,49 +230,119 @@ int main(int argc, char * argv[])
       /*
        * Estimate Endmembers Numbers
        */
+      std::cout << "Estimate Endmembers Numbers by ELM" << std::endl;
+
+      ELMType::Pointer elm = ELMType::New();
+      elm->SetCovariance(covariance);
+      elm->SetCorrelation(correlation);
+      elm->SetNumberOfPixels(inputImage->GetLargestPossibleRegion().GetNumberOfPixels());
+      elm->Compute();
+
+      nbEndmembers = elm->GetNumberOfEndmembers();
 
+      std::cout << "ELM : " << nbEndmembers << " estimated endmembers" << std::endl;
       }
 
     /*
      * Estimate Endmembers
      */
+    std::cout << "Estimate Endmembers by VCA" << std::endl;
 
+    VCAFilterType::Pointer vca = VCAFilterType::New();
+    vca->SetNumberOfEndmembers(nbEndmembers);
+    vca->SetInput(inputImage);
+
+    endmembersImage = vca->GetOutput();
+    endmembersRef = vca;
     }
   else
     {
     /*
      * Read input endmembers
      */
+    std::cout << "Read Endmembers " << inputEndmembers << std::endl;
 
+    ReaderType::Pointer readerEndmembers = ReaderType::New();
+    readerEndmembers->SetFileName(inputEndmembers);
+    endmembersImage = readerEndmembers->GetOutput();
 
+    endmembersRef = readerEndmembers;
     }
 
-
   /*
-   * Unmix
+   * Transform Endmembers image to matrix representation
    */
+  VectorImageToMatrixImageFilterType::Pointer endMember2Matrix = VectorImageToMatrixImageFilterType::New();
+  endMember2Matrix->SetInput(endmembersImage);
+  endMember2Matrix->Update();
 
+  MatrixType endMembersMatrix = endMember2Matrix->GetMatrix();
 
   /*
-   * Write abundance map
+   * Unmix
    */
-  WriterType::Pointer writer = WriterType::New();
-  writer->SetFileName(outputImageName);
-  //writer->SetInput(scale->GetOutput());
-  writer->Update();
+  VectorImageType::Pointer abundanceMap;
+  itk::ProcessObject::Pointer unmixerRef;
+
+  switch (unmixingAlgo)
+  {
+  case UnMixingMethod_NONE:
+    break;
+  case UnMixingMethod_UCLS:
+    {
+    std::cout << "UCLS Unmixing" << std::endl;
+
+    UCLSUnmixingFilterType::Pointer unmixer =
+        UCLSUnmixingFilterType::New();
 
+    unmixer->SetInput(readerImage->GetOutput());
+    unmixer->SetMatrix(endMembersMatrix);
+    unmixer->SetNumberOfThreads(1); // FIXME : currently buggy
+
+    unmixerRef = unmixer;
+    abundanceMap = unmixer->GetOutput();
+    }
+    break;
+  case UnMixingMethod_ISRA:
+    {
+    std::cout << "ISRA Unmixing" << std::endl;
+
+    ISRAUnmixingFilterType::Pointer unmixer =
+        ISRAUnmixingFilterType::New();
+
+    unmixer->SetInput(readerImage->GetOutput());
+    unmixer->SetEndmembersMatrix(endMembersMatrix);
+    unmixerRef = unmixer;
+    abundanceMap = unmixer->GetOutput();
+    }
+    break;
+  default:
+    break;
+  }
 
   if ( outputEndmembers != NULL )
     {
     /*
      * Write endmembers
      */
+    std::cout << "Write endmembers " << outputEndmembers << std::endl;
     WriterType::Pointer endmembersWriter = WriterType::New();
     endmembersWriter->SetFileName(outputEndmembers);
-    //endmembersWriter->SetInput(scale->GetOutput());
+    endmembersWriter->SetInput(endmembersImage);
     endmembersWriter->Update();
     }
 
+  if ( unmixingAlgo != UnMixingMethod_NONE )
+    {
+    /*
+     * Write abundance map
+     */
+    std::cout << "Write abundance map" << outputImageName << std::endl;
+    WriterType::Pointer writer = WriterType::New();
+    writer->SetFileName(outputImageName);
+    writer->SetInput(abundanceMap);
+    writer->Update();
+    }
 
   return EXIT_SUCCESS;
 }