diff --git a/Code/DisparityMap/otbDisparityMapToDEMFilter.h b/Code/DisparityMap/otbDisparityMapToDEMFilter.h
index e90afed2626d027d03b80b413ee6cb94f7cd4c90..dda0995d1ce1d6ff53261cf62d885d8cb15718e8 100644
--- a/Code/DisparityMap/otbDisparityMapToDEMFilter.h
+++ b/Code/DisparityMap/otbDisparityMapToDEMFilter.h
@@ -20,10 +20,12 @@
 
 #include "itkImageToImageFilter.h"
 #include "otbGenericRSTransform.h"
+#include "itkImageRegionSplitter.h"
 // #include "itkConstNeighborhoodIterator.h"
 // #include "itkImageRegionConstIterator.h"
 // #include "itkImageRegionIterator.h"
-// #include "otbImage.h"
+#include "otbVectorImage.h"
+#include "otbImage.h"
 
 namespace otb
 {
@@ -33,7 +35,8 @@ namespace otb
  *
  *  This filter uses an input disparity map (horizontal and vertical) to produce a DEM with a regular sampling
  *  in the chosen map projection system. The elevation is computed from the triangulation of the "left-right" pairs
- *  of pixels matched. When several elevations are possible on a DEM cell, the highest is kept.
+ *  of pixels matched. When several elevations are possible on a DEM cell, the highest is kept. Note : disparity maps
+ *  and DEM are expected to be of scalar image type.
  *
  *  The inputs are:
  *    - the horizontal and vertical disparity maps (SetHorizontalDisparityMapInput, SetVerticalDisparityMapInput)
@@ -55,7 +58,7 @@ namespace otb
  *
  */
 template <class TDisparityImage, class TInputImage, class TOutputDEMImage = TDisparityImage,
-          class TEpipolarGridImage = TDisparityImage, class TMaskImage = otb::Image<unsigned char> >
+          class TEpipolarGridImage = otb::VectorImage<float,2> , class TMaskImage = otb::Image<unsigned char> >
 class ITK_EXPORT DisparityMapToDEMFilter :
     public itk::ImageToImageFilter<TDisparityImage,TOutputDEMImage>
 {
@@ -81,6 +84,9 @@ public:
   typedef TMaskImage              MaskImageType;
   
   typedef typename DEMImageType::RegionType         RegionType;
+  typedef typename DEMImageType::PixelType          DEMPixelType;
+  
+  typedef itk::ImageRegionSplitter<2>   SplitterType;
   
   // 3D RS transform
   // TODO: Allow to tune precision (i.e. double or float)
@@ -167,14 +173,17 @@ protected:
   /** Threaded generate data */
   virtual void ThreadedGenerateData(const RegionType & outputRegionForThread, int threadId);
   
+  /** After threaded generate data : sum up temporary DEMs */
+  virtual void AfterThreadedGenerateData();
+  
 private:
   DisparityMapToDEMFilter(const Self&); //purposely not implemented
   void operator=(const Self&); //purposely not implemented
   
-  /** Minimum elevation of the DEM in meters (over the chosen reference : DEM, geoid, average)*/
+  /** Minimum elevation of the DEM in meters */
   double m_ElevationMin;
   
-  /** Maximum elevation of the DEM in meters (over the chosen reference : DEM, geoid, average)*/
+  /** Maximum elevation of the DEM in meters */
   double m_ElevationMax;
   
   /** DEM grid step (in meters) */
@@ -188,6 +197,15 @@ private:
   
   /** Average Elevation */
   double m_AverageElevation;
+  
+  /** Region splitter for input disparity maps */
+  SplitterType::Pointer m_InputSplitter;
+  
+  /** Number of splits used for input multithreading */
+  unsigned int m_UsedInputSplits;
+  
+  /** Temporary DEMs for mutlithreading */
+  std::vector<typename DEMImageType::Pointer> m_TempDEMRegions;
 };
 } // end namespace otb
 
diff --git a/Code/DisparityMap/otbDisparityMapToDEMFilter.txx b/Code/DisparityMap/otbDisparityMapToDEMFilter.txx
index b0cc31feae02e40827ef218a77a31cd2a2768b02..cd2cf031cf5c06a88e5c33c151c93b98d340af0b 100644
--- a/Code/DisparityMap/otbDisparityMapToDEMFilter.txx
+++ b/Code/DisparityMap/otbDisparityMapToDEMFilter.txx
@@ -19,8 +19,8 @@
 #define __otbDisparityMapToDEMFilter_txx
 
 #include "otbDisparityMapToDEMFilter.h"
-#include "itkImageConstIteratorWithIndex.h"
-// #include "itkImageRegionIterator.h"
+#include "itkImageRegionConstIteratorWithIndex.h"
+#include "itkImageRegionIterator.h"
 // #include "itkProgressReporter.h"
 // #include "itkConstantBoundaryCondition.h"
 
@@ -45,9 +45,12 @@ DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGri
   m_ElevationMax = 100.0;
   m_DEMGridStep = 10.0;
   
-  m_AverageElevation = 0;
+  m_AverageElevation = 0.0;
   m_DEMDirectory = "";
   m_GeoidFile = "";
+  
+  m_InputSplitter = SplitterType::New();
+  m_UsedInputSplits = 1;
 }
 
 template <class TDisparityImage, class TInputImage, class TOutputDEMImage,
@@ -254,10 +257,10 @@ DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGri
   const TInputImage * rightImgPtr = this->GetRightInput();
   TOutputDEMImage * outputPtr = this->GetDEMOutput();
   
-  // Setup the DEM handler if needed
-  typename DEMHandler::Pointer demHandler = DEMHandler::New();
+  // // Setup the DEM handler if needed
+  //typename DEMHandler::Pointer demHandler = DEMHandler::New();
   
-  bool useDEM = false;
+  //bool useDEM = false;
   
   // Set-up a transform to use the DEMHandler
   typedef otb::GenericRSTransform<> RSTransform2DType;
@@ -265,30 +268,34 @@ DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGri
   leftToGroundTransform->SetInputKeywordList(leftImgPtr->GetImageKeywordlist());
   if(m_DEMDirectory!="")
     {
-    demHandler->OpenDEMDirectory(m_DEMDirectory);
+    //demHandler->OpenDEMDirectory(m_DEMDirectory);
     leftToGroundTransform->SetDEMDirectory(m_DEMDirectory);
-    useDEM = true;
+    //useDEM = true;
     }
   if(m_GeoidFile!="")
     {
     leftToGroundTransform->SetGeoidFile(m_GeoidFile);
-    demHandler->OpenGeoidFile(m_GeoidFile);
+    //demHandler->OpenGeoidFile(m_GeoidFile);
     }
+  leftToGroundTransform->SetAverageElevation(m_AverageElevation);
+  
   leftToGroundTransform->InstanciateTransform();
   
   RSTransform2DType::Pointer rightToGroundTransform = RSTransform2DType::New();
   rightToGroundTransform->SetInputKeywordList(rightImgPtr->GetImageKeywordlist());
   if(m_DEMDirectory!="")
     {
-    demHandler->OpenDEMDirectory(m_DEMDirectory);
+    //demHandler->OpenDEMDirectory(m_DEMDirectory);
     rightToGroundTransform->SetDEMDirectory(m_DEMDirectory);
-    useDEM = true;
+    //useDEM = true;
     }
   if(m_GeoidFile!="")
     {
     rightToGroundTransform->SetGeoidFile(m_GeoidFile);
-    demHandler->OpenGeoidFile(m_GeoidFile);
+    //demHandler->OpenGeoidFile(m_GeoidFile);
     }
+  rightToGroundTransform->SetAverageElevation(m_AverageElevation);
+  
   rightToGroundTransform->InstanciateTransform();
   
   // left image
@@ -609,7 +616,33 @@ void
 DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage>
 ::BeforeThreadedGenerateData()
 {
-  // TODO
+  const TDisparityImage * horizDisp = this->GetHorizontalDisparityMapInput();
+  
+  const TOutputDEMImage * outputDEM = this->GetDEMOutput();
+  
+  m_UsedInputSplits = m_InputSplitter->GetNumberOfSplits(horizDisp->GetRequestedRegion(), this->GetNumberOfThreads());
+  
+  if (m_UsedInputSplits > 0 && m_UsedInputSplits <= this->GetNumberOfThreads())
+    {
+    m_TempDEMRegions.clear();
+    
+    for (unsigned int i=0;i<m_UsedInputSplits;i++)
+      {
+      typename DEMImageType::Pointer tmpImg = TOutputDEMImage::New();
+      tmpImg->SetNumberOfComponentsPerPixel(1);
+      tmpImg->SetRegions(outputDEM->GetRequestedRegion());
+      tmpImg->Allocate();
+      
+      typename DEMImageType::PixelType minElevation = static_cast<typename DEMImageType::PixelType>(m_ElevationMin);
+      tmpImg->FillBuffer(minElevation);
+      
+      m_TempDEMRegions.push_back(tmpImg);
+      }
+    }
+  else
+    {
+    itkExceptionMacro(<<"Wrong number of splits for input multithreading : "<<m_UsedInputSplits);
+    }
 }
 
 template <class TDisparityImage, class TInputImage, class TOutputDEMImage,
@@ -624,22 +657,31 @@ DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGri
   const TInputImage * leftSensor = this->GetLeftInput();
   const TInputImage * rightSensor = this->GetRightInput();
   
+  const TMaskImage * disparityMask = this->GetDisparityMaskInput();
+  
+  const TOutputDEMImage * outputDEM = this->GetDEMOutput();
+  
   RSTransformType::Pointer leftToGroundTransform = RSTransformType::New();
   RSTransformType::Pointer rightToGroundTransform = RSTransformType::New();
   
   leftToGroundTransform->SetInputKeywordList(leftSensor->GetImageKeywordlist());
   rightToGroundTransform->SetInputKeywordList(rightSensor->GetImageKeywordlist());
   
+  typename DEMHandler::Pointer demHandler = DEMHandler::New();
+  
   if(m_DEMDirectory!="")
     {
     leftToGroundTransform->SetDEMDirectory(m_DEMDirectory);
     rightToGroundTransform->SetDEMDirectory(m_DEMDirectory);
+    demHandler->OpenDEMDirectory(m_DEMDirectory);
     }
   if(m_GeoidFile!="")
     {
     leftToGroundTransform->SetGeoidFile(m_GeoidFile);
     rightToGroundTransform->SetGeoidFile(m_GeoidFile);
+    demHandler->OpenGeoidFile(m_GeoidFile);
     }
+  demHandler->SetDefaultHeightAboveEllipsoid(m_AverageElevation);
     
   leftToGroundTransform->InstanciateTransform();
   rightToGroundTransform->InstanciateTransform();
@@ -647,10 +689,21 @@ DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGri
   const TEpipolarGridImage * leftGrid = this->GetLeftEpipolarGridInput();
   const TEpipolarGridImage * rightGrid = this->GetRightEpipolarGridInput();
   
-  typename TEpipolarGridImage::RegionType gridRegion = leftGrid->GetLargestPossibleRegion();
+  typename TEpipolarGridImage::RegionType gridRegion = leftGrid->GetLargestPossibleRegion(); 
+  
+  TOutputDEMImage * tmpDEM = NULL;
+  typename TOutputDEMImage::RegionType outputRequestedRegion = outputDEM->GetRequestedRegion();
   
-  // TODO : replace by sub region for thread
-  typename TDisparityImage::RegionType disparityRegion = horizDisp->GetRequestedRegion();
+  typename TDisparityImage::RegionType disparityRegion;
+  if (threadId < m_UsedInputSplits)
+    {
+    disparityRegion = m_InputSplitter->GetSplit(threadId,m_UsedInputSplits,horizDisp->GetRequestedRegion());
+    tmpDEM = m_TempDEMRegions[threadId];
+    }
+  else
+    {
+    return;
+    }
   
   itk::ImageRegionConstIteratorWithIndex<DisparityMapType> horizIt(horizDisp,disparityRegion);
   itk::ImageRegionConstIteratorWithIndex<DisparityMapType> vertiIt(vertiDisp,disparityRegion);
@@ -658,6 +711,22 @@ DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGri
   horizIt.GoToBegin();
   vertiIt.GoToBegin();
   
+  bool useMask = false;
+  if (disparityMask)
+    {
+    useMask = true;
+    }
+  else
+    {
+    disparityMask = MaskImageType::New();
+    }
+  
+  itk::ImageRegionConstIterator<MaskImageType> maskIt(disparityMask,disparityRegion);
+  if (useMask)
+    {
+    maskIt.GoToBegin();
+    }
+  
   typename TDisparityImage::PointType epiPoint;
   itk::ContinuousIndex<double,2> gridIndexConti;
   double subPixIndex[2];
@@ -676,7 +745,17 @@ DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGri
   
   while (!horizIt.IsAtEnd() && !vertiIt.IsAtEnd())
     {
-    // TODO : if mask, check value and skip iteration if mask value is not valid
+    // check mask value if any
+    if (useMask)
+      {
+      if (!(maskIt.Get() > 0))
+        {
+        ++horizIt;
+        ++vertiIt;
+        ++maskIt;
+        continue;
+        }
+      }
     
     // compute left ray
     horizDisp->TransformIndexToPhysicalPoint(horizIt.GetIndex(),epiPoint);
@@ -719,6 +798,10 @@ DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGri
     leftGroundHmax = leftToGroundTransform->TransformPoint(sensorPoint);
     
     // compute right ray
+    itk::ContinuousIndex<double,2> rightIndexEstimate;
+    rightIndexEstimate[0] = static_cast<double>((horizIt.GetIndex())[0]) + static_cast<double>(horizIt.Get());
+    rightIndexEstimate[1] = static_cast<double>((horizIt.GetIndex())[1]) + static_cast<double>(vertiIt.Get());
+    horizDisp->TransformContinuousIndexToPhysicalPoint(rightIndexEstimate,epiPoint);
     rightGrid->TransformPhysicalPointToContinuousIndex(epiPoint,gridIndexConti);
     
     ulIndex[0] = static_cast<int>(vcl_floor(gridIndexConti[0]));
@@ -757,19 +840,112 @@ DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGri
     sensorPoint[2] = m_ElevationMax;
     rightGroundHmax = rightToGroundTransform->TransformPoint(sensorPoint);
     
-    // Compute ray intersection
+    // Compute ray intersection (mid-point method), TODO : implement non-iterative method from Hartley & Sturm
+    double a = (leftGroundHmax[0] - leftGroundHmin[0]) * (leftGroundHmax[0] - leftGroundHmin[0]) +
+               (leftGroundHmax[1] - leftGroundHmin[1]) * (leftGroundHmax[1] - leftGroundHmin[1]) +
+               (leftGroundHmax[2] - leftGroundHmin[2]) * (leftGroundHmax[2] - leftGroundHmin[2]);
+    double b = (rightGroundHmax[0] - rightGroundHmin[0]) * (rightGroundHmax[0] - rightGroundHmin[0]) +
+               (rightGroundHmax[1] - rightGroundHmin[1]) * (rightGroundHmax[1] - rightGroundHmin[1]) +
+               (rightGroundHmax[2] - rightGroundHmin[2]) * (rightGroundHmax[2] - rightGroundHmin[2]);
+    double c = -(leftGroundHmax[0] - leftGroundHmin[0]) * (rightGroundHmax[0] - rightGroundHmin[0])
+               -(leftGroundHmax[1] - leftGroundHmin[1]) * (rightGroundHmax[1] - rightGroundHmin[1])
+               -(leftGroundHmax[2] - leftGroundHmin[2]) * (rightGroundHmax[2] - rightGroundHmin[2]);
+    double g = (leftGroundHmax[0] - leftGroundHmin[0]) * (rightGroundHmin[0] - leftGroundHmin[0]) +
+               (leftGroundHmax[1] - leftGroundHmin[1]) * (rightGroundHmin[1] - leftGroundHmin[1]) +
+               (leftGroundHmax[2] - leftGroundHmin[2]) * (rightGroundHmin[2] - leftGroundHmin[2]);
+    double h = -(rightGroundHmax[0] - rightGroundHmin[0]) * (rightGroundHmin[0] - leftGroundHmin[0])
+               -(rightGroundHmax[1] - rightGroundHmin[1]) * (rightGroundHmin[1] - leftGroundHmin[1])
+               -(rightGroundHmax[2] - rightGroundHmin[2]) * (rightGroundHmin[2] - leftGroundHmin[2]);
+    
+    double rLeft = (b * g - c * h) / (a * b - c * c);
+    double rRight = (a * h - c * g) / (a * b - c * c);
+    
+    TDPointType leftFoot;
+    leftFoot.SetToBarycentricCombination(leftGroundHmax,leftGroundHmin,rLeft );
     
-    // Optimise position ?
+    TDPointType rightFoot;
+    rightFoot.SetToBarycentricCombination(rightGroundHmax,rightGroundHmin,rRight);
+    
+    TDPointType midPoint3D;
+    midPoint3D.SetToMidPoint(leftFoot,rightFoot);
     
     // Is point inside DEM area ?
+    typename DEMImageType::PointType midPoint2D;
+    midPoint2D[0] = midPoint3D[0];
+    midPoint2D[1] = midPoint3D[1];
+    itk::ContinuousIndex<double,2> midIndex;
+    outputDEM->TransformPhysicalPointToContinuousIndex(midPoint2D,midIndex);
+    typename DEMImageType::IndexType cellIndex;
+    cellIndex[0] = static_cast<int>(vcl_floor(midIndex[0] + 0.5));
+    cellIndex[1] = static_cast<int>(vcl_floor(midIndex[1] + 0.5));
     
-    // Add point to its corresponding cell (keep maximum)
+    if (outputRequestedRegion.IsInside(cellIndex))
+      {
+      // Estimate local reference elevation (average, DEM or geoid)
+      double localElevation = demHandler->GetHeightAboveEllipsoid(midPoint2D);
+      
+      // Add point to its corresponding cell (keep maximum)
+      DEMPixelType cellHeight = static_cast<DEMPixelType>(midPoint3D[2] + localElevation);
+      if (cellHeight > tmpDEM->GetPixel(cellIndex) && cellHeight < static_cast<DEMPixelType>(m_ElevationMax))
+        {
+        tmpDEM->SetPixel(cellIndex,cellHeight);
+        }
+      }
     
     ++horizIt;
     ++vertiIt;
+    
+    if (useMask) ++maskIt;
+    
+    }
+}
+
+template <class TDisparityImage, class TInputImage, class TOutputDEMImage,
+class TEpipolarGridImage, class TMaskImage>
+void
+DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage>
+::AfterThreadedGenerateData()
+{
+  TOutputDEMImage * outputDEM = this->GetDEMOutput();
+  
+  if (m_TempDEMRegions.size() < 1)
+    {
+    outputDEM->FillBuffer(m_ElevationMin);
+    return;
+    }
+  
+  itk::ImageRegionIterator<DEMImageType> outputDEMIt(outputDEM,outputDEM->GetRequestedRegion());
+  itk::ImageRegionIterator<DEMImageType> firstDEMIt(m_TempDEMRegions[0],outputDEM->GetRequestedRegion());
+  
+  outputDEMIt.GoToBegin();
+  firstDEMIt.GoToBegin();
+  
+  // Copy first DEM
+  while (!outputDEMIt.IsAtEnd() && !firstDEMIt.IsAtEnd())
+    {
+    outputDEMIt.Set(firstDEMIt.Get());
+    ++outputDEMIt;
+    ++firstDEMIt;
     }
   
-  // TODO
+  // Check DEMs from other threads and keep the maximum elevation
+  for (unsigned int i=1;i<m_TempDEMRegions.size();i++)
+    {
+    itk::ImageRegionIterator<DEMImageType> tmpDEMIt(m_TempDEMRegions[i],outputDEM->GetRequestedRegion());
+    
+    outputDEMIt.GoToBegin();
+    tmpDEMIt.GoToBegin();
+    
+    while (!outputDEMIt.IsAtEnd() && !tmpDEMIt.IsAtEnd())
+      {
+      if (tmpDEMIt.Get() > outputDEMIt.Get())
+        {
+        outputDEMIt.Set(tmpDEMIt.Get());
+        }
+      ++outputDEMIt;
+      ++tmpDEMIt;
+      }
+    }
 }
 
 }