diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d84e78d4f4fe852336269ef1821f7b2ce529d38d..29de07cd84970214b33910a4809f0b144633ebda 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -8,7 +8,17 @@ maven:
   stage: build
   when: always
   script:
-   - mvn clean install -DskipTests
+   - mvn clean install
   artifacts:
     paths:
       - target/*.jar
+
+paramaterSweep:
+  image: maven:3.6.3-jdk-11
+  stage: test
+  when: manual
+  script:
+    - mvn -Dtest=PipelineTest test
+  artifacts:
+    paths:
+    - target/*.csv
\ No newline at end of file
diff --git a/doc/fakeHeightMap.tif b/doc/fakeHeightMap.tif
new file mode 100644
index 0000000000000000000000000000000000000000..33abd675186f4878a814da63ee812c3141326028
Binary files /dev/null and b/doc/fakeHeightMap.tif differ
diff --git a/doc/surf_phantom2_voronoiMesh.tif b/doc/surf_phantom2_voronoiMesh.tif
new file mode 100644
index 0000000000000000000000000000000000000000..cf6389950725a55ccf916daf472c3e29bf96cbac
Binary files /dev/null and b/doc/surf_phantom2_voronoiMesh.tif differ
diff --git a/doc/surf_phantom2_voronoiMesh_HM.tif b/doc/surf_phantom2_voronoiMesh_HM.tif
new file mode 100644
index 0000000000000000000000000000000000000000..1251acca76ba4004309afdfe860ee245afbfeac5
Binary files /dev/null and b/doc/surf_phantom2_voronoiMesh_HM.tif differ
diff --git a/pom.xml b/pom.xml
index 37d3376a897d343ab3d61f90e8a9ed9e524cb111..dfe4113b216ddd32fb1aee9059c5b3941fcbe444 100644
--- a/pom.xml
+++ b/pom.xml
@@ -60,6 +60,19 @@
                     <release>11</release>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>3.0.0-M5</version>
+                <configuration>
+                    <includes>
+                        <include>*Test.java</include>
+                    </includes>
+                    <excludes>
+                        <exclude>**/behavior/*</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
 
         </plugins>
     </build>
@@ -139,16 +152,67 @@
             <groupId>io.scif</groupId>
             <artifactId>scifio</artifactId>
         </dependency>
+
+
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>1.2.3</version>
+        </dependency>
+
+
         <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter-api</artifactId>
-            <version>5.6.2</version>
+            <version>5.7.0</version>
         </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-params</artifactId>
+            <version>5.7.0</version>
+        </dependency>
+
+
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <scope>compile</scope>
         </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <version>3.13.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>1.10.19</version>
+            <scope>test</scope>
+        </dependency>
+        <!--        <dependency>-->
+        <!--            <groupId>org.powermock</groupId>-->
+        <!--            <artifactId>powermock-api-mockito2</artifactId>-->
+        <!--            <version>2.0.9</version>-->
+        <!--        </dependency>-->
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-mockito</artifactId>
+            <version>1.7.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-module-junit4</artifactId>
+            <version>2.0.9</version>
+        </dependency>
+
+        <!--        <dependency>-->
+        <!--            <groupId>org.jacoco</groupId>-->
+        <!--            <artifactId>jacoco-maven-plugin</artifactId>-->
+        <!--            <version>0.8.6</version>-->
+        <!--        </dependency>-->
+
 
     </dependencies>
 
diff --git a/src/main/java/StartingOSStats.java b/src/main/java/StartingOSStats.java
deleted file mode 100644
index 11bf1a4fc718480b2f0b2de5c3708fd9d1bc9dda..0000000000000000000000000000000000000000
--- a/src/main/java/StartingOSStats.java
+++ /dev/null
@@ -1,114 +0,0 @@
-import fr.pasteur.ida.zellige.surfaceConstruction.parameters.AdvancedUserParameters;
-import fr.pasteur.ida.zellige.surfaceConstruction.construction.ReferenceSurfaceExtraction;
-import fr.pasteur.ida.zellige.surfaceConstruction.parameters.UserParameters;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSE;
-import fr.pasteur.ida.zellige.utils.TestMIP;
-import ij.IJ;
-import ij.ImageJ;
-import io.scif.img.IO;
-import io.scif.img.SCIFIOImgPlus;
-import net.imglib2.img.Img;
-import net.imglib2.img.display.imagej.ImageJFunctions;
-import net.imglib2.type.NativeType;
-import net.imglib2.type.numeric.RealType;
-
-import java.io.BufferedWriter;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.TreeMap;
-
-public class StartingOSStats
-{
-
-    BufferedWriter writer;
-    FileWriter fileWriter;
-    private final String path =  "C:\\Users\\ctrebeau\\Desktop\\stats\\";
-
-    public StartingOSStats( String fileName  ) throws IOException
-    {
-        fileName.replace( "tif", "txt" );
-        writer = new BufferedWriter(new FileWriter(fileName));
-        writer.write(path + fileName  );
-    }
-
-
-    public void writeParameter(String amplitude, String otsu, String sigmas, String delta) throws IOException
-    {
-        StringBuilder s = new StringBuilder(
-                "Amplitude percent : " + amplitude +
-                "Otsu percent : " +otsu + System.lineSeparator() +
-                "Sigmas : " + sigmas + System.lineSeparator()+
-                "Delta : " + delta + System.lineSeparator());
-
-        writer.write( s.toString() );
-    }
-
-    public void close() throws IOException
-    {
-        writer.close();
-    }
-
-    public void writeHistogram(  TreeMap<Integer, Integer> map ) throws IOException
-    {
-        writer.write(map.toString());
-    }
-
-    public void writeInfo( String info, double value) throws IOException
-    {
-        writer.write( info + " : " + value );
-    }
-    public static < T extends RealType< T > & NativeType< T > > void main( String[] args ) throws IOException
-    {
-        String path = "C:\\Users\\ctrebeau\\Desktop\\MoucheAile\\STK\\";
-        String fileName = "STK_Mouche_c01_f0001_p005.tif";
-
-        // Input of the image.
-        final String imagePath = path + fileName;
-//        "doc/BG2.tif";
-
-
-
-
-        System.out.println("File : " + fileName );
-
-
-        ImageJ ij = new ImageJ();
-        /* JY version for opening files. */
-        final SCIFIOImgPlus< ? > imgPlus = IO.openImgs( imagePath ).get( 0 );
-
-        final Img< T > stackImage = ( Img < T > ) imgPlus.getImg();
-
-
-        /* User Parameters AKA arguments to run the program*/
-        double amplitude = Double.parseDouble( args[ 0 ] );
-        double otsu = Double.parseDouble( args[ 1 ] );
-        int sigmas = Integer.parseInt( args[ 2 ] );
-        int k1 = Integer.parseInt( args[ 3 ] );
-        double percent1 = Double.parseDouble( args[ 4 ] );
-        int k2 = Integer.parseInt( args[ 5 ] );
-        double percent2 = Double.parseDouble( args[ 6 ] );
-        int delta = Integer.parseInt( args[ 7 ] );
-        /* End of parameters. */
-
-        UserParameters userParameters = new UserParameters( amplitude, otsu, sigmas, delta, "MIP" );
-        AdvancedUserParameters advancedUserParameters = new AdvancedUserParameters( k1, percent1, k2, percent2 );
-
-        IJ.log("Type: "+ imgPlus.firstElement().getClass().toGenericString());
-
-        if ( stackImage.numDimensions() == 3 )// Is it a stack ?
-        {
-//            ImageJFunctions.show( stackImage, "original" );
-//            ImageJFunctions.show( TestMIP.findMIP( stackImage, stackImage.factory() ), "MIP" );
-            new ReferenceSurfaceExtraction<>( stackImage, stackImage.factory(),userParameters, advancedUserParameters );
-        }
-        else
-        {
-            System.out.println( " This image has to be a z-stack ! " );
-        }
-        StartingOSStats startingOSStats = new StartingOSStats( fileName );
-        startingOSStats.writeParameter( args[ 0 ] , args[ 1 ] , args[ 2 ], args[ 3 ]  );
-        startingOSStats.writeInfo( "OS count ", OSE.getCount() );
-//        startingOSStats.writeHistogram( OSE.getOcc() );
-        startingOSStats.close();
-    }
-}
diff --git a/src/main/java/fr/pasteur/ida/zellige/ReferenceSurfaceExtraction.java b/src/main/java/fr/pasteur/ida/zellige/ReferenceSurfaceExtraction.java
new file mode 100644
index 0000000000000000000000000000000000000000..86216b5187d03cd3f5413e804ba433c00da207b7
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/ReferenceSurfaceExtraction.java
@@ -0,0 +1,176 @@
+package fr.pasteur.ida.zellige;
+
+import fr.pasteur.ida.zellige.exception.EmptyOutputException;
+import fr.pasteur.ida.zellige.exception.NoClassificationException;
+import fr.pasteur.ida.zellige.jzy3D.LocalMaximumsDisplay;
+import fr.pasteur.ida.zellige.jzy3D.SurfaceDisplay;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound.FirstRoundConstruction;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound.SecondRoundConstruction;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection.Pretreatment;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection.SurfacePixelSelection;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ReferenceSurface;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ConstructionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.DisplayParameter;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ProjectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelSelectionParameters;
+import fr.pasteur.ida.zellige.utils.Interpolation;
+import fr.pasteur.ida.zellige.utils.Utils;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.img.Img;
+import net.imglib2.img.ImgFactory;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.RealType;
+import net.imglib2.type.numeric.integer.UnsignedShortType;
+import org.jzy3d.analysis.AnalysisLauncher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+
+
+
+public class ReferenceSurfaceExtraction< T extends RealType< T > & NativeType< T > >
+{
+
+    private final static Logger LOGGER = LoggerFactory.getLogger( ReferenceSurfaceExtraction.class );
+
+    private final  ArrayList< ReferenceSurface <T>> referenceSurfaces = new ArrayList<>();
+    private final RandomAccessibleInterval< T > input;
+    private final ImgFactory<T> factory;
+    private final PixelSelectionParameters selectionParameters;
+    private final ProjectionParameters projectionParameters;
+    private final ConstructionParameters [] constructionParameters;
+    private Pixels [][] maximums;
+    public ReferenceSurfaceExtraction( RandomAccessibleInterval< T > input, ImgFactory< T > factory,
+                                       PixelSelectionParameters parameters , ProjectionParameters projectionParameters,
+                                       ConstructionParameters [] constructionParameters)
+    {
+        this.input = input;
+        this.factory = factory;
+        this.selectionParameters = parameters;
+        this.projectionParameters = projectionParameters;
+        this.constructionParameters = constructionParameters;
+    }
+
+
+    public void select() throws NoClassificationException, EmptyOutputException
+    {
+        /* First step : Pixel selection */
+        LOGGER.info("Running selection...");
+        maximums = SurfacePixelSelection.run( input, selectionParameters );
+    }
+
+
+    public void construct()
+    {
+        LOGGER.info("Running construction...");
+        try
+        {
+            /*  First round construction*/
+            ArrayList< Surface > tempSurfaces = FirstRoundConstruction.run( maximums, constructionParameters[0] );
+            System.out.println( "first round surfaces = " + tempSurfaces.size() );
+//            for(Surface s : tempSurfaces)
+//            {
+//                displaySurface( s );
+//            }
+            /* Second round construction */
+            ArrayList<Surface> finalSurfaces = SecondRoundConstruction.run( tempSurfaces, constructionParameters[1] );
+
+            /* Building reference surfaces */
+            referenceSurfaceInstantiation( finalSurfaces );
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+        }
+    }
+    public   void extract( ) throws EmptyOutputException, NoClassificationException
+    {
+//        select();
+        construct();
+//        /* Second step : Surface construction in 2 rounds */
+//        try
+//        {
+//            /*  First round construction*/
+//            ArrayList< Surface > tempSurfaces = FirstRoundConstruction.run( maximums, constructionParameters[0] );
+//            System.out.println( "first round surfaces = " + tempSurfaces.size() );
+////            for(Surface s : tempSurfaces)
+////            {
+////                displaySurface( s );
+////            }
+//            /* Second round construction */
+//            ArrayList<Surface> finalSurfaces = SecondRoundConstruction.run( tempSurfaces, constructionParameters[1] );
+//
+//            /* Building reference surfaces */
+//            referenceSurfaceInstantiation( finalSurfaces );
+//        }
+//        catch ( Exception e )
+//        {
+//            e.printStackTrace();
+//        }
+    }
+
+    public Img<UnsignedShortType> processedZMap(Surface surface)
+    {
+        // First step : fill in the holes with linear interpolation. */
+        Img< UnsignedShortType > interpolated = Interpolation.run( surface.getZMap() );
+        Img< UnsignedShortType > smoothed = interpolated.copy();
+//        ImageJFunctions.show( smoothed, "smoothed" );
+        // Second step:  smooth the elevation map with gaussian blur
+        Utils.gaussConvolution( interpolated, smoothed, new double[]{ 1.0, 1.0 } );
+        return smoothed;
+    }
+
+    private void referenceSurfaceInstantiation(ArrayList<Surface> finalSurfaces)
+    {
+        int index = 0;
+        for( Surface surface : finalSurfaces )
+        {
+//            displaySurface( surface );
+            Img< UnsignedShortType > processedZMap = processedZMap( surface );
+            ReferenceSurface< T > referenceSurface = new ReferenceSurface<>( input, factory, processedZMap, index++ );
+            referenceSurfaces.add( referenceSurface );
+        }
+    }
+
+    public void project()
+    {
+        LOGGER.info("Running projection...");
+        for(ReferenceSurface<T> referenceSurface : referenceSurfaces)
+        {
+            referenceSurface.setProjection( projectionParameters.getProjectionType(), projectionParameters.getDelta() );
+            DisplayParameter displayParameter = new DisplayParameter( projectionParameters.getDelta(), false,
+                    false, false, true );
+            referenceSurface.display( displayParameter );
+        }
+    }
+
+
+
+    public static void displaySurface( Surface surface )
+    {
+        try
+        {
+            SurfaceDisplay s = new SurfaceDisplay( surface );
+            AnalysisLauncher.open( s );
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+        }
+    }
+
+    public ArrayList< ReferenceSurface< T > > getReferenceSurfaces()
+    {
+        return referenceSurfaces;
+    }
+
+    public Pixels[][] getMaximums()
+    {
+        return maximums;
+    }
+}
+
+
diff --git a/src/main/java/SurfacesExtractionAnalyse.java b/src/main/java/fr/pasteur/ida/zellige/SurfacesExtractionAnalyse.java
similarity index 70%
rename from src/main/java/SurfacesExtractionAnalyse.java
rename to src/main/java/fr/pasteur/ida/zellige/SurfacesExtractionAnalyse.java
index e37a8e35963a6dfec8110fc16d49c1b07b779020..7fc10e6e8d4abbd1c397401d79503708021e8043 100644
--- a/src/main/java/SurfacesExtractionAnalyse.java
+++ b/src/main/java/fr/pasteur/ida/zellige/SurfacesExtractionAnalyse.java
@@ -1,3 +1,26 @@
+package fr.pasteur.ida.zellige;
+
+import fr.pasteur.ida.zellige.ReferenceSurfaceExtraction;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.AbstractOSE;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ConstructionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ProjectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelClassificationParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelSelectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PostTreatmentParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters;
+import ij.IJ;
+import ij.ImageJ;
+import io.scif.img.IO;
+import io.scif.img.SCIFIOImgPlus;
+import net.imglib2.img.Img;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.RealType;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.TreeMap;
+
 public class SurfacesExtractionAnalyse
 {
 //    public static < T extends RealType < T > & NativeType < T > > void main( String[] args )
@@ -344,6 +367,108 @@ public class SurfacesExtractionAnalyse
 //
 //    }
 
+    public static class StartingOSStats
+    {
+
+        BufferedWriter writer;
+        FileWriter fileWriter;
+        private final String path =  "C:\\Users\\ctrebeau\\Desktop\\stats\\";
+
+        public StartingOSStats( String fileName  ) throws IOException
+        {
+            fileName.replace( "tif", "txt" );
+            writer = new BufferedWriter(new FileWriter(fileName));
+            writer.write(path + fileName  );
+        }
+
+
+        public void writeParameter(String amplitude, String otsu, String sigmas, String delta) throws IOException
+        {
+            StringBuilder s = new StringBuilder(
+                    "Amplitude percent : " + amplitude +
+                    "Otsu percent : " +otsu + System.lineSeparator() +
+                    "Sigmas : " + sigmas + System.lineSeparator()+
+                    "Delta : " + delta + System.lineSeparator());
+
+            writer.write( s.toString() );
+        }
+
+        public void close() throws IOException
+        {
+            writer.close();
+        }
+
+        public void writeHistogram(  TreeMap<Integer, Integer> map ) throws IOException
+        {
+            writer.write(map.toString());
+        }
+
+        public void writeInfo( String info, double value) throws IOException
+        {
+            writer.write( info + " : " + value );
+        }
+        public static < T extends RealType< T > & NativeType< T > > void main( String[] args ) throws Exception
+        {
+            String path = "C:\\Users\\ctrebeau\\Desktop\\MoucheAile\\STK\\";
+            String fileName = "STK_Mouche_c01_f0001_p005.tif";
+
+            // Input of the image.
+            final String imagePath = path + fileName;
+    //        "doc/BG2.tif";
+
+
+
+
+            System.out.println("File : " + fileName );
+
+
+            ImageJ ij = new ImageJ();
+            /* JY version for opening files. */
+            final SCIFIOImgPlus< ? > imgPlus = IO.openImgs( imagePath ).get( 0 );
+
+            final Img< T > stackImage = ( Img < T > ) imgPlus.getImg();
+
+
+            /* User Parameters AKA arguments to run the program*/
+            double amplitude = Double.parseDouble( args[ 0 ] );
+            double otsu = Double.parseDouble( args[ 1 ] );
+            double sigmaXY = Double.parseDouble( args[ 2 ] );
+            double sigmaZ = Double.parseDouble( args[ 3 ] );
+            int k1 = Integer.parseInt( args[ 4 ] );
+            double percent1 = Double.parseDouble( args[ 5 ] );
+            int k2 = Integer.parseInt( args[ 6 ] );
+            double percent2 = Double.parseDouble( args[ 7 ] );
+            int delta = Integer.parseInt( args[ 8 ] );
+            /* End of parameters. */
+            PretreatmentParameters pretreatmentParameters = new PretreatmentParameters( "Median", new double[]{2} );
+            PixelClassificationParameters classificationParameters = new PixelClassificationParameters( amplitude, otsu );
+            PostTreatmentParameters postTreatmentParameters = new PostTreatmentParameters( sigmaXY, sigmaZ, 5, 8 );
+            PixelSelectionParameters pixelSelectionParameters = new PixelSelectionParameters( pretreatmentParameters, classificationParameters, postTreatmentParameters );
+            ProjectionParameters projectionParameters = new ProjectionParameters( delta, "MIP" );
+            ConstructionParameters[] constructionParameters = new ConstructionParameters[]{
+                    new ConstructionParameters( 0.75, k1, percent1 ),
+                    new ConstructionParameters( 0.1, k2, percent2 )};
+
+            IJ.log("Type: "+ imgPlus.firstElement().getClass().toGenericString());
+
+            if ( stackImage.numDimensions() == 3 )// Is it a stack ?
+            {
+    //            ImageJFunctions.show( stackImage, "original" );
+    //            ImageJFunctions.show( TestMIP.findMIP( stackImage, stackImage.factory() ), "MIP" );
+     new ReferenceSurfaceExtraction<>
+                        ( stackImage, stackImage.factory(), pixelSelectionParameters, projectionParameters, constructionParameters);
+            }
+            else
+            {
+                System.out.println( " This image has to be a z-stack ! " );
+            }
+            StartingOSStats startingOSStats = new StartingOSStats( fileName );
+            startingOSStats.writeParameter( args[ 0 ] , args[ 1 ] , args[ 2 ], args[ 3 ]  );
+            startingOSStats.writeInfo( "OS count ", AbstractOSE.getCount() );
+    //        startingOSStats.writeHistogram( OSE.getOcc() );
+            startingOSStats.close();
+        }
+    }
 }
 
 
diff --git a/src/main/java/fr/pasteur/ida/zellige/exception/DataValidationException.java b/src/main/java/fr/pasteur/ida/zellige/exception/DataValidationException.java
new file mode 100644
index 0000000000000000000000000000000000000000..90a7f76fd089b9334d7cc963f0bdc5867e8a7e44
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/exception/DataValidationException.java
@@ -0,0 +1,10 @@
+package fr.pasteur.ida.zellige.exception;
+
+public class DataValidationException extends Exception
+{
+
+    public DataValidationException( String message )
+    {
+        super( message );
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/exception/DifferentReferenceTestedSizeException.java b/src/main/java/fr/pasteur/ida/zellige/exception/DifferentReferenceTestedSizeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..795e67782dba0ce05b5e660a85ac5418f6eb383a
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/exception/DifferentReferenceTestedSizeException.java
@@ -0,0 +1,5 @@
+package fr.pasteur.ida.zellige.exception;
+
+public class DifferentReferenceTestedSizeException extends Exception
+{
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/exception/EmptyOutputException.java b/src/main/java/fr/pasteur/ida/zellige/exception/EmptyOutputException.java
new file mode 100644
index 0000000000000000000000000000000000000000..f29b4de815707c97d02a23c7af4f41a6e2323f4a
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/exception/EmptyOutputException.java
@@ -0,0 +1,9 @@
+package fr.pasteur.ida.zellige.exception;
+
+public class EmptyOutputException extends Exception
+{
+    public EmptyOutputException( String message )
+    {
+        super( message );
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/exception/NoClassificationException.java b/src/main/java/fr/pasteur/ida/zellige/exception/NoClassificationException.java
new file mode 100644
index 0000000000000000000000000000000000000000..944f69d20e1d531fddbcb3193c1a12a8a3028d32
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/exception/NoClassificationException.java
@@ -0,0 +1,5 @@
+package fr.pasteur.ida.zellige.exception;
+
+public class NoClassificationException extends Exception
+{
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/exception/NotAnHeightMapException.java b/src/main/java/fr/pasteur/ida/zellige/exception/NotAnHeightMapException.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c7778a2dea82cade92c039ac2cbf9fef81e265b
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/exception/NotAnHeightMapException.java
@@ -0,0 +1,5 @@
+package fr.pasteur.ida.zellige.exception;
+
+public class NotAnHeightMapException extends Exception
+{
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/jzy3D/LocalMaximumsDisplay.java b/src/main/java/fr/pasteur/ida/zellige/jzy3D/LocalMaximumsDisplay.java
index 1eb743fece7ba90e2f3ce7ee77ce37458ea52c3d..1acfcc368aef77fa52b25d867e57d7eb86cc0e22 100644
--- a/src/main/java/fr/pasteur/ida/zellige/jzy3D/LocalMaximumsDisplay.java
+++ b/src/main/java/fr/pasteur/ida/zellige/jzy3D/LocalMaximumsDisplay.java
@@ -4,15 +4,21 @@ package fr.pasteur.ida.zellige.jzy3D;
 import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
 import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
 import org.jzy3d.analysis.AbstractAnalysis;
+import org.jzy3d.analysis.AnalysisLauncher;
 import org.jzy3d.chart.factories.AWTChartComponentFactory;
 import org.jzy3d.colors.Color;
 import org.jzy3d.maths.Coord3d;
 import org.jzy3d.plot3d.primitives.Scatter;
 import org.jzy3d.plot3d.rendering.canvas.Quality;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.awt.*;
 
 
 public class LocalMaximumsDisplay extends AbstractAnalysis
 {
+    private final static Logger LOGGER = LoggerFactory.getLogger( LocalMaximumsDisplay.class );
     private final Pixels[][] maximumCoordinates;
 
     public LocalMaximumsDisplay( Pixels[][] localMaximums )
@@ -21,8 +27,32 @@ public class LocalMaximumsDisplay extends AbstractAnalysis
         init();
     }
 
+    /**
+     * Displays the local maximums found using jzy3D package.
+     */
+    public static void displayMaximums( Pixels[][] maximums )
+    {
+        LOGGER.info( "3D maximums display" );
+//        if ( ! GraphicsEnvironment.isHeadless() )
+        {
+            try
+            {
+                LocalMaximumsDisplay localMaximumsDisplay = new LocalMaximumsDisplay( maximums );
+                AnalysisLauncher.open( localMaximumsDisplay );
+            }
+            catch ( Exception e )
+            {
+                e.printStackTrace();
+            }
+        }
+//        else
+//        {
+//            LOGGER.warn( "No Graphics Environment detected" );
+//        }
+    }
+
     @Override
-    public void init( )
+    public void init()
     {
         if ( maximumCoordinates != null )
         {
@@ -44,8 +74,9 @@ public class LocalMaximumsDisplay extends AbstractAnalysis
                     {
 
                         if ( pixels.size() == 1 )
-                        { Coordinate pixel  = pixels.get(0);
-                        x = pixel.getX();
+                        {
+                            Coordinate pixel = pixels.get( 0 );
+                            x = pixel.getX();
                             y = pixel.getY();
                             z = pixel.getZ();
                             points[ index ] = new Coord3d( x, y, z );
@@ -54,9 +85,9 @@ public class LocalMaximumsDisplay extends AbstractAnalysis
                         }
                         else
                         {
-                            for ( Coordinate coordinate :  pixels .get() )
+                            for ( Coordinate coordinate : pixels.get() )
                             {
-                                z =  coordinate.getZ();
+                                z = coordinate.getZ();
                                 points[ index ] = new Coord3d( coordinate.getX(), coordinate.getY(), z );
                                 colors[ index ] = Color.RED;
 //                                System.out.println( points[index]);
@@ -78,13 +109,13 @@ public class LocalMaximumsDisplay extends AbstractAnalysis
     private int getNumberOfCoordinates()
     {
         int n = 0;
-        for ( int i = 0; i <= maximumCoordinates[0].length - 1; i++ )
+        for ( int i = 0; i <= maximumCoordinates[ 0 ].length - 1; i++ )
         {
-            for ( int j = 0; j <= maximumCoordinates.length - 1 ; j++ )
+            for ( int j = 0; j <= maximumCoordinates.length - 1; j++ )
             {
-                if( maximumCoordinates[j][i] != null)
+                if ( maximumCoordinates[ j ][ i ] != null )
                 {
-                    n += maximumCoordinates[j][i].size();
+                    n += maximumCoordinates[ j ][ i ].size();
                 }
             }
         }
diff --git a/src/main/java/fr/pasteur/ida/zellige/jzy3D/OSDisplay.java b/src/main/java/fr/pasteur/ida/zellige/jzy3D/OSDisplay.java
index b1d8a7ba26d9de079fa5d2a922bb9fcc26bd26e7..553fc6ba0913934212f31ba0b795cb0ce7b8e240 100644
--- a/src/main/java/fr/pasteur/ida/zellige/jzy3D/OSDisplay.java
+++ b/src/main/java/fr/pasteur/ida/zellige/jzy3D/OSDisplay.java
@@ -1,7 +1,7 @@
 package fr.pasteur.ida.zellige.jzy3D;
 
 import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSE;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.AbstractOSE;
 import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEList;
 import org.jzy3d.analysis.AbstractAnalysis;
 import org.jzy3d.chart.factories.AWTChartComponentFactory;
@@ -26,7 +26,7 @@ public class OSDisplay extends AbstractAnalysis {
     public void init() {
         int count = 0;
         for ( OSEList oseList : oseLists ) {
-            for ( OSE os : oseList ) {
+            for ( AbstractOSE os : oseList ) {
                 count = count+os.size();
             }
         }
@@ -42,7 +42,7 @@ public class OSDisplay extends AbstractAnalysis {
         int index = 0;
         for ( OSEList oseList : oseLists ) {
 
-            for ( OSE os : oseList ) {
+            for ( AbstractOSE os : oseList ) {
                 // one color per OS
                 float G = r.nextFloat() ;
                 float R = r.nextFloat()  ;
diff --git a/src/main/java/fr/pasteur/ida/zellige/main/Main.java b/src/main/java/fr/pasteur/ida/zellige/main/Main.java
index d2530578c92e44d0b65907218db57465f519b44c..bcac6578fdc6745fce67c700da500839c2f8afcd 100644
--- a/src/main/java/fr/pasteur/ida/zellige/main/Main.java
+++ b/src/main/java/fr/pasteur/ida/zellige/main/Main.java
@@ -1,9 +1,13 @@
 package fr.pasteur.ida.zellige.main;
 
-import fr.pasteur.ida.zellige.surfaceConstruction.parameters.AdvancedUserParameters;
-import fr.pasteur.ida.zellige.surfaceConstruction.construction.ReferenceSurfaceExtraction;
-import fr.pasteur.ida.zellige.surfaceConstruction.parameters.UserParameters;
-import fr.pasteur.ida.zellige.utils.TestMIP;
+
+import fr.pasteur.ida.zellige.ReferenceSurfaceExtraction;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ConstructionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelClassificationParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelSelectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ProjectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PostTreatmentParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters;
 import ij.IJ;
 import ij.ImageJ;
 import io.scif.img.IO;
@@ -13,6 +17,8 @@ import net.imglib2.img.display.imagej.ImageJFunctions;
 import net.imglib2.type.NativeType;
 import net.imglib2.type.numeric.RealType;
 
+import java.awt.*;
+
 
 /**
  *
@@ -57,12 +63,14 @@ public class Main
 
         // Input of the image.
         final String imagePath =
-//        "doc/C0T0.tif";
-//        "C:\\Users\\ctrebeau\\Desktop\\MoucheAile\\STK\\STK_Mouche_c01_f0001_p005.tif";
-//        "C:\\Users\\ctrebeau\\Downloads\\phantom3b_combined.tif";
+                "doc/STK.tif";
+//        "doc/phantoms_crossingsurf_crop.tif";
+//        "doc/phantom_small4test.tif";
+//        "C:\\Users\\ctrebeau\\Desktop\\MoucheAile\\STK\\STK_Mouche_c01_f0001_p003.tif";
+//        "C:\\Users\\ctrebeau\\Downloads\\phantoms_curv100.tif";
 //                "C:\\Users\\ctrebeau\\Desktop\\HighRes\\STK_170706_Vangl2-Lp-wt_E14.5_Phall_cochlea_01bHighRes_c01_f0001_p005.tif";
 //       "C:\\Users\\ctrebeau\\Desktop\\HighRes\\STK_170706_Vangl2-Lp-wt_E14.5_Phall_cochlea_01bHighRes_c01_f0001_p002.tif";
-      "C:\\Users\\ctrebeau\\Desktop\\Acq060720\\C2-MucilairB spike zo1 J2 Mock-2.tif";
+//      "C:\\Users\\ctrebeau\\Desktop\\phantom_tests_snr_1surf\\phantoms_1surf_snr0.mat.tif";
         System.out.println(imagePath);
         // Creation of the image : version with unsigned type. */
         /* JY version for opening files. */
@@ -74,34 +82,48 @@ public class Main
         /* User Parameters AKA arguments to run the program*/
         double amplitude = Double.parseDouble( args[ 0 ] );
         double otsu = Double.parseDouble( args[ 1 ] );
-        double sigmas = Double.parseDouble( args[ 2 ] );
-        int k1 = Integer.parseInt( args[ 3 ] );
-        double percent1 = Double.parseDouble( args[ 4 ] );
-        int k2 = Integer.parseInt( args[ 5 ] );
-        double percent2 = Double.parseDouble( args[ 6 ] );
-        int delta = Integer.parseInt( args[ 7 ] );
+        double sigmaXY = Double.parseDouble( args[ 2 ] );
+        double sigmaZ = Double.parseDouble( args[ 3 ] );
+        int k1 = Integer.parseInt( args[ 4 ] );
+        double percent1 = Double.parseDouble( args[ 5 ] );
+        int k2 = Integer.parseInt( args[ 6 ] );
+        double percent2 = Double.parseDouble( args[ 7 ] );
+        int delta = Integer.parseInt( args[ 8 ] );
         /* End of parameters. */
 
 
         /* Print parameters.*/
         System.out.println( " amplitude  : " + amplitude );
         System.out.println( " threshold  : " + otsu );
-        System.out.println( " Blur size : " + sigmas );
+        System.out.println( " Blur size : " + sigmaXY );
         System.out.println( " Delta : " + delta );
         System.out.println( System.lineSeparator() );
         /* End of  Print parameters.*/
 
-        UserParameters userParameters = new UserParameters( amplitude, otsu, sigmas, delta, "MIP" );
-        AdvancedUserParameters advancedUserParameters = new AdvancedUserParameters( k1, percent1, k2, percent2 );
+        PretreatmentParameters pretreatmentParameters = new PretreatmentParameters( "GaussianBlur", new double[]{2, 2, 1} );
+        PixelClassificationParameters classificationParameters = new PixelClassificationParameters( amplitude, otsu );
+        PostTreatmentParameters postTreatmentParameters = new PostTreatmentParameters( sigmaXY, sigmaZ, 10, 8 );
+
+        PixelSelectionParameters pixelSelectionParameters = new PixelSelectionParameters( pretreatmentParameters, classificationParameters, postTreatmentParameters );
+        ProjectionParameters projectionParameters = new ProjectionParameters( delta, "MIP" );
+        ConstructionParameters[] constructionParameters = new ConstructionParameters[]{
+                new ConstructionParameters( 0.75, k1, percent1 ),
+                new ConstructionParameters( 0.1, k2, percent2 )};
         IJ.log("Type: "+ imgPlus.firstElement().getClass().toGenericString());
 
         if ( stackImage.numDimensions() == 3 )// Is it a stack ?
         {
-            ImageJFunctions.show( stackImage, "original" );
+//            ImageJFunctions.show( stackImage, "original" );
 //            ImageJFunctions.show( TestMIP.findMIP( stackImage, stackImage.factory() ), "MIP" );
-            ReferenceSurfaceExtraction rse = new ReferenceSurfaceExtraction<>( stackImage, stackImage.factory(),userParameters, advancedUserParameters );
-            rse.extract();
-            rse.project();
+            ReferenceSurfaceExtraction<T> rse = new ReferenceSurfaceExtraction<>
+                    ( stackImage, stackImage.factory(), pixelSelectionParameters, projectionParameters,constructionParameters );
+            rse.select();
+            rse.construct();
+
+            if ( !GraphicsEnvironment.isHeadless())
+            {
+                rse.project();
+            }
         }
         else
         {
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/OSEListConstruction.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/OSEListConstruction.java
deleted file mode 100644
index 2b573922e769630c45f3880564aa02fce662197a..0000000000000000000000000000000000000000
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/OSEListConstruction.java
+++ /dev/null
@@ -1,272 +0,0 @@
-package fr.pasteur.ida.zellige.surfaceConstruction.construction;
-
-import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSE;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEList;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEStartingStatus;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.Queue;
-
-
-/**
- * This class contains a main method for the construction of OSE : {@code findOS}.
- */
-public class OSEListConstruction
-{
-    private final Pixels[][] maximums;
-    private final OSEList[] oseLists;
-    private final OSEStartingStatus startingStatus;
-    private final int dimension;
-
-    public OSEListConstruction( Pixels[][] maximums , int dimension)
-    {
-        this.maximums = maximums;
-        this.oseLists = new OSEList[maximums.length];
-        this.dimension = dimension;
-        this.startingStatus = new OSEStartingStatus( dimension );
-    }
-
-    public void run()
-    {
-        for ( int i = 0; i <= maximums.length - 1; i++ )
-        {
-            oseLists[ i ] = findOSE( maximums[ i ] );
-        }
-        startingStatus.setStartingStatus();
-        System.out.println( "Starting size = " + startingStatus.getMinimumSize());
-    }
-    
-        /**
-         * This method finds all the possible 2D surfaces that can be created from the coordinates detected as
-         * local maximums on a array of {@link }.
-         *
-         * @param rawCoordinates - the raw Coordinates from the projection.
-         * @return all the orthogonal surfaces for the projection as an {@link ArrayList<OSE>}.
-         */
-        private OSEList findOSE( Pixels[] rawCoordinates )
-        {
-            if ( dimension == 1 )
-            {
-                reset( rawCoordinates );// the number of right and left coordinates are reset to 0.
-            }
-            ArrayList< Coordinate > startingCoordinates = checkForSideCoordinates( rawCoordinates );
-            OSEList paths = findSimplePaths( startingCoordinates, rawCoordinates );
-            OSEList finalPaths = findComplexPaths( paths );
-            if ( dimension == 0 )
-            {
-                finalPaths.removeIf( ose -> ose.size() < 3 );// shortest ones are removed
-            }
-            for ( OSE ose : finalPaths )
-            {
-                ose.set();
-            }
-            finalPaths.reset();
-            return finalPaths;
-        }
-
-        private OSEList findSimplePaths( ArrayList< Coordinate > startingCoordinates, Pixels[] rawCoordinates )
-        {
-            Queue< Coordinate > firstQueue = new LinkedList<>( startingCoordinates );// Add the coordinates with no left coordinates in
-            // the queue
-            OSEList smallPath = new OSEList();
-            while ( ! firstQueue.isEmpty() )
-            {
-                Coordinate current = firstQueue.remove();
-                OSE ose = new OSE( startingStatus );
-                ose.add( current );
-                findSimplePaths( rawCoordinates, smallPath, ose, current, firstQueue );
-            }
-            return smallPath;
-        }
-
-        /**
-         * @param rawCoordinates -  the raw Coordinates from the projection.
-         * @param smallPath      - the one-Z-OSE
-         * @param ose             - the first OSE considered.
-         * @param current        - the starting {@link Coordinate} considered.
-         */
-        private  void findSimplePaths
-        ( Pixels[] rawCoordinates,
-          ArrayList< OSE > smallPath, OSE ose, Coordinate current, Queue< Coordinate > queue )
-        {
-            int i;
-            if ( dimension == 0 )
-            {
-                i = current.getX();
-            }
-            else
-            {
-                i = current.getY();
-            }
-            while ( i <= rawCoordinates.length - 2 // x must be < to the length of the image minus 1 because [X + 1]
-                    && rawCoordinates[ i ] != null // the contents in the array at index x must not be null
-                    && rawCoordinates[ i + 1 ] != null // the contents in the array at index (x +1) must not be null
-                    && current != null )
-            {
-                Coordinate next = current.getNext( rawCoordinates[ i + 1 ], 0 );
-                if ( next != null )//  Conditions :  |x1 - x2 |= 1 => only 1D surface
-                {
-                    ose.add( next );
-                }
-                else
-                {
-                    if ( ( i ) < rawCoordinates.length - 3
-                            && rawCoordinates[ i + 2 ] != null// the contents in the array at index (x +1) must not
-                            // be null
-                            && current.getRightNumber() == 0 )
-                    {
-                        next = current.getNext( rawCoordinates[ i + 2 ], 0 );
-                        if ( next != null )//fake coordinate
-                        {
-                            if ( dimension == 0 )
-                            {
-                                ose.add( new Coordinate( current.getX() + 1, current.getY(), current.getZ() ) );
-                            }
-                            else
-                            {
-                                ose.add( new Coordinate( current.getX(), current.getY() + 1, current.getZ() ) );
-                            }
-                            ose.add( next );
-                            queue.remove( next );
-                            i++;
-                        }
-                    }
-                }
-                current = next;
-                i++; //increment of the index
-            }
-            smallPath.add( ose );
-        }
-
-        /**
-         * @param shortPaths - the list of one-z-OSE.
-         * @return - the list of "big paths" OSE.
-         */
-        private OSEList findComplexPaths( OSEList shortPaths )
-        {
-            OSEList paths = new OSEList();
-            Queue< OSE > queue = new LinkedList<>( shortPaths );
-            while ( ! queue.isEmpty() )
-            {
-                OSE first = queue.remove();
-                shortPaths.remove( first );
-                findComplexPaths( first, shortPaths, queue, paths );
-            }
-            return paths;
-        }
-
-        /**
-         * @param first      - the starting OSE.
-         * @param smallPaths - the list of all small path OSE.
-         * @param queue      - the remaining OSE.
-         * @param longPaths  - the list of long path OSE.
-         */
-        private  void findComplexPaths( OSE first,
-                                        ArrayList< OSE > smallPaths,
-                                        Queue< OSE > queue, ArrayList< OSE > longPaths )
-        {
-            for ( OSE o : smallPaths )
-            {
-                if ( first.isNextTo( o, dimension ) )
-                {
-                    first.addAll( o );
-                    o.setVisited( true );
-                    queue.remove( o );
-                }
-            }
-            smallPaths.removeIf( OSE::isVisited );
-            longPaths.add( first );
-        }
-
-        /**
-         * Stores the coordinates that don't have a coordinate to the left.
-         *
-         * @param slice - a one-dimensional array containing the local maximums.
-         * @return - a list of coordinates that don't have a coordinate to the left.
-         */
-        private ArrayList< Coordinate > checkForSideCoordinates( Pixels[] slice )
-        {
-            /* Stores the coordinates that have no coordinates to the left.*/
-            ArrayList< Coordinate > noLeftCoordinates = new ArrayList<>();
-            /* Starting point. */
-            int start = 0;
-            while ( start <= slice.length - 3 && slice[ start ] == null )
-            {
-                start++;//the index starts where a List of Coordinates is found in the array
-            }
-            if ( slice[ start ] != null && slice[ start + 1 ] != null ) //some Coordinates were found
-            {
-                /* For the first list of coordinates. */
-                for ( int i = 0; i <= slice[ start ].size() - 1; i++ )// the first coordinates of the array have obviously no left coordinates
-                {
-                    Coordinate coordinate = slice[ start ].get( i );
-                    noLeftCoordinates.add( coordinate );
-                    coordinate.setRightCoordinates( slice[ start + 1 ] );
-                }
-            }
-            /* For the rest. */
-            for ( int i = start + 1; i <= slice.length - 2; i++ )
-            {
-                if ( slice[ i ] != null )
-                {
-                    for ( Coordinate coordinate : slice[ i ].get() )
-                    {
-                        coordinate.setRightCoordinates( slice[ i + 1 ] );
-                        coordinate.setLeftCoordinates( slice[ i - 1 ] );
-                        boolean hasNoLeft = coordinate.numberOfNeighbours( slice[ i - 1 ], 0 ) == 0;
-                        if ( hasNoLeft )
-                        {
-                            noLeftCoordinates.add( coordinate );
-                        }
-                    }
-                }
-            }
-            /* the last one */ //Avoid ArrayOutOfBoundException
-            int end = slice.length - 1;
-            if ( slice[ end ] != null && slice[ end - 1 ] != null )
-            {
-                for ( Coordinate coordinate : slice[ end ].get() )
-                {
-                    coordinate.setLeftCoordinates( slice[ end - 1 ] );
-                    boolean hasNoLeft = coordinate.numberOfNeighbours( slice[ end - 1 ], 0 ) == 0;
-                    if ( hasNoLeft )
-                    {
-                        noLeftCoordinates.add( coordinate );
-                    }
-                }
-            }
-            return noLeftCoordinates;
-        }
-
-        /**
-         * Resets the parameters of each {@link Coordinate } for a given {@link Pixels} array
-         * before the Y dimension reconstruction ( rightsNumber , leftsNumber, noLeft, queue ).
-         *
-         * @param slice - the {@link Pixels} array considered.
-         */
-        private  void reset( Pixels[] slice )
-        {
-            for ( Pixels pixels : slice )
-            {
-                if ( pixels != null )
-                {
-                    pixels.resetSideCoordinate();
-                }
-            }
-        }
-
-
-    public OSEList[] getOseLists()
-    {
-        return oseLists;
-    }
-
-    public OSEStartingStatus getStartingStatus()
-    {
-        return startingStatus;
-    }
-}
-
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/ReferenceSurfaceExtraction.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/ReferenceSurfaceExtraction.java
deleted file mode 100644
index 5d72072a75e65829122371a2c646dbef2f908fc4..0000000000000000000000000000000000000000
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/ReferenceSurfaceExtraction.java
+++ /dev/null
@@ -1,294 +0,0 @@
-package fr.pasteur.ida.zellige.surfaceConstruction.construction;
-
-import fr.pasteur.ida.zellige.surfaceConstruction.parameters.AdvancedUserParameters;
-import fr.pasteur.ida.zellige.surfaceConstruction.parameters.DisplayParameter;
-import fr.pasteur.ida.zellige.exception.FirstRoundConstructionException;
-import fr.pasteur.ida.zellige.exception.NoSurfaceFoundException;
-import fr.pasteur.ida.zellige.jzy3D.LocalMaximumsDisplay;
-import fr.pasteur.ida.zellige.jzy3D.OSDisplay;
-import fr.pasteur.ida.zellige.jzy3D.SurfaceDisplay;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.ReferenceSurface;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEList;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine.SurfaceLine;
-import fr.pasteur.ida.zellige.surfaceConstruction.parameters.UserParameters;
-import fr.pasteur.ida.zellige.utils.*;
-import net.imglib2.RandomAccessibleInterval;
-import net.imglib2.img.Img;
-import net.imglib2.img.ImgFactory;
-import net.imglib2.img.display.imagej.ImageJFunctions;
-import net.imglib2.type.NativeType;
-import net.imglib2.type.numeric.RealType;
-import net.imglib2.type.numeric.integer.UnsignedShortType;
-import org.jzy3d.analysis.AnalysisLauncher;
-
-import java.util.ArrayList;
-
-
-
-public class ReferenceSurfaceExtraction< T extends RealType< T > & NativeType< T > >
-{
-
-    private final  ArrayList< ReferenceSurface <T>> referenceSurfaces = new ArrayList<>();
-    private final RandomAccessibleInterval< T > input;
-    private final ImgFactory<T> factory;
-    private final UserParameters userParameters;
-    private final AdvancedUserParameters advancedUserParameters;
-    public ReferenceSurfaceExtraction( RandomAccessibleInterval< T > input, ImgFactory<T> factory,
-                                       UserParameters userParameters, AdvancedUserParameters advancedUserParameters)
-    {
-        this.input = input;
-        this.factory = factory;
-        this.userParameters = userParameters;
-        this.advancedUserParameters = advancedUserParameters;
-    }
-
-
-    public   void extract( )
-    {
-        /* First step : Pixel selection */
-        SurfacePixelSelection selection = new SurfacePixelSelection( userParameters );
-        selection.run( input );
-        Pixels[][] maximums = selection.getMaximums();
-        /* Second step : Surface construction in 2 rounds */
-        try
-        {
-            /*  First round construction*/
-            double percent1 = advancedUserParameters.getPercent1();
-            int k1 = advancedUserParameters.getK1();
-            ArrayList< Surface > tempSurfaces = firstRoundConstruction( maximums,  percent1, k1);
-            System.out.println( "first round surfaces = " + tempSurfaces.size() );
-
-            /* Second round construction */
-            double percent2 = advancedUserParameters.getPercent2();
-            int k2 = advancedUserParameters.getK2();
-            ArrayList< Surface > finalSurfaces = secondRoundConstruction( tempSurfaces, percent2, k2 );
-            System.out.println( "second round surfaces = " + finalSurfaces.size() );
-
-            /* Process of zMaps */
-            processZMap( finalSurfaces );
-
-            System.out.println( "The end" );
-        }
-        catch ( Exception e )
-        {
-            e.printStackTrace();
-        }
-    }
-
-    /* ----- First and second round construction methods. ----- */
-    private  ArrayList< Surface > firstRoundConstruction( Pixels[][] maximums,  double percent, int k ) throws NoSurfaceFoundException
-    {
-        int dimension = 0;
-        ArrayList<Surface> surfaces = constructSurfaces( maximums, dimension, percent, k );
-        if ( ! surfaces.isEmpty() )
-        {
-            mergeReferenceSurface( surfaces );
-        }
-        else
-        {
-            System.out.println( "No Surface Exception" );
-            throw new FirstRoundConstructionException();
-        }
-        return surfaces;
-    }
-
-    /**
-     * Rebuilds the double pixel array from the {@link SurfaceLine} array
-     * of a {@link Surface} for a construction in the height dimension.
-     *
-     * @param surface - the {@link SurfaceLine}  array of a {@link Surface}
-     * @return a {@link Surface} specific double pixel array.
-     */
-    private  Pixels[][] rebuildPixelsArray( Surface surface )
-    {
-        int width = surface.getHeight();
-        int height = surface.getWidth();
-        Pixels[][] tempCoordinates = new Pixels[ height ][ width ]; // Transposed array
-        for ( int i = 0; i <= width - 1; i++ )
-        {
-            for ( int j = 0; j <= height - 1; j++ )
-            {
-                if ( surface.get( i ) != null )
-                {
-                    tempCoordinates[ j ][ i ] = surface.get( i ).get( j );
-                }
-            }
-        }
-        displayMaximums( tempCoordinates );
-        return tempCoordinates;
-    }
-
-    /**
-     * Reconstructs the TempSurface objects  of the specified list in dimension width.
-     *
-     * @param surfaces - the list of TempSurface objects.
-     */
-    private ArrayList< Surface > secondRoundConstruction( ArrayList< Surface > surfaces,  double percent, int k ) throws NoSurfaceFoundException
-    {
-        int dimension = 1;
-        ArrayList< Surface > finalSurfaces = new ArrayList<>();
-        System.out.println( "========================================" );
-        for ( Surface surface : surfaces )
-        {
-            int width = surface.getHeight();
-            if ( surface.hasDuplicate() )// CoordinateList instead of Coordinate
-            {
-                Pixels[][] maximums = rebuildPixelsArray( surface );
-                ArrayList< Surface > temps = constructSurfaces( maximums,dimension, percent, k);
-                if ( temps.isEmpty() )
-                {
-                    System.out.println( "small surface in second round" );
-//                    throw new SecondRoundConstructionException();
-                }
-                else
-                {
-                    finalSurfaces.addAll( temps );
-                }
-            }
-            else
-            {
-                finalSurfaces.add( surface.transpose(width) );
-            }
-        }
-        mergeReferenceSurface( surfaces);
-        return finalSurfaces;
-
-    }
-
-    private Img<UnsignedShortType> processedZMap(Surface surface)
-    {
-        // First step : fill in the holes with linear interpolation. */
-        Img< UnsignedShortType > interpolated = Interpolation.run( surface.getZMap() );
-        Img< UnsignedShortType > smoothed = interpolated.copy();
-//        ImageJFunctions.show( smoothed, "smoothed" );
-        // Second step:  smooth the elevation map with gaussian blur
-        Utils.gaussConvolution( interpolated, smoothed, new double[]{ 1.0, 1.0 } );
-        return smoothed;
-    }
-
-    //TODO Handle the NOSurfaceFoundException dynamically : this particular surface has to be constructed with a
-    // smaller StartingOSMinimumSize but not necessary the other ones.
-    // May be add a static variable to store the maximum OS size per surfaces
-    //
-
-    /**
-     * Merges the TempSurface objects of the specified list.
-     *
-     * @param surfaces - the list to merge
-     */
-    private  void mergeReferenceSurface( ArrayList< Surface > surfaces )
-    {
-        // Merging step.
-        ArrayList< Surface > toRemoved = new ArrayList<>();
-        for ( int i = surfaces.size() - 1; i > 0; i-- )
-        {
-            Surface one = surfaces.get( i );
-            for ( int j = i - 1; j >= 0; j-- )
-            {
-                Surface two = surfaces.get( j );
-                if ( one.sameSurface( two ) )
-                {
-                    two.merge( one );
-                    toRemoved.add( one );
-                }
-            }
-        }
-        surfaces.removeAll( toRemoved );
-    }
-
-    private OSEList[] constructOSLists( Pixels[][] maximums, int dimension)
-    {
-        OSEListConstruction construction = new OSEListConstruction( maximums, dimension );
-        construction.run();
-        return  construction.getOseLists();
-    }
-
-
-    private ArrayList<Surface> constructSurfaces(Pixels[][] maximums, int dimension, double percent, int k)
-    {
-        int surfaceLineLength = maximums[0].length;
-        OSEList[] oseLists = constructOSLists( maximums, dimension );
-        SurfacesReconstruction surfacesReconstruction = new SurfacesReconstruction(dimension, oseLists,surfaceLineLength, percent, k);
-        surfacesReconstruction.buildSurfaces(  );
-        System.out.println(" Small Surface count : " + surfacesReconstruction.getSmallSurfaceCount());
-        return surfacesReconstruction.getSurfaces();
-    }
-
-    private void processZMap(ArrayList<Surface> surfaces)
-    {
-        int index = 0;
-        for( Surface surface : surfaces )
-        {
-            displaySurface( surface );
-            Img< UnsignedShortType > processedZMap = processedZMap( surface );
-            ReferenceSurface< T > referenceSurface = new ReferenceSurface<>( input, factory, processedZMap, index++ );
-            referenceSurfaces.add( referenceSurface );
-        }
-    }
-
-    public void project()
-    {
-        for(ReferenceSurface<T> referenceSurface : referenceSurfaces)
-        {
-            referenceSurface.setProjection( userParameters.getProjectionType(), userParameters.getDelta() );
-            DisplayParameter displayParameter = new DisplayParameter( userParameters.getDelta(), false,
-                    false, false, true );
-            referenceSurface.display( displayParameter );
-        }
-    }
-
-
-    /* -----  Displaying methods -----*/
-    /**
-     * Displays the local maximums found using jzy3D package.
-     */
-    public static void displayMaximums( Pixels[][] maximums )
-    {
-        try
-        {
-            LocalMaximumsDisplay localMaximumsDisplay = new LocalMaximumsDisplay( maximums );
-            AnalysisLauncher.open( localMaximumsDisplay );
-        }
-        catch ( Exception e )
-        {
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * Displays the local maximums found using jzy3D package.
-     */
-    public static void displayOS( OSEList[] oseLists )
-    {
-        try
-        {
-            OSDisplay display = new OSDisplay( oseLists );
-            AnalysisLauncher.open( display );
-        }
-        catch ( Exception e )
-        {
-            e.printStackTrace();
-        }
-    }
-
-
-
-    public static void displaySurface( Surface surface )
-    {
-        try
-        {
-            SurfaceDisplay s = new SurfaceDisplay( surface );
-            AnalysisLauncher.open( s );
-        }
-        catch ( Exception e )
-        {
-            e.printStackTrace();
-        }
-
-    }
-
-}
-
-
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/SurfacePixelSelection.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/SurfacePixelSelection.java
deleted file mode 100644
index cc73b76159bcfb66bbd81f0d5cfd01dc403cfe1b..0000000000000000000000000000000000000000
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/SurfacePixelSelection.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package fr.pasteur.ida.zellige.surfaceConstruction.construction;
-
-import fr.pasteur.ida.zellige.jzy3D.LocalMaximumsDisplay;
-import fr.pasteur.ida.zellige.surfaceConstruction.parameters.UserParameters;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
-import fr.pasteur.ida.zellige.utils.*;
-import fr.pasteur.ida.zellige.utils.islandSearch.IslandSearch;
-import net.imglib2.RandomAccess;
-import net.imglib2.RandomAccessibleInterval;
-import net.imglib2.converter.Converters;
-import net.imglib2.converter.readwrite.RealFloatSamplerConverter;
-import net.imglib2.img.Img;
-import net.imglib2.img.ImgFactory;
-import net.imglib2.img.array.ArrayImgFactory;
-import net.imglib2.img.display.imagej.ImageJFunctions;
-import net.imglib2.type.NativeType;
-import net.imglib2.type.logic.BitType;
-import net.imglib2.type.numeric.RealType;
-import net.imglib2.type.numeric.real.FloatType;
-import org.jzy3d.analysis.AnalysisLauncher;
-
-public class SurfacePixelSelection
-{
-
-    private final UserParameters userParameters;
-    private Pixels[][] maximums;
-
-    public SurfacePixelSelection( UserParameters userParameters )
-    {
-        this.userParameters = userParameters;
-    }
-
-    /**
-     *
-     * @param source
-     * @param <T>
-     * @return
-     */
-    public < T extends RealType< T > & NativeType< T > > void run( RandomAccessibleInterval< T > source )
-    {
-        /* Pretreatment of the image.*/
-        Img< FloatType > normalized = pretreatment( source );
-        ImageJFunctions.show( normalized.copy(), "converted, blurred and normalized " );
-        ImgFactory<FloatType> factory = normalized.factory();
-        /* Local maximum search and selection */
-        maximums  = maximumSearch2( normalized, factory );
-        /* Output  */
-        displayMaximums( maximums );
-    }
-
-    /**
-     *
-     * @param source
-     * @param <T>
-     * @return
-     */
-    private  < T extends RealType< T > & NativeType< T > >Img<FloatType> pretreatment( RandomAccessibleInterval< T > source )
-    {
-        // Conversion into FloatType for the derivative computation (negative values)
-        RandomAccessibleInterval< FloatType > converted = Converters.convert( source, new RealFloatSamplerConverter<>() );
-
-        //Image denoising with an anisotropic convolution or median filter !!
-        ImgFactory<FloatType> factory = new ArrayImgFactory<>(new FloatType());
-//        Img <FloatType> c = Utils.gaussConvolution(  converted,factory, new double[]{1, 1, 0 } );
-        Img <FloatType> c = Filter2D.median( converted, 2 );
-        // Normalization
-       return Utils.normalizeImage( c, c.factory());
-    }
-
-    /**
-     *
-     * @param input
-     * @param factory
-     * @param <T>
-     * @return
-     */
-    private  < T extends RealType< T > & NativeType< T > > Pixels[][] maximumSearch( RandomAccessibleInterval< T > input,ImgFactory<T> factory )
-    {
-        /* Grid of amplitude thresholds */
-        Img< FloatType > amplitudeImg = MaximumAmplitudeClassification.find(input,factory,userParameters.getAmplitude() , 0.10);
-
-        ImageJFunctions.show( amplitudeImg," amplitude1" );
-
-        /* Grid of local thresholds*/
-        Img< BitType > thresholds = LocalOtsuClassification.find( input, factory, userParameters.getThreshold());
-
-        /* Pixel selection */
-        Img<FloatType> finalList = Threshold.classification( amplitudeImg, amplitudeImg.factory(), thresholds );
-
-        /* Isolated Pixel removal */
-        ImageJFunctions.show( finalList.copy(), "isolated pixel sel" );
-        /* Dilatation of the resulting image*/
-
-        double sigma = userParameters.getSigmas();
-
-        Utils.gaussConvolution( finalList.copy(), finalList, new double[]{ sigma, sigma, 1 } );
-        ImageJFunctions.show(finalList, "blurred maximums1" );
-
-        /* Local maximum detection due to previous smoothing*/
-        finalList = LocalExtremaDetection.findMaxima( finalList.copy(), finalList.factory() );
-        return buildPixelArray( finalList );
-    }
-
-    /**
-     *
-     * @param input
-     * @param factory
-     * @param <T>
-     * @return
-     */
-    private  < T  extends RealType< T > & NativeType< T >   >  Pixels[][] maximumSearch3( RandomAccessibleInterval< T > input,ImgFactory<T> factory )
-    {
-        /* Grid of amplitude thresholds */
-        Img< FloatType > amplitudeImg = MaximumAmplitudeClassification3.find(input,factory,userParameters.getAmplitude() , 0.10);
-
-//        ImageJFunctions.show( amplitudeImg," amplitude1" );
-
-        /* Grid of local thresholds*/
-        Img< BitType > thresholds = LocalOtsuClassification.find( input, factory, userParameters.getThreshold());
-
-        /* Pixel selection */
-        Img<FloatType> finalList = Threshold.classification( amplitudeImg, amplitudeImg.factory(), thresholds );
-
-        /* Isolated Pixel removal */
-
-//        ImageJFunctions.show( finalList.copy(), "isolated pixel sel" );//new ImgLabeling< FloatType, IntType >( labeling ),
-        /* Dilatation of the resulting image*/
-
-        double sigma = userParameters.getSigmas();
-
-        Utils.gaussConvolution( finalList.copy(), finalList, new double[]{ sigma, sigma, 1 } );
-//        ImageJFunctions.show(finalList, "blurred maximums1" );
-
-        /* Local maximum detection due to previous smoothing*/
-        finalList = LocalExtremaDetection.findMaxima( finalList.copy(), finalList.factory() );
-        return buildPixelArray( finalList );
-    }
-
-    private  < T extends RealType< T > & NativeType< T > > Pixels[][] maximumSearch2( RandomAccessibleInterval< T > input,ImgFactory<T> factory )
-    {
-        /* Grid of amplitude thresholds */
-        Img< BitType > amplitudeImg = MaximumAmplitudeClassification2.find(input,factory,userParameters.getAmplitude() );
-//        ImageJFunctions.show( amplitudeImg2," amplitude2" );
-
-        /* Grid of local thresholds*/
-        Img< BitType > thresholds = LocalOtsuClassification.find( input, factory, userParameters.getThreshold());
-
-        /* Pixel selection */
-        Img<BitType> finalList = Threshold.classification( amplitudeImg, amplitudeImg.factory(), thresholds );
-
-        /* Isolated Pixel removal */
-        finalList = IslandSearch.run( finalList, 5, 8 );
-        ImageJFunctions.show( finalList.copy(), "isolated pixel sel" );
-        Img< FloatType > converted = Utils.convertBitTypeIntoFloatType( finalList );
-
-        /* Dilatation of the resulting image*/
-        double sigma = userParameters.getSigmas();
-
-        Utils.gaussConvolution( converted.copy(), converted, new double[]{ sigma, sigma, 0 } );
-//        ImageJFunctions.show(converted, "blurred maximums2" );
-
-        /* Local maximum detection due to previous smoothing*/
-        converted = LocalExtremaDetection.findMaxima( converted.copy(), converted.factory() );
-        return buildPixelArray( converted );
-    }
-    /**
-     *
-     * @param stack
-     * @param <T>
-     * @return
-     */
-    public  < T extends RealType< T > & NativeType< T > > Pixels[][] buildPixelArray(
-            final RandomAccessibleInterval< T > stack )
-    {
-        RandomAccess< T > access = stack.randomAccess();
-        Pixels[][] pixels = new Pixels[ ( int ) stack.dimension( 1 ) ][ ( int ) stack.dimension( 0 ) ];
-        for ( int x = 0; x <= stack.dimension( 0 ) - 1; x++ )
-        {
-            for ( int y = 0; y <= stack.dimension( 1 ) - 1; y++ )
-            {
-                for ( int z = 0; z <= stack.dimension( 2 ) - 1; z++ )
-                {
-                    double value = Utils.setPositionAndGet( access, x, y, z ).getRealDouble();
-                    if ( value > 0 )
-                    {
-                        if ( pixels[ y ][ x ] == null )
-                        { // nothing yet
-                            pixels[ y ][ x ] = new Pixels( new Coordinate( x, y, z ) );
-                        }
-                        else // already at least two coordinates
-                        {
-                            pixels[ y ][ x ].add( new Coordinate( x, y, z ) );
-                        }
-                    }
-                }
-            }
-        }
-        return pixels;
-    }
-
-    /**
-     * Displays the local maximums found using jzy3D package.
-     */
-    public static void displayMaximums( Pixels[][] maximums )
-    {
-        try
-        {
-            LocalMaximumsDisplay localMaximumsDisplay = new LocalMaximumsDisplay( maximums );
-            AnalysisLauncher.open( localMaximumsDisplay );
-        }
-        catch ( Exception e )
-        {
-            e.printStackTrace();
-        }
-    }
-
-    public Pixels[][] getMaximums()
-    {
-        return maximums;
-    }
-}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/SurfacesReconstruction.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/SurfacesReconstruction.java
deleted file mode 100644
index 35b57ad6fbf2238ebbd6f80d07cfad71f7474cbd..0000000000000000000000000000000000000000
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/SurfacesReconstruction.java
+++ /dev/null
@@ -1,322 +0,0 @@
-package fr.pasteur.ida.zellige.surfaceConstruction.construction;
-
-
-import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSE;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEList;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine.SurfaceLine;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine.SurfaceLineX;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine.SurfaceLineY;
-
-import java.util.ArrayList;
-
-
-/**
- * Static methods to build Surface instances from OS.
- */
-public class SurfacesReconstruction
-{
-
-    private final ArrayList< Surface > surfaces = new ArrayList<>();
-    private final int dimension;
-    private final OSEList[] oseLists;
-    private final int surfaceLineLength;
-    private final double percent;
-    private final int k;
-
-    private int smallSurfaceCount;
-
-    public SurfacesReconstruction( int dimension, OSEList[] oseLists, int surfaceLineLength, double percent, int k )
-    {
-        this.dimension = dimension;
-        this.oseLists = oseLists;
-        this.surfaceLineLength = surfaceLineLength;
-        this.percent = percent;
-        this.k = k;
-    }
-
-    /**
-     * Returns a list of TempSurface constructed from the specified OSList array.
-     *
-     */
-    public void buildSurfaces()
-    {
-        // Construction of the list of output TempSurface.
-        smallSurfaceCount = 0;
-        int finalIndex = findIndexValue( 0 );
-        do
-        {
-            // All the OSLists are set to "not visited".
-            reset();
-            int startingIndex = finalIndex;
-            OSE firstOSE = getFirstOs( finalIndex );
-//            osLists[finalIndex].remove( firstOS );//TODO remove or not
-            if ( firstOSE != null )
-            {
-                Surface surface = createSurface( firstOSE, surfaceLineLength );
-                buildSurface(  surface, finalIndex );
-                //it is really a reference surface ?
-                if ( surface.getSize() >= surfaceLineLength * oseLists.length * 0.01 )
-                {
-                    surfaces.add( surface );
-                }
-                else
-                {
-                    smallSurfaceCount++;
-                    System.out.println( "searching.....from " );
-                }
-                finalIndex = findIndexValue( startingIndex );
-            }
-        }
-        while ( finalIndex <= oseLists.length - 2
-                && ( oseLists[ finalIndex ] != null
-                && ! oseLists[ finalIndex ].isEmpty()
-                && oseLists[ finalIndex ].containsAStart() ) );
-        System.out.println( "smallSurfaceCount = " + smallSurfaceCount );
-    }
-
-    /**
-     * Adds new SurfaceLine to a specified TempSurface.
-     *
-     * @param surface  - the TempSurface to construct
-     * @param index    - the position in the TempSurface
-     */
-    private void buildSurface(  Surface surface, int index )
-    {
-        /* First round of the construction -> top to bottom in the dimension.*/
-        SurfaceLine current = surface.get( index );
-        SurfaceLine next;
-        while ( current != null )
-        {
-            next = searchForward( current );
-            if ( next != null )
-            {
-                surface.set( next.getLine(), next );
-            }
-            current = next;
-        }
-
-        /* Second round of the construction -> top to bottom to top until  every OS has been visited.*/
-        int size = 0;
-        while ( size != surface.getSize() )
-        {
-            size = surface.getSize();
-            for ( int i = surface.getHeight() - 1; i > 0; i-- )
-            {
-                if ( surface.get( i ) != null )
-                {
-                    SurfaceLine previous = searchBackward( surface.get( i ) );
-                    if ( previous != null )
-                    {
-                        if ( surface.get( i - 1 ) != null )
-                        {
-                            surface.get( i - 1 ).merge( previous );
-                        }
-                        else
-                        {
-                            surface.set( i - 1, previous );
-                        }
-                    }
-                }
-            }
-            for ( int i = 0; i <= surface.getHeight() - 2; i++ )
-            {
-                if ( surface.get( i ) != null )
-                {
-                    next = searchForward( surface.get( i ) );
-                    if ( next != null )
-                    {
-                        if ( surface.get( i + 1 ) != null )
-                        {
-                            surface.get( i + 1 ).merge( next );
-                        }
-                        else
-                        {
-                            surface.set( i + 1, next );
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-
-    /**
-     * @param firstOSE  - the first surface element.
-     * @return a surface as a {@link Surface}
-     */
-    private Surface createSurface( OSE firstOSE, int surfaceLineLength )
-    {
-        Surface surface = new Surface( dimension, oseLists.length );
-
-        int i;
-        if ( dimension == 0 )
-        {
-            i = firstOSE.get( 0 ).getY();
-            surface.set( i, new SurfaceLineX( surfaceLineLength, firstOSE ) );
-        }
-        else
-        {
-            i = firstOSE.get( 0 ).getX();
-            surface.set( i, new SurfaceLineY( surfaceLineLength, firstOSE ) );
-        }
-        return surface;
-    }
-
-    /**
-     * Returns the index value of the first OSList containing a starting OS.
-     *
-     * @param index    - the previous index value
-     * @return the value of the first OSList containing a starting OS
-     */
-    private int findIndexValue( int index )
-    {
-        int i = index;
-        int limitValue;
-        limitValue = oseLists.length - 1;
-        while ( i <= limitValue - 2 )
-        {
-            if ( oseLists[ i ] != null
-                    && ! oseLists[ i ].isEmpty()
-                    && oseLists[ i ].containsAStart() )
-            {
-                return i;
-            }
-            i++;
-        }
-        index = limitValue;
-        return index;
-    }
-
-    /**
-     * Returns the first OS with a start status in the OSList array.
-     *
-     * @param index the previous index value
-     * @return the first OS with a true Start status
-     */
-    private OSE getFirstOs( int index )
-    {
-        for ( OSE os : oseLists[ index ] )
-        {
-            if ( os.isAStart() )
-            {
-                os.setVisited();
-                return os;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns the SurfaceLine matching the current in a specific direction
-     *
-     * @param next        - the OSList to search into
-     * @param currentLine - the {@link SurfaceLine } to match.
-     * @param j           - the direction of the search (1 or -1)
-     * @return the OSList matching SurfaceLine
-     */
-    private SurfaceLine search( OSEList next, SurfaceLine currentLine, int j )
-    {
-        ArrayList< SurfaceLine > list = new ArrayList<>();
-        for ( OSE os : next )
-        {
-
-            if ( ! os.isVisited() ) // The OS is already added to the referenceSurface
-            {
-                SurfaceLine line = currentLine.match( os, j, percent, k );
-                if ( line != null )
-                {
-                    list.add( line );
-                }
-            }
-        }
-        if ( list.size() == 0 )
-        {
-            return null;
-        }
-        else
-        {
-            merge( list );
-            return list.get( 0 );
-        }
-    }
-
-    /**
-     * Returns the SurfaceLine generated from the specified OSList array matching the current SurfaceLine
-     *
-     * @param current  - the {@link SurfaceLine } to match
-     * @return the SurfaceLine generated from the specified OSList array matching the current SurfaceLine
-     */
-    private SurfaceLine searchForward( SurfaceLine current )
-    {
-
-        if ( current.getLine() + 1 <= oseLists.length - 1 )
-        {
-            return search( oseLists[ current.getLine() + 1 ], current, 1 );
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    /**
-     * @param current  - the current SurfaceLine to match with.
-     * @return - the matching SurfaceLine.
-     */
-    private SurfaceLine searchBackward( SurfaceLine current )
-    {
-        if ( current.getCoordinatesNumber() != 0 && current.getLine() > 0 )
-        {
-            return search( oseLists[ current.getLine() - 1 ], current, - 1 );
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    /**
-     * Merges the SurfaceLine objects in the specified list.
-     *
-     * @param list - the list to merge.
-     */
-    private void merge( ArrayList< SurfaceLine > list )
-    {
-        if ( list.size() >= 2 ) //more than one SurfaceLine
-        {
-            int index = list.size() - 1;
-            while ( list.size() != 1 )
-            {
-                list.get( index - 1 ).merge( list.remove( index ) );
-                index--;
-            }
-        }
-    }
-
-
-    /**
-     * Resets the "visited" value of each OS of each OSList to FALSE.
-     *
-     */
-    private void reset()
-    {
-        for ( OSEList oseList : oseLists )
-        {
-            if ( oseList != null )
-            {
-                oseList.reset();
-            }
-        }
-    }
-
-    public int getSmallSurfaceCount()
-    {
-        return smallSurfaceCount;
-    }
-
-    public ArrayList< Surface > getSurfaces()
-    {
-        return surfaces;
-    }
-}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/ConstructionPipeline.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/ConstructionPipeline.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b1a1f8ebba05dd21919016ced867fba49539835
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/ConstructionPipeline.java
@@ -0,0 +1,73 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound;
+
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection.Util;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.ose.OseConstructionXZ;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.ose.OseConstructionYZ;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.surface.AllSurfaceConstruction;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEListArray;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ConstructionParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+
+public class ConstructionPipeline
+{
+    private final static Logger LOGGER = LoggerFactory.getLogger( ConstructionPipeline.class );
+
+    public static final int DIMENSION = 0;
+    private final Pixels[][] maximums;
+    private final double startingSizeThreshold;
+    private final int overlap;
+    private final double connexityRate;
+    private final ArrayList< Surface > surfaces;
+    private final int dimension;
+
+
+
+
+    public static  ArrayList<Surface> run(  Pixels[][] maximums, int dimension, ConstructionParameters constructionParameters )
+    {
+        ConstructionPipeline pipeline = new ConstructionPipeline( maximums, dimension, constructionParameters );
+        pipeline.run();
+        return pipeline.surfaces;
+    }
+
+
+    public ConstructionPipeline( Pixels[][] maximums, int dimension, ConstructionParameters constructionParameters )
+    {
+        this.maximums = maximums;
+        this.dimension = dimension;
+        this.startingSizeThreshold = constructionParameters.getStartingSizeThreshold();
+        this.overlap = constructionParameters.getOverlap();
+        this.connexityRate = constructionParameters.getConnexityRate();
+        this.surfaces = new ArrayList<>();
+    }
+
+    public void run()
+    {
+        LOGGER.info("Processing...");
+        /* OSE construction according to the dimension considered */
+        OSEListArray oseLists = constructOSE( );
+
+        /* Construction of surfaces*/
+        LOGGER.info("Starting surface construction...");
+        int lineLength = maximums[0].length;
+        this.surfaces.addAll( AllSurfaceConstruction.run( oseLists, lineLength, overlap, connexityRate ));
+        LOGGER.info("Completed");
+    }
+
+    private OSEListArray constructOSE( )
+    {
+        if ( dimension == DIMENSION )
+        {
+            return OseConstructionXZ.runConstruction( maximums, startingSizeThreshold );
+        }
+        else
+        {
+            return OseConstructionYZ.runConstruction( maximums, startingSizeThreshold );
+        }
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/ConstructionRound.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/ConstructionRound.java
new file mode 100644
index 0000000000000000000000000000000000000000..6c73495b7398fbdedbf972e896946f7e0b5d8f37
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/ConstructionRound.java
@@ -0,0 +1,56 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound;
+
+import fr.pasteur.ida.zellige.exception.NoSurfaceFoundException;
+import fr.pasteur.ida.zellige.jzy3D.OSDisplay;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEList;
+import org.jzy3d.analysis.AnalysisLauncher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+
+public class ConstructionRound
+{
+    private final static Logger LOGGER = LoggerFactory.getLogger( ConstructionRound.class );
+
+    void finalizeSurface(ArrayList<Surface> surfaces) throws NoSurfaceFoundException
+    {
+        if ( ! surfaces.isEmpty() )
+        {
+            mergeReferenceSurface( surfaces );
+        }
+        else
+        {
+            System.out.println( "No Surface Exception" );
+            throw new NoSurfaceFoundException();
+        }
+    }
+
+    /**
+     * Merges the TempSurface objects of the specified list.
+     *
+     * @param surfaces - the list to merge
+     */
+     void mergeReferenceSurface( ArrayList< Surface > surfaces )
+    {
+        LOGGER.info("Merging surfaces....");
+        // Merging step.
+        ArrayList< Surface > toRemoved = new ArrayList<>();
+        for ( int i = surfaces.size() - 1; i > 0; i-- )
+        {
+            Surface one = surfaces.get( i );
+            for ( int j = i - 1; j >= 0; j-- )
+            {
+                Surface two = surfaces.get( j );
+                if ( one.sameSurface( two ) )
+                {
+                    two.merge( one );
+                    toRemoved.add( one );
+                }
+            }
+        }
+        surfaces.removeAll( toRemoved );
+        LOGGER.info("Merging completed");
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/FirstRoundConstruction.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/FirstRoundConstruction.java
new file mode 100644
index 0000000000000000000000000000000000000000..55b16d837621986c8d90e7042780768b99cd4303
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/FirstRoundConstruction.java
@@ -0,0 +1,42 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound;
+
+import fr.pasteur.ida.zellige.exception.NoSurfaceFoundException;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ConstructionParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+
+public class FirstRoundConstruction extends ConstructionRound
+{
+    private final static Logger LOGGER = LoggerFactory.getLogger( FirstRoundConstruction.class );
+
+    private static final int DIMENSION = 0;
+    private final Pixels[][] maximums;
+    private final ConstructionParameters constructionParameters;
+    private final ArrayList< Surface > surfaces;
+
+    public static ArrayList< Surface> run(Pixels[][] maximums, ConstructionParameters constructionParameters) throws NoSurfaceFoundException
+    {
+        FirstRoundConstruction round = new FirstRoundConstruction( maximums, constructionParameters );
+        round.process();
+        return round.surfaces;
+    }
+
+    public FirstRoundConstruction( Pixels[][] maximums, ConstructionParameters constructionParameters )
+    {
+        this.maximums = maximums;
+        this.constructionParameters= constructionParameters;
+        this.surfaces = new ArrayList<>();
+    }
+
+    public void  process() throws NoSurfaceFoundException
+    {
+        LOGGER.info("Processing...");
+        surfaces.addAll( ConstructionPipeline.run(maximums, DIMENSION, constructionParameters ));
+        this.finalizeSurface( surfaces );
+        LOGGER.info("Round completed");
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/OSEStartingStatus.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/OSEStartingStatus.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3d86816e9ed36245626e60037b54ce377b02b7c
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/OSEStartingStatus.java
@@ -0,0 +1,39 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.TreeMap;
+
+public class OSEStartingStatus extends TreeMap<Integer, Integer>
+{
+    private final static Logger LOGGER = LoggerFactory.getLogger( OSEStartingStatus.class );
+
+    private int startingSize;
+    private final double threshold;
+
+    public OSEStartingStatus( double threshold )
+    {
+        this.threshold = threshold;
+        LOGGER.info( "OSE starting threshold = {}", threshold);
+    }
+
+    public  void setStartingStatus()
+    {
+        if (this.size() != 0)
+        {
+            {
+                for ( int i = 0; this.size() > 20 && i <= this.size()* threshold ;i++ )
+                {
+                    this.remove( this.lastKey() );
+                }
+            }
+            this.startingSize = this.lastKey() ;
+            LOGGER.info("Starting OSE size = {}", startingSize);
+        }}
+
+    public int getStartingSize()
+    {
+        return startingSize;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/SecondRoundConstruction.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/SecondRoundConstruction.java
new file mode 100644
index 0000000000000000000000000000000000000000..df991c90c062cd1dc0037e1e22510c77e3ba2613
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/SecondRoundConstruction.java
@@ -0,0 +1,91 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound;
+
+import fr.pasteur.ida.zellige.exception.NoSurfaceFoundException;
+import fr.pasteur.ida.zellige.exception.SecondRoundConstructionException;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine.SurfaceLine;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ConstructionParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+
+public class SecondRoundConstruction extends ConstructionRound
+{
+    private final static Logger LOGGER = LoggerFactory.getLogger( SecondRoundConstruction.class );
+
+    private final ConstructionParameters constructionParameters;
+    private final ArrayList< Surface > tempSurfaces;
+    private final ArrayList< Surface > finalSurfaces;
+    private static final int DIMENSION = 1;
+
+    public SecondRoundConstruction( ArrayList< Surface > tempSurfaces, ConstructionParameters constructionParameters )
+    {
+       this.constructionParameters = constructionParameters;
+       this.tempSurfaces = tempSurfaces;
+       this.finalSurfaces = new ArrayList<>();
+
+    }
+
+    public static ArrayList< Surface> run( ArrayList< Surface > tempSurfaces, ConstructionParameters constructionParameters) throws NoSurfaceFoundException
+    {
+       SecondRoundConstruction round = new SecondRoundConstruction( tempSurfaces, constructionParameters );
+        round.process();
+        return round.finalSurfaces;
+    }
+
+    public void  process() throws NoSurfaceFoundException
+    {
+        LOGGER.info("Starting process...");
+        for ( Surface surface : tempSurfaces )
+        {
+            if ( surface.hasDuplicate() )// CoordinateList instead of Coordinate
+            {
+                Pixels[][] maximums = rebuildMaximums( surface );
+                ArrayList< Surface > temps = ConstructionPipeline.run( maximums, DIMENSION, constructionParameters );
+                if ( temps.isEmpty() )
+                {
+                    System.out.println( "small surface in second round" );
+                    throw new SecondRoundConstructionException();
+                }
+                else
+                {
+                    finalSurfaces.addAll( temps );
+                }
+            }
+            else
+            {
+                finalSurfaces.add( surface.transpose() );
+            }
+        }
+        LOGGER.info("Process completed.");
+    }
+
+    /**
+     * Rebuilds the double pixel array from the {@link SurfaceLine} array
+     * of a {@link Surface} for a construction in the height dimension.
+     *
+     * @param surface - the {@link SurfaceLine}  array of a {@link Surface}
+     * @return a {@link Surface} specific double pixel array.
+     */
+    private  Pixels[][] rebuildMaximums( Surface surface )
+    {
+        LOGGER.info("Rebuilding surface...");
+        int width = surface.getHeight();
+        int height = surface.getWidth();
+        Pixels[][] tempCoordinates = new Pixels[ height ][ width ]; // Transposed array
+        for ( int i = 0; i <= width - 1; i++ )
+        {
+            for ( int j = 0; j <= height - 1; j++ )
+            {
+                if ( surface.get( i ) != null )
+                {
+                    tempCoordinates[ j ][ i ] = surface.get( i ).get( j );
+                }
+            }
+        }
+        LOGGER.info("Surface rebuild.");
+        return tempCoordinates;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/constructSurface/ConstructionRounds.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/constructSurface/ConstructionRounds.java
new file mode 100644
index 0000000000000000000000000000000000000000..3d72d2f37350c2b22599b11ff1f813af85ba4b45
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/constructionRound/constructSurface/ConstructionRounds.java
@@ -0,0 +1,48 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound.constructSurface;
+
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound.FirstRoundConstruction;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound.SecondRoundConstruction;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ConstructionParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+
+public class ConstructionRounds
+{
+    private final static Logger LOGGER = LoggerFactory.getLogger( ConstructionRounds.class );
+
+    public static final double adequacy = 0.02;
+    private final ArrayList< Surface > referenceSurfaces = new ArrayList<>();
+
+
+    public void process( Pixels[][] maximums, ConstructionParameters[] constructionParameters)
+    {
+        LOGGER.info("Starting rounds...");
+        LOGGER.info( "Adequacy value = {}", adequacy);
+        try
+        {
+            /*  First round construction*/
+            ArrayList< Surface > tempSurfaces = FirstRoundConstruction.run( maximums, constructionParameters[0] );
+            System.out.println( "first round surfaces = " + tempSurfaces.size() );
+//            for(Surface s : tempSurfaces)
+//            {
+//                displaySurface( s );
+//            }
+            /* Second round construction */
+            referenceSurfaces.addAll(   SecondRoundConstruction.run( tempSurfaces, constructionParameters[1] ));
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+        }
+        LOGGER.info("Rounds completed.");
+    }
+
+    public ArrayList< Surface > getReferenceSurfaces()
+    {
+        return referenceSurfaces;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/utils/LocalExtremaDetection.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/LocalExtremaDetection.java
similarity index 68%
rename from src/main/java/fr/pasteur/ida/zellige/utils/LocalExtremaDetection.java
rename to src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/LocalExtremaDetection.java
index 0127fe3e74116e9db6fec4278af12c3e2b5b280b..06f4f991ca48f0e2547fc99fc7a98838277b8cbe 100644
--- a/src/main/java/fr/pasteur/ida/zellige/utils/LocalExtremaDetection.java
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/LocalExtremaDetection.java
@@ -1,53 +1,37 @@
-package fr.pasteur.ida.zellige.utils;
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection;
 
 import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.utils.Utils;
 import net.imglib2.RandomAccess;
 import net.imglib2.RandomAccessibleInterval;
 import net.imglib2.img.Img;
 import net.imglib2.img.ImgFactory;
-import net.imglib2.img.display.imagej.ImageJFunctions;
 import net.imglib2.type.NativeType;
 import net.imglib2.type.numeric.RealType;
 import net.imglib2.view.IntervalView;
 import net.imglib2.view.Views;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-public class LocalExtremaDetection
+class LocalExtremaDetection < T extends RealType< T > & NativeType< T > >
 {
 
+    //TODO review implementation (multithreading)
 
-    public static < T extends RealType< T > & NativeType< T > > Img< T > findMinima( RandomAccessibleInterval< T > input,
-                                                                                     ImgFactory< T > factory )
-    {
-        Img< T > minima = factory.create( input.dimension( 0 ), input.dimension( 1 ), input.dimension( 2 ) );
-        new LocalExtremaDetectionOperator<>( input, factory, minima, "min" );
-        return minima;
-    }
-
-
-    public static < T extends RealType< T > & NativeType< T > > Img< T > findMaxima( RandomAccessibleInterval< T > input,
-                                                                                     ImgFactory< T > factory )
-    {
-        Img< T > maxima = factory.create( input.dimension( 0 ), input.dimension( 1 ), input.dimension( 2 ) );
-        new LocalExtremaDetectionOperator<>( input, factory, maxima, "max" );
-        return maxima;
-    }
-
-    private static class LocalExtremaDetectionOperator< T extends RealType< T > & NativeType< T > >
-    {
-
+        public static final String MAX = "max";
         private final RandomAccessibleInterval< T > input;
         private final ImgFactory< T > factory;
-        private final RandomAccessibleInterval< T > output;
+        private final Img< T > extrema;
         private final String type;
 
-        public LocalExtremaDetectionOperator( RandomAccessibleInterval< T > input, ImgFactory< T > factory,
-                                              RandomAccessibleInterval< T > output, String type )
+    private final static Logger LOGGER = LoggerFactory.getLogger( LocalExtremaDetection.class );
+
+         LocalExtremaDetection( RandomAccessibleInterval< T > input, ImgFactory< T > factory, String type )
         {
             this.input = input;
             this.factory = factory;
-            this.output = output;
+            this.extrema = factory.create( input );
             this.type = type;
-            findExtrema();
         }
 
         /**
@@ -55,9 +39,10 @@ public class LocalExtremaDetection
          * according to given local and global thresholds by first using a gaussian blur.
          * The local maximums are stored in a 2D {@link Pixels} array.
          */
-        private void
+        public void
         findExtrema()
         {
+            LOGGER.info("Starting detection...");
             // For each individual orthogonal XZ sections.*/
             for ( int x = 0; x <= input.dimension( 0 ) - 1; x++ )// iteration on dimension X
             {
@@ -66,16 +51,16 @@ public class LocalExtremaDetection
                     // The YZ section.
                     IntervalView< T > intervalView = Views.hyperSlice( this.input, 0, x );
                     // Each maximum found is stored in double Pixel array .
-                    getExtrema( intervalView, x );
+                    setExtrema( intervalView, x );
                 }
                 catch ( Exception e )
                 {
                     e.printStackTrace();
                 }
             }
+            LOGGER.info("Extrema detected.");
         }
 
-
         /**
          * Finds all the local maximums of an 2D image,
          * according to given local and global thresholds by first using a gaussian blur and then a partial derivative
@@ -85,14 +70,14 @@ public class LocalExtremaDetection
          * @param x            - the index of the orthogonal section AKA the stack index in dimension X.
          */
         private void
-        getExtrema( RandomAccessibleInterval< T > YZProjection, int x )
+        setExtrema( RandomAccessibleInterval< T > YZProjection, int x )
         {
             // Output for partial derivative.
             // Addition of one supplementary line, in case the last slice contains some local maximums
-            RandomAccessibleInterval< T > partialDerivative = factory.create(YZProjection);
+            RandomAccessibleInterval< T > partialDerivative = factory.create( YZProjection );
             // Partial derivative computation */
             Utils.derivative( YZProjection, partialDerivative );
-            getExtrema( partialDerivative, YZProjection, x );
+            setExtrema( partialDerivative, YZProjection, x );
         }
 
 
@@ -101,17 +86,17 @@ public class LocalExtremaDetection
          * @param x                 the index in dimension X
          */
         private void
-        getExtrema
+        setExtrema
         ( RandomAccessibleInterval< T > partialDerivative, RandomAccessibleInterval< T > original, int x )
         {
             RandomAccess< T > derivativeAccess = Views.extendMirrorSingle( partialDerivative ).randomAccess();
-            RandomAccess< T > maxAccess = output.randomAccess();
+            RandomAccess< T > maxAccess = extrema.randomAccess();
             RandomAccess< T > oriAccess = original.randomAccess();
 
-            for ( int y = 0; y <= output.dimension( 1 ) - 1; y++ )
+            for ( int y = 0; y <= extrema.dimension( 1 ) - 1; y++ )
             {
                 derivativeAccess.setPosition( y, 0 );
-                for ( int z = 0; z <= output.dimension( 2 ) - 1; z++ )
+                for ( int z = 0; z <= extrema.dimension( 2 ) - 1; z++ )
                 {
                     if ( isALocalExtrema( derivativeAccess, z ) )
                     {
@@ -140,7 +125,7 @@ public class LocalExtremaDetection
             final double tZero = derivative.get().getRealDouble();
             derivative.setPosition( ( z + 1 ), 1 );
             final double tOne = derivative.get().getRealDouble();
-            if ( type.equals( "max" ) )
+            if ( type.equals( MAX ) )
             {
                 return ( tZero >= 0 && tOne < 0 );
             }
@@ -149,6 +134,10 @@ public class LocalExtremaDetection
                 return ( tZero < 0 && tOne >= 0 );
             }
         }
-
+        public Img< T > getExtrema()
+        {
+            return extrema;
+        }
     }
-}
+
+
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/LocalOtsuClassification.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/LocalOtsuClassification.java
new file mode 100644
index 0000000000000000000000000000000000000000..bbec02a7be814420d65d78d8efb4c25bbc297b3c
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/LocalOtsuClassification.java
@@ -0,0 +1,130 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection;
+
+import fr.pasteur.ida.zellige.utils.Otsu;
+import fr.pasteur.ida.zellige.utils.Threshold;
+import fr.pasteur.ida.zellige.utils.Utils;
+import net.imglib2.*;
+import net.imglib2.algorithm.util.Grids;
+import net.imglib2.img.Img;
+import net.imglib2.img.ImgFactory;
+import net.imglib2.img.display.imagej.ImageJFunctions;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.logic.BitType;
+import net.imglib2.type.numeric.RealType;
+import net.imglib2.view.IntervalView;
+import net.imglib2.view.Views;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class LocalOtsuClassification< T extends RealType< T > & NativeType< T > >
+{
+
+    private final RandomAccessibleInterval< T > source;
+    private final ImgFactory< T > factory;
+    private final RandomAccessibleInterval< T > grid;
+    private final Img< BitType > binary;
+    private final double percent;
+
+    private final static Logger LOGGER = LoggerFactory.getLogger( LocalOtsuClassification.class );
+
+    /**
+     * @param source  the input {@link Img}
+     * @param binary  the resulting binary image as a {@link Img<BitType> }
+     * @param percent the percentage of global otsu value
+     */
+   LocalOtsuClassification( final RandomAccessibleInterval< T > source, final ImgFactory< T > factory, final Img< BitType > binary, double percent )
+    {
+        this.source = source;
+        this.factory = factory;
+        this.binary = binary;
+        this.percent = percent;
+        this.grid = factory.create( source );
+    }
+
+    /**
+     * @param input the input {@link Img}
+     * @param grid  the image containing the grid of local thresholds
+     */
+    public   void
+    computeLocalThreshold( RandomAccessibleInterval< T > input, ImgFactory< T > factory, RandomAccessibleInterval< T > grid )
+    {
+        long width = input.dimension( 0 );
+        long height = input.dimension( 1 );
+        long depth = input.dimension( 2 );
+        List< Interval > intervals = Grids.collectAllContainedIntervals( new long[]{ width, height, depth },
+                new int[]{ 50, 50, 3 } );//TODO Size of a grid cube ?
+
+        for ( Interval interval : intervals )
+        {
+            computeLocalThreshold( input, grid, interval );
+        }
+        grid = Utils.gaussConvolution( grid, factory, new double[]{ 5, 5, 1 } );
+        LOGGER.info("Local thresholds computed with user value  = {}.", this.percent);
+    }
+
+    public  void
+    computeLocalThreshold( RandomAccessibleInterval< T > input, RandomAccessibleInterval< T > grid, Interval interval )
+    {
+        IntervalView< T > viewSource = Views.offsetInterval( input, interval );
+        IntervalView< T > viewGrid = Views.offsetInterval( grid, interval );
+        T threshold = Otsu.getThreshold( viewSource );
+        viewGrid.forEach( pixel -> pixel.set( threshold ) );
+
+    }
+
+    /**
+     * @param input   the input image as an {@link IterableInterval}
+     * @param grid    the image containing the grid of local thresholds as an {@link IterableInterval}
+     * @param binary  the resulting binary image as a {@link RandomAccessibleInterval<BitType> }
+     * @param percent the percentage of global otsu value
+     * @param <T>     the input type
+     */
+    public static < T extends RealType< T > & NativeType< T > > void
+    applyLocalThreshold( IterableInterval< T > input, IterableInterval< T > grid, RandomAccessibleInterval< BitType > binary, double percent )
+    {
+        double threshold = Threshold.getThreshold( input, percent ).getRealDouble();
+        Cursor< T > sourceCursor = input.localizingCursor();
+        Cursor< T > outputCursor = grid.cursor();
+        RandomAccess< BitType > randomAccess = binary.randomAccess();
+        while ( sourceCursor.hasNext() )
+        {
+            sourceCursor.fwd();
+            outputCursor.fwd();
+            final double s = sourceCursor.get().getRealDouble();
+            final double o = outputCursor.get().getRealDouble();
+            {
+                if ( s >= Math.max( o, threshold ) )// background subtraction
+                {
+                    randomAccess.setPosition( sourceCursor );
+                    randomAccess.get().set( true );
+                }
+            }
+        }
+        LOGGER.info("Local thresholds applied.");
+    }
+
+    /**
+     *
+     */
+    void run()
+    {
+        computeLocalThreshold( source, factory, grid );
+        applyLocalThreshold( Views.iterable( source ), Views.iterable( grid ), binary, percent );
+    }
+
+    /**
+     * @return the image containing the grid of local thresholds
+     */
+    public Img< BitType > getGrid()
+    {
+        return binary;
+    }
+}
+
+
+
+
+
+
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/MaximumAmplitudeClassification.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/MaximumAmplitudeClassification.java
new file mode 100644
index 0000000000000000000000000000000000000000..957672b429dbf0a6b8776ceaa537fdf4738c6f5e
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/MaximumAmplitudeClassification.java
@@ -0,0 +1,168 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection;
+
+import fr.pasteur.ida.zellige.exception.EmptyOutputException;
+import fr.pasteur.ida.zellige.jzy3D.LocalMaximumsDisplay;
+import fr.pasteur.ida.zellige.utils.Threshold;
+import net.imglib2.RandomAccess;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.algorithm.binary.Thresholder;
+import net.imglib2.img.Img;
+import net.imglib2.img.ImgFactory;
+import net.imglib2.img.display.imagej.ImageJFunctions;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.logic.BitType;
+import net.imglib2.type.numeric.RealType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static fr.pasteur.ida.zellige.utils.Threshold.findMin;
+
+/**
+ * This class makes it possible to get a binary classification of the pixels (background/ foreground) according to their amplitude and their amplitude's neighborhood.
+ * First, the amplitude of all local maximums is computed and stored as an {@link Img}.This class generate a binary image according to a percentage of the smallest mode value  of the input image
+ * @param <T> the type of the input {@link Img}
+ */
+public class MaximumAmplitudeClassification< T extends RealType< T > & NativeType< T > >
+{
+
+    private final RandomAccessibleInterval< T > input;
+    private final ImgFactory< T > factory;
+    private final double userAmplitudeThreshold;
+    private Img< BitType > amplitude;
+
+    private final static Logger LOGGER = LoggerFactory.getLogger( MaximumAmplitudeClassification.class );
+    public MaximumAmplitudeClassification( RandomAccessibleInterval< T > input,
+                                           ImgFactory< T > factory, Img< BitType > amplitude,
+                                           double userAmplitudeThreshold ) throws EmptyOutputException
+    {
+        this.input = input;
+        this.factory = factory;
+        this.amplitude = amplitude;
+        this.userAmplitudeThreshold = userAmplitudeThreshold;
+        LOGGER.info("User input = {}", userAmplitudeThreshold);
+    }
+
+    /**
+     * @param max the image containing only the values of local maximums
+     * @param min the image containing only the values of local minimums
+     * @return an image containing the value of the maximums amplitude
+     */
+    private  Img< T > getAmplitude(
+            RandomAccessibleInterval< T > max, ImgFactory< T > factory, RandomAccessibleInterval< T > min )
+    {
+        Img< T > amp = factory.create( max );
+        RandomAccess< T > maxAccess = max.randomAccess();
+        RandomAccess< T > minAccess = min.randomAccess();
+        RandomAccess< T > ampAccess = amp.randomAccess();
+        for ( int x = 0; x <= max.dimension( 0 ) - 1; x++ )
+        {
+            maxAccess.setPosition( x, 0 );
+            for ( int y = 0; y <= max.dimension( 1 ) - 1; y++ )
+            {
+                maxAccess.setPosition( y, 1 );
+                for ( int z = 0; z <= max.dimension( 2 ) - 1; z++ )
+                {
+                    maxAccess.setPosition( z, 2 );
+                    double maxValue = maxAccess.get().getRealDouble();
+                    if ( maxValue != 0 )
+                    {
+                        minAccess.setPosition( maxAccess );
+                        double amplitude = getAmplitude( maxValue, minAccess, ( int ) max.dimension( 2 ) );
+                        ampAccess.setPosition( maxAccess );
+                        ampAccess.get().setReal( amplitude );
+                    }
+                }
+            }
+        }
+//        ImageJFunctions.show( amp, "amplitude" );
+        return amp;
+    }
+
+    /**
+     * @param maxValue  the intensity value at local maximum positioned at minAccess location
+     * @param minAccess - the random access positioned at  the same specific local maximum location
+     * @return the chosen amplitude value of the local maximum positioned at minAccess location
+     */
+    private   double getAmplitude( double maxValue, RandomAccess< T > minAccess, int depth )
+    {
+        double up = findValueUp( minAccess, maxValue );
+        double down = findValueDown( minAccess, maxValue, depth );
+        double result = Math.max( Math.abs( maxValue - up ), Math.abs( maxValue - down ) );
+        if ( result == 0 )
+        {
+            return maxValue;
+
+        }
+        return ( result );
+    }
+
+    /**
+     * @param minAccess the random access of the local minimum image
+     * @param maxValue  the intensity value of the local maximum located at minAccess position
+     * @return the amplitude value above the local maximum location in the Z dimension
+     */
+    private double findValueUp(
+            RandomAccess< T > minAccess, double maxValue )
+    {
+        int start = minAccess.getIntPosition( 2 );
+        for ( int z = start - 1; z >= 0; z-- )
+        {
+            minAccess.setPosition( z, 2 );
+            double value = minAccess.get().getRealDouble();
+            if ( value != 0 )
+            {
+                return value;
+            }
+        }
+        return maxValue;
+    }
+
+    /**
+     * @param minAccess the random access of the local minimum image
+     * @param maxValue  the intensity value of the local maximum located at minAccess position
+     * @return the amplitude value below the local maximum location in the Z dimension
+     */
+    private double findValueDown(
+            RandomAccess< T > minAccess, double maxValue, int depth )
+    {
+        int start = minAccess.getIntPosition( 2 );
+        for ( int z = start + 1; z <= depth - 1; z++ )
+        {
+            minAccess.setPosition( z, 2 );
+            double value = minAccess.get().getRealDouble();
+            if ( value != 0 )
+            {
+                return value;
+            }
+        }
+        return maxValue;
+    }
+
+    public void runClassification() throws EmptyOutputException
+    {
+        Img< T > maximums = Util.findMaxima( input, factory );
+        Img< T > minimums = Util.findMinima( input, factory );
+        Img< T > amp = getAmplitude( maximums, factory, minimums );
+        T TMax = Threshold.getFirstMaxValue( maximums, false );
+        LOGGER.info( "threshold value before user = {} ", TMax );
+        TMax.mul( userAmplitudeThreshold );
+        LOGGER.info( "Threshold value after user = {}", TMax );
+//            checkOutput( amp, TMax );
+        amplitude =  Thresholder.threshold( amp.copy(), TMax, true, 2 );
+    }
+
+    private void checkOutput( Img< T > amp, T finalThreshold ) throws EmptyOutputException
+    {
+        double min = findMin( amp, true ).getRealDouble();
+        if ( min > finalThreshold.getRealDouble() )
+        {
+            throw new EmptyOutputException( "The amplitude image is empty" );
+        }
+    }
+
+    public Img< BitType > getAmplitude()
+    {
+        return amplitude;
+    }
+}
+
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PixelClassification.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PixelClassification.java
new file mode 100644
index 0000000000000000000000000000000000000000..d48f067caab643eb00dba995652542dbe38c7992
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PixelClassification.java
@@ -0,0 +1,121 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection;
+
+import fr.pasteur.ida.zellige.exception.EmptyOutputException;
+import fr.pasteur.ida.zellige.exception.NoClassificationException;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelClassificationParameters;
+import net.imglib2.Cursor;
+import net.imglib2.IterableInterval;
+import net.imglib2.RandomAccess;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.img.Img;
+import net.imglib2.img.ImgFactory;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.logic.BitType;
+import net.imglib2.type.numeric.RealType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class allows the double classification of a 3D image using in parallel a classification based on the amplitude
+ * of the image local maxima and a classification based on the local intensity. The final classification is the
+ * intersection of both. Each classification is parametrized by a value provided by the user.
+ *
+ * @param <T>
+ */
+public class PixelClassification< T extends RealType< T > & NativeType< T > >
+{
+    private final static Logger LOGGER = LoggerFactory.getLogger( PixelClassification.class );
+
+
+    public static final int ZERO = 0;
+    Img< BitType > output;
+
+
+
+    PixelClassification() {}
+
+    /**
+     * @param input      the 3D image to classified
+     * @param factory    - the input {@link ImgFactory}
+     * @param parameters - the user parameters to set the classifications
+     */
+    public void process( RandomAccessibleInterval< T > input, ImgFactory< T > factory, PixelClassificationParameters parameters ) throws EmptyOutputException, NoClassificationException
+    {
+        LOGGER.info("Starting classification...");
+        double amplitudeThreshold = parameters.getAmplitudeThreshold();
+        double otsuThreshold = parameters.getOtsuThreshold();
+        if ( amplitudeThreshold != ZERO && otsuThreshold != ZERO )
+        {
+          processBothClassification( input, factory, amplitudeThreshold, otsuThreshold );
+        }
+        else if ( amplitudeThreshold != ZERO )
+        {
+           processAmplitudeClassification( input, factory, amplitudeThreshold );
+        }
+        else if ( otsuThreshold != ZERO )
+        {
+           processOtsuClassification( input, factory, otsuThreshold );
+        }
+        else
+        {
+            throw new NoClassificationException();
+        }
+        LOGGER.info("Classification complete");
+    }
+
+     void processAmplitudeClassification( RandomAccessibleInterval< T > input, ImgFactory< T > factory, double amplitudeThreshold ) throws EmptyOutputException
+    {
+        /* Classification according to maximum amplitude */
+       output = Util.runAmplitudeClassification( input, factory, amplitudeThreshold );
+    }
+
+     void processOtsuClassification( RandomAccessibleInterval< T > input, ImgFactory< T > factory, double otsuThreshold )
+    {
+        /* Classification according to local intensity*/
+        output = Util.runOtsuClassification( input, factory, otsuThreshold );
+    }
+
+    void processBothClassification (RandomAccessibleInterval< T > input, ImgFactory< T > factory, double amplitudeThreshold , double otsuThreshold ) throws EmptyOutputException
+    {
+        /* Classification according to maximum amplitude */
+
+        Img< BitType > amplitudeImg = Util.runAmplitudeClassification( input, factory, amplitudeThreshold );
+        /* Classification according to local intensity*/
+
+        Img< BitType > otsuImg = Util.runOtsuClassification( input, factory, otsuThreshold );
+        /* Intersection of both classification */
+        this.output = classification( amplitudeImg, amplitudeImg.factory(), otsuImg );
+    }
+
+
+    /**
+     * @param amplitude  an {@link BitType}{@link Img}
+     * @param factory    the same  {@link BitType} {@link ImgFactory} as amplitude
+     * @param thresholds another {@link BitType}{@link Img}
+     * @return the intersection of both image
+     */
+    private Img< BitType > classification( IterableInterval< BitType > amplitude,
+                                           ImgFactory< BitType > factory,
+                                           RandomAccessibleInterval< BitType > thresholds )
+    {
+        Img< BitType > output = factory.create( thresholds );
+        Cursor< BitType > amplitudeCursor = amplitude.localizingCursor();
+        RandomAccess< BitType > thresholdAccess = thresholds.randomAccess();
+        RandomAccess< BitType > outputAccess = output.randomAccess();
+        while ( amplitudeCursor.hasNext() )
+        {
+            amplitudeCursor.fwd();
+            if ( amplitudeCursor.get().getRealDouble() != 0 )
+            {
+                thresholdAccess.setPosition( amplitudeCursor );
+                if ( thresholdAccess.get().get() )
+                {
+                    outputAccess.setPosition( amplitudeCursor );
+                    outputAccess.get().setOne();
+                }
+            }
+        }
+        return output;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PostTreatment.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PostTreatment.java
new file mode 100644
index 0000000000000000000000000000000000000000..7069ba6ebc0c4ef5965057b6c9bac19370f5419a
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PostTreatment.java
@@ -0,0 +1,107 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection;
+
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PostTreatmentParameters;
+import fr.pasteur.ida.zellige.utils.Utils;
+import fr.pasteur.ida.zellige.utils.islandSearch.IslandSearch;
+import net.imglib2.RandomAccess;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.img.Img;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.logic.BitType;
+import net.imglib2.type.numeric.RealType;
+import net.imglib2.type.numeric.real.FloatType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PostTreatment
+{
+    private final static Logger LOGGER = LoggerFactory.getLogger( PostTreatment.class );
+
+    private Pixels[][] output;
+
+    public PostTreatment()
+    {
+    }
+
+    public void process( Img< BitType > classifiedPixel , PostTreatmentParameters parameters )
+    {
+        LOGGER.info("Starting post treatment.");
+        /* Isolated Pixel removal */
+        int islandSize = parameters.getIslandSize();
+        if (islandSize != 0)
+        {
+            int connexity = parameters.getConnexity();
+            classifiedPixel = runIslandSearch( classifiedPixel, islandSize, connexity );
+        }
+
+        /* Conversion into FloatType before dilatation */
+        Img< FloatType > converted = Utils.convertBitTypeIntoFloatType( classifiedPixel );
+        // Use of Converter.convert() not possible because classifiedPixel type do not extends RealType
+
+        /* Dilatation of the resulting image*/
+        runDilatation( converted, parameters );
+//        double sigmaXY = parameters.getSigmaXY();
+//        double sigmaZ = parameters.getSigmaZ();
+//        Utils.gaussConvolution( converted.copy(), converted, new double[]{ sigmaXY, sigmaXY, sigmaZ } );
+
+        /* Final local maximum detection */
+        converted = Util.findMaxima( converted.copy(), converted.factory() );
+        output =  buildPixelArray( converted );
+        LOGGER.info("Post treatment complete");
+    }
+
+    Img< BitType > runIslandSearch(Img< BitType > input , int islandSize, int connexity)
+    {
+            return IslandSearch.run( input, islandSize, connexity );
+    }
+
+    void runDilatation( Img<FloatType> input, PostTreatmentParameters parameters )
+    {
+        double sigmaXY = parameters.getSigmaXY();
+        double sigmaZ = parameters.getSigmaZ();
+        LOGGER.info( "Running dilatation with sigma XY = {} and sigma Z = {}", sigmaXY, sigmaZ);
+        Utils.gaussConvolution( input.copy(), input, new double[]{ sigmaXY, sigmaXY, sigmaZ } );
+    }
+
+    /**
+     *
+     * @param stack an image as a {@link RandomAccessibleInterval}
+     * @param <T> the image type
+     * @return the image as a 2D {@link Pixels} array.
+     */
+    public  < T extends RealType< T > & NativeType< T > > Pixels[][] buildPixelArray(
+            final RandomAccessibleInterval< T > stack )
+    {
+        RandomAccess< T > access = stack.randomAccess();
+        Pixels[][] pixels = new Pixels[ ( int ) stack.dimension( 1 ) ][ ( int ) stack.dimension( 0 ) ];
+        for ( int x = 0; x <= stack.dimension( 0 ) - 1; x++ )
+        {
+            for ( int y = 0; y <= stack.dimension( 1 ) - 1; y++ )
+            {
+                for ( int z = 0; z <= stack.dimension( 2 ) - 1; z++ )
+                {
+                    double value = Utils.setPositionAndGet( access, x, y, z ).getRealDouble();
+                    if ( value > 0 )
+                    {
+                        if ( pixels[ y ][ x ] == null )
+                        { // nothing yet
+                            pixels[ y ][ x ] = new Pixels( new Coordinate( x, y, z ) );
+                        }
+                        else // already at least two coordinates
+                        {
+                            pixels[ y ][ x ].add( new Coordinate( x, y, z ) );
+                        }
+                    }
+                }
+            }
+        }
+        return pixels;
+    }
+
+    public Pixels[][] getOutput()
+    {
+        return output;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/Pretreatment.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/Pretreatment.java
new file mode 100644
index 0000000000000000000000000000000000000000..0539d4ace105ac5ea052d54773b2efac47aff357
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/Pretreatment.java
@@ -0,0 +1,110 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection;
+
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters;
+import fr.pasteur.ida.zellige.utils.Filter2D;
+import fr.pasteur.ida.zellige.utils.Utils;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.converter.Converters;
+import net.imglib2.converter.readwrite.RealFloatSamplerConverter;
+import net.imglib2.img.Img;
+import net.imglib2.img.ImgFactory;
+import net.imglib2.img.array.ArrayImgFactory;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.RealType;
+import net.imglib2.type.numeric.real.FloatType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Pretreatment< T extends RealType< T > & NativeType< T > >
+{
+    private final static Logger LOGGER = LoggerFactory.getLogger( Pretreatment.class );
+
+    public static final String MEDIAN = "Median";
+    public static final String GAUSSIAN_BLUR = "GaussianBlur";
+    private final RandomAccessibleInterval< T > input;
+    private final PretreatmentParameters pretreatmentParameters;
+    private Img< FloatType > pretreatedImg;
+
+
+    Pretreatment( RandomAccessibleInterval< T > input, PretreatmentParameters pretreatmentParameters )
+    {
+        this.input = input;
+        this.pretreatmentParameters = pretreatmentParameters;
+    }
+
+
+     void run()
+    {
+        LOGGER.info("Starting process...");
+        // The input is converted into FloatType
+        RandomAccessibleInterval< FloatType > converted = Converters.convert( input, new RealFloatSamplerConverter<>() );
+        LOGGER.info("Input converted.");
+        //The choose method of denoising is applied
+        Img< FloatType > denoised = denoisingStep( converted, this.pretreatmentParameters.getMethod() );
+        // The denoised image is normalized between 0 and 255
+        this.pretreatedImg = Utils.normalizeImage( denoised, denoised.factory() );
+        LOGGER.info("Input normalized.");
+        LOGGER.info("Process complete.");
+    }
+
+    /**
+     * Applies the denoising step on the specified input according to the specified method
+     *
+     * @param input           the noisy image as a {@link RandomAccessibleInterval}
+     * @param denoisingMethod the denoising method
+     * @return a denoised image as a  {@link Img}
+     */
+     Img< FloatType > denoisingStep( RandomAccessibleInterval< FloatType > input, String denoisingMethod )
+    {
+        LOGGER.info("Starting denoising step...");
+        RandomAccessibleInterval< FloatType > converted = Converters.convert( input, new RealFloatSamplerConverter<>() );
+        if ( denoisingMethod.equals( MEDIAN ) )
+        {
+            LOGGER.info("Denoising step complete, with median filter");
+            return medianFilterDenoising( converted );
+        }
+        else// if ( denoisingMethod.equals( GAUSSIAN_BLUR ) )
+        {
+            LOGGER.info("Denoising step complete, with gaussian filter");
+            return gaussianBlurFilterDenoising( converted );
+        }
+
+    }
+
+    /**
+     * Applies a 2D median filter to a noisy image
+     *
+     * @param input the noisy image as a {@link RandomAccessibleInterval}
+     * @return a denoised image as a  {@link Img}
+     */
+     Img< FloatType > medianFilterDenoising( RandomAccessibleInterval< FloatType > input )
+    {
+        int radius = ( int ) pretreatmentParameters.getParameters()[ 0 ];
+        return Filter2D.median( input, radius );
+    }
+
+    /**
+     * Applies a gaussian filter to a noisy image
+     *
+     * @param input the noisy image as a {@link RandomAccessibleInterval}
+     * @return a denoised image as a  {@link Img}
+     */
+    Img< FloatType > gaussianBlurFilterDenoising( RandomAccessibleInterval< FloatType > input )
+    {
+        ImgFactory< FloatType > factory = new ArrayImgFactory<>( new FloatType() );
+        double[] parameters = pretreatmentParameters.getParameters();
+        //TODO (3 parameters or only 2 (x == y))
+        return Utils.gaussConvolution( input, factory, parameters );
+    }
+
+    public RandomAccessibleInterval< T > getInput()
+    {
+        return input;
+    }
+
+
+    public Img< FloatType > getPretreatedImg()
+    {
+        return pretreatedImg;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/SurfacePixelSelection.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/SurfacePixelSelection.java
new file mode 100644
index 0000000000000000000000000000000000000000..983eac5964964ffb5a6777a21f976b4c6c7d768b
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/SurfacePixelSelection.java
@@ -0,0 +1,74 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection;
+
+import fr.pasteur.ida.zellige.exception.EmptyOutputException;
+import fr.pasteur.ida.zellige.exception.NoClassificationException;
+import fr.pasteur.ida.zellige.jzy3D.LocalMaximumsDisplay;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelClassificationParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelSelectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PostTreatmentParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.img.Img;
+import net.imglib2.img.display.imagej.ImageJFunctions;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.logic.BitType;
+import net.imglib2.type.numeric.RealType;
+import net.imglib2.type.numeric.real.FloatType;
+import org.jzy3d.analysis.AnalysisLauncher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class allows to get a set of classified and localised Pixels objects as a double array.
+ */
+public class SurfacePixelSelection
+{
+    private final static Logger LOGGER = LoggerFactory.getLogger( SurfacePixelSelection.class );
+
+    private final PretreatmentParameters pretreatmentParameters;
+    private final PixelClassificationParameters classificationParameters;
+    private final PostTreatmentParameters postTreatmentParameters;
+    private Pixels[][] maximums;
+
+    public SurfacePixelSelection( PixelSelectionParameters parameters )
+    {
+        this.pretreatmentParameters = parameters.getPretreatmentParameters();
+        this.classificationParameters = parameters.getClassificationParameters();
+        this.postTreatmentParameters = parameters.getPostTreatmentParameters();
+    }
+
+    public static < T extends RealType< T > & NativeType< T > >Pixels[][]
+    run(RandomAccessibleInterval< T > source,PixelSelectionParameters parameters ) throws EmptyOutputException, NoClassificationException
+    {
+        LOGGER.info("Starting selection...");
+        SurfacePixelSelection selection = new SurfacePixelSelection ( parameters );
+        selection.run( source );
+        LOGGER.info("Selection complete");
+        return selection.maximums;
+    }
+
+    /**
+     * @param source - the pretreated image
+     */
+    public  < T extends RealType< T > & NativeType< T > >void run( RandomAccessibleInterval< T > source ) throws EmptyOutputException, NoClassificationException
+    {
+        /* Pretreatment of the image.*/
+        LOGGER.info("Running Pretreatment...");
+        Img< FloatType > pretreatedImage = Util.runPretreatment( source, pretreatmentParameters );
+
+        /* Classification. */
+        LOGGER.info("Running Classification...");
+        Img< BitType > classifiedPixel = Util.runClassification( pretreatedImage, pretreatedImage.factory(), classificationParameters );
+//        ImageJFunctions.show( classifiedPixel );
+        /* PostTreatment and output*/
+        LOGGER.info("Running Post treatment...");
+        maximums = Util.runPostTreatment( classifiedPixel, postTreatmentParameters );
+//        displayMaximums( maximums );
+    }
+
+    public Pixels[][] getMaximums()
+    {
+        return maximums;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/Util.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/Util.java
new file mode 100644
index 0000000000000000000000000000000000000000..b5a998c2ccf6ab770d04c60653ddff3a394d4ee7
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/Util.java
@@ -0,0 +1,143 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection;
+
+import fr.pasteur.ida.zellige.exception.EmptyOutputException;
+import fr.pasteur.ida.zellige.exception.NoClassificationException;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelClassificationParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PostTreatmentParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.img.Img;
+import net.imglib2.img.ImgFactory;
+import net.imglib2.img.array.ArrayImgFactory;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.logic.BitType;
+import net.imglib2.type.numeric.RealType;
+import net.imglib2.type.numeric.real.FloatType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Util
+{
+
+    private final static Logger LOGGER = LoggerFactory.getLogger( Util.class );
+    /**
+     *
+     * @param input the image containing the extrema
+     * @param factory the input factory
+     * @param type the type of extrema to search (min for minimums or max for maximums)
+     * @param <T> the input type
+     * @return an image with extrema with original value and other pixels at zero value
+     */
+    private static < T extends RealType< T > & NativeType< T > > Img< T > findExtrema( RandomAccessibleInterval< T > input,
+                                                                                       ImgFactory< T > factory, String type )
+    {
+        LocalExtremaDetection <T> detector = new LocalExtremaDetection<>( input, factory, type );
+        detector.findExtrema();
+        return detector.getExtrema();
+    }
+    /**
+     *
+     * @param input the image containing the extrema
+     * @param factory the input factory
+     * @param <T> the input type
+     * @return an image with extrema with original value and other pixels at zero value
+     */
+    public static < T extends RealType< T > & NativeType< T > > Img< T > findMinima( RandomAccessibleInterval< T > input,
+                                                                                     ImgFactory< T > factory )
+    {
+        LOGGER.info("Finding minima...");
+        return findExtrema( input, factory, "min" );
+    }
+
+    /**
+     *
+     * @param input the image containing the extrema
+     * @param factory the input factory
+     * @param <T> the input type
+     * @return an image with extrema with original value and other pixels at zero value
+     */
+    public static < T extends RealType< T > & NativeType< T > > Img< T > findMaxima( RandomAccessibleInterval< T > input,
+                                                                                     ImgFactory< T > factory )
+    {
+        LOGGER.info("Finding maxima...");
+        return findExtrema( input, factory, "max" );
+    }
+
+
+    /**
+     * @param <T>                - the type of the input
+     * @param input              - the input image as a {@link RandomAccessibleInterval}
+     * @param amplitudeThreshold - the parameter user value to apply to the first mode of the image histogram.
+     * @return a binary image of background foreground classification
+     */
+    public static < T extends RealType< T > & NativeType< T > > Img< BitType > runAmplitudeClassification( final RandomAccessibleInterval< T > input,
+                                                                                                           final ImgFactory< T > factory, double amplitudeThreshold ) throws EmptyOutputException
+    {
+            // Prepare output.
+            Img< BitType > amplitude = new ArrayImgFactory<>( new BitType() ).create( input );
+            MaximumAmplitudeClassification <T>classification =
+                    new MaximumAmplitudeClassification<>( input, factory,amplitude, amplitudeThreshold );
+            classification.runClassification();
+            return classification.getAmplitude();
+    }
+
+
+    /**
+     * Static method to provide a 2-part classification on a 3D image
+     *
+     * @param <T>        the image type
+     * @param input      the 3D image
+     * @param factory    the input's {@link ImgFactory}.
+     * @param parameters - the parameters for the 2-parts classification
+     * @return a binary image
+     * @throws EmptyOutputException if the binary image is empty.
+     */
+    public static < T extends RealType< T > & NativeType< T > > Img< BitType >
+    runClassification( RandomAccessibleInterval< T > input, ImgFactory< T > factory, PixelClassificationParameters parameters ) throws EmptyOutputException, NoClassificationException
+    {
+        PixelClassification< T > classification = new PixelClassification<>(  );
+        classification.process( input, factory, parameters );
+        return classification.output;
+    }
+
+    /**
+     * @param input   the input {@link Img}
+     * @param percent the percentage of global otsu value
+     * @param <T>     the type on the input
+     * @return a 3D binary {@link Img<BitType>}
+     */
+    public static < T extends RealType< T > & NativeType< T > > Img< BitType > runOtsuClassification( final RandomAccessibleInterval< T > input, ImgFactory< T > factory, double percent )
+    {
+        if (percent > 0)
+        {
+            // Prepare output.
+            final ImgFactory< BitType > bitTypeImgFactory = net.imglib2.util.Util.getArrayOrCellImgFactory( input, new BitType() );
+            Img< BitType > binary = bitTypeImgFactory.create( input );
+            LocalOtsuClassification <T> classification = new LocalOtsuClassification<>(input, factory, binary,percent);
+            classification.run();
+
+            return classification.getGrid();
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    public static < T extends RealType< T > & NativeType< T > > Img< FloatType >
+    runPretreatment( RandomAccessibleInterval< T > input, PretreatmentParameters pretreatmentParameters)
+    {
+        Pretreatment<T> pretreatment = new Pretreatment<>( input, pretreatmentParameters );
+        pretreatment.run();
+        return pretreatment.getPretreatedImg();
+    }
+
+    public static Pixels[][] runPostTreatment( Img< BitType > input, PostTreatmentParameters parameters)
+    {
+        PostTreatment postTreatment = new PostTreatment();
+        postTreatment.process( input, parameters );
+        return postTreatment.getOutput();
+    }
+
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/ose/OseConstruction.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/ose/OseConstruction.java
new file mode 100644
index 0000000000000000000000000000000000000000..54e11df77e22a9e22ff20d3d6115b6e73d48626a
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/ose/OseConstruction.java
@@ -0,0 +1,243 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.ose;
+
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound.OSEStartingStatus;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.AbstractOSE;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEList;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEListArray;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.Queue;
+
+public abstract class OseConstruction
+{
+
+    private final Pixels[][] maximums;
+    private final OSEListArray oseListArray;
+    private final OSEStartingStatus startingStatus;
+
+    private final static Logger LOGGER = LoggerFactory.getLogger( OseConstruction.class );
+
+
+    public OseConstruction( Pixels[][] maximums , double threshold)
+    {
+        this.maximums = maximums;
+        this.startingStatus = new OSEStartingStatus( threshold);
+        this.oseListArray = new OSEListArray( maximums.length );
+    }
+
+    public void processAllSection()
+    {
+        LOGGER.info( "Starting Ose construction..." );
+        for ( int i = 0; i <= maximums.length - 1; i++ )
+        {
+            oseListArray.set(i, findOSE( maximums[ i ] ));
+        }
+        startingStatus.setStartingStatus();
+        System.out.println( "Starting size = " + startingStatus.getStartingSize());
+        LOGGER.info( "Ose construction complete. All sections processed." );
+    }
+
+    /**
+     * This method finds all the possible 2D surfaces that can be created from the coordinates detected as
+     * local maximums on a array of {@link }.
+     *
+     * @param rawCoordinates - the raw Coordinates from the projection.
+     * @return all the orthogonal surfaces for the projection as an {@link ArrayList <AbstractOSE>}.
+     */
+    private OSEList findOSE( Pixels[] rawCoordinates )
+    {
+        // beware reset dimension if dimension 2
+        ArrayList< Coordinate > startingCoordinates = checkForSideCoordinates( rawCoordinates );
+        OSEList paths = findSimplePaths( startingCoordinates, rawCoordinates );
+        OSEList finalPaths = findComplexPaths( paths );
+        for ( AbstractOSE ose : finalPaths )
+        {
+            ose.set();
+        }
+        finalPaths.reset();
+        return finalPaths;
+    }
+
+    public abstract OSEList findSimplePaths( ArrayList< Coordinate > startingCoordinates, Pixels[] rawCoordinates );
+
+    /**
+     * @param rawCoordinates -  the raw Coordinates from the projection.
+     * @param smallPath      - the one-Z-AbstractOSE
+     * @param ose             - the first AbstractOSE considered.
+     * @param current        - the starting {@link Coordinate} considered.
+     */
+      void findSimplePaths
+    ( Pixels[] rawCoordinates,
+      ArrayList< AbstractOSE > smallPath, AbstractOSE ose, Coordinate current, Queue< Coordinate > queue )
+    {
+        int i = ose.startingIndex( current );
+        while ( i <= rawCoordinates.length - 2 // x must be < to the length of the image minus 1 because [X + 1]
+                && rawCoordinates[ i ] != null // the contents in the array at index x must not be null
+                && rawCoordinates[ i + 1 ] != null // the contents in the array at index (x +1) must not be null
+                && current != null )
+        {
+            Coordinate next = current.getNext( rawCoordinates[ i + 1 ], 0 );
+            if ( next != null )//  Conditions :  |x1 - x2 |= 1 => only 1D surface
+            {
+                ose.add( next );
+            }
+            else
+            {
+                if ( ( i ) < rawCoordinates.length - 3
+                        && rawCoordinates[ i + 2 ] != null// the contents in the array at index (x +1) must not
+                        // be null
+                        && current.getRightNumber() == 0 )
+                {
+                    next = current.getNext( rawCoordinates[ i + 2 ], 0 );
+                    if ( next != null )//fake coordinate
+                    {
+                            ose.createCoordinate(current);
+                        
+                        ose.add( next );
+                        queue.remove( next );
+                        i++;
+                    }
+                }
+            }
+            current = next;
+            i++; //increment of the index
+        }
+        smallPath.add( ose );
+    }
+
+    /**
+     * @param shortPaths - the list of one-z-AbstractOSE.
+     * @return - the list of "big paths" AbstractOSE.
+     */
+    private OSEList findComplexPaths( OSEList shortPaths )
+    {
+        OSEList paths = new OSEList();
+        Queue< AbstractOSE > queue = new LinkedList<>( shortPaths );
+        while ( ! queue.isEmpty() )
+        {
+            AbstractOSE first = queue.remove();
+            shortPaths.remove( first );
+            findComplexPaths( first, shortPaths, queue, paths );
+        }
+        return paths;
+    }
+
+    /**
+     * @param first      - the starting AbstractOSE.
+     * @param smallPaths - the list of all small path AbstractOSE.
+     * @param queue      - the remaining AbstractOSE.
+     * @param longPaths  - the list of long path AbstractOSE.
+     */
+    private  void findComplexPaths( AbstractOSE first,
+                                    ArrayList< AbstractOSE > smallPaths,
+                                    Queue< AbstractOSE > queue, ArrayList< AbstractOSE > longPaths )
+    {
+        for ( AbstractOSE o : smallPaths )
+        {
+            if ( first.isNextTo( o ))
+            {
+                first.addAll( o );
+                o.setVisited( true );
+                queue.remove( o );
+            }
+        }
+        smallPaths.removeIf( AbstractOSE::isVisited );
+        longPaths.add( first );
+    }
+
+    /**
+     * Stores the coordinates that don't have a coordinate to the left.
+     *
+     * @param slice - a one-dimensional array containing the local maximums.
+     * @return - a list of coordinates that don't have a coordinate to the left.
+     */
+    ArrayList< Coordinate > checkForSideCoordinates( Pixels[] slice )
+    {
+        /* Stores the coordinates that have no coordinates to the left.*/
+        ArrayList< Coordinate > noLeftCoordinates = new ArrayList<>();
+        /* Starting point. */
+        int start = 0;
+        while ( start <= slice.length - 3 && slice[ start ] == null )
+        {
+            start++;//the index starts where a List of Coordinates is found in the array
+        }
+        if ( slice[ start ] != null && slice[ start + 1 ] != null ) //some Coordinates were found
+        {
+            /* For the first list of coordinates. */
+            for ( int i = 0; i <= slice[ start ].size() - 1; i++ )// the first coordinates of the array have obviously no left coordinates
+            {
+                Coordinate coordinate = slice[ start ].get( i );
+                noLeftCoordinates.add( coordinate );
+                coordinate.setRightCoordinates( slice[ start + 1 ] );
+            }
+        }
+        /* For the rest. */
+        for ( int i = start + 1; i <= slice.length - 2; i++ )
+        {
+            if ( slice[ i ] != null )
+            {
+                for ( Coordinate coordinate : slice[ i ].get() )
+                {
+                    coordinate.setRightCoordinates( slice[ i + 1 ] );
+                    coordinate.setLeftCoordinates( slice[ i - 1 ] );
+                    boolean hasNoLeft = coordinate.numberOfNeighbours( slice[ i - 1 ], 0 ) == 0;
+                    if ( hasNoLeft )
+                    {
+                        noLeftCoordinates.add( coordinate );
+                    }
+                }
+            }
+        }
+        /* the last one */ //Avoid ArrayOutOfBoundException
+        int end = slice.length - 1;
+        if ( slice[ end ] != null && slice[ end - 1 ] != null )
+        {
+            for ( Coordinate coordinate : slice[ end ].get() )
+            {
+                coordinate.setLeftCoordinates( slice[ end - 1 ] );
+                boolean hasNoLeft = coordinate.numberOfNeighbours( slice[ end - 1 ], 0 ) == 0;
+                if ( hasNoLeft )
+                {
+                    noLeftCoordinates.add( coordinate );
+                }
+            }
+        }
+        return noLeftCoordinates;
+    }
+
+//    /**
+//     * Resets the parameters of each {@link Coordinate } for a given {@link Pixels} array
+//     * before the Y dimension reconstruction ( rightsNumber , leftsNumber, noLeft, queue ).
+//     *
+//     * @param slice - the {@link Pixels} array considered.
+//     */
+//    private  void reset( Pixels[] slice )
+//    {
+//        for ( Pixels pixels : slice )
+//        {
+//            if ( pixels != null )
+//            {
+//                pixels.resetSideCoordinate();
+//            }
+//        }
+//    }
+
+    public Pixels[][] getMaximums()
+    {
+        return maximums;
+    }
+    public OSEListArray getOseListArray()
+    {
+        return oseListArray;
+    }
+
+    public OSEStartingStatus getStartingStatus()
+    {
+        return startingStatus;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/ose/OseConstructionXZ.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/ose/OseConstructionXZ.java
new file mode 100644
index 0000000000000000000000000000000000000000..586310c1f0ef1fa06239daa4d5bf4c90d76519c6
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/ose/OseConstructionXZ.java
@@ -0,0 +1,49 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.ose;
+
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection.MaximumAmplitudeClassification;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.AbstractOSE;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEList;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEListArray;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OseXZ;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.Queue;
+
+public class OseConstructionXZ extends OseConstruction
+{
+
+    private final static Logger LOGGER = LoggerFactory.getLogger( OseConstructionXZ.class );
+    public static OSEListArray runConstruction( Pixels[][] maximums, double threshold)
+    {
+        LOGGER.info("Starting XZ construction");
+        OseConstructionXZ constructionXZ = new OseConstructionXZ( maximums, threshold );
+        constructionXZ.processAllSection();
+        return constructionXZ.getOseListArray();
+    }
+
+    public OseConstructionXZ( Pixels[][] maximums, double threshold )
+    {
+        super( maximums, threshold );
+    }
+
+    @Override
+    public OSEList findSimplePaths( ArrayList< Coordinate > startingCoordinates, Pixels[] rawCoordinates )
+    {
+        Queue< Coordinate > firstQueue = new LinkedList<>( startingCoordinates );// Add the coordinates with no left coordinates in
+        // the queue
+        OSEList smallPath = new OSEList();
+        while ( ! firstQueue.isEmpty() )
+        {
+            Coordinate current = firstQueue.remove();
+            AbstractOSE ose = new OseXZ( this.getStartingStatus() );
+            ose.add( current );
+            findSimplePaths( rawCoordinates, smallPath, ose, current, firstQueue );
+        }
+        return smallPath;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/ose/OseConstructionYZ.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/ose/OseConstructionYZ.java
new file mode 100644
index 0000000000000000000000000000000000000000..dfc1aaa0739a470d77d64f3417a62b5d83625336
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/ose/OseConstructionYZ.java
@@ -0,0 +1,69 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.ose;
+
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.AbstractOSE;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEList;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEListArray;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OseYZ;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.Queue;
+
+public class OseConstructionYZ extends OseConstruction
+{
+    private final static Logger LOGGER = LoggerFactory.getLogger( OseConstructionYZ.class );
+    public OseConstructionYZ( Pixels[][] maximums, double threshold )
+    {
+        super( maximums, threshold );
+    }
+
+
+    public static OSEListArray runConstruction( Pixels[][] maximums, double threshold)
+    {
+        LOGGER.info("Starting YZ construction");
+        OseConstructionYZ constructionYZ = new OseConstructionYZ( maximums, threshold );
+        constructionYZ.reset();
+        constructionYZ.processAllSection();
+
+        return constructionYZ.getOseListArray();
+    }
+
+    @Override
+    public OSEList findSimplePaths( ArrayList< Coordinate > startingCoordinates, Pixels[] rawCoordinates )
+    {
+        Queue< Coordinate > firstQueue = new LinkedList<>( startingCoordinates );// Add the coordinates with no left coordinates in
+        // the queue
+        OSEList smallPath = new OSEList();
+        while ( ! firstQueue.isEmpty() )
+        {
+            Coordinate current = firstQueue.remove();
+            AbstractOSE ose = new OseYZ( this.getStartingStatus() );
+            ose.add( current );
+            findSimplePaths( rawCoordinates, smallPath, ose, current, firstQueue );
+        }
+        return smallPath;
+    }
+
+    /**
+     * Resets the parameters of each {@link Coordinate } for a given {@link Pixels} array
+     * before the Y dimension reconstruction ( rightsNumber , leftsNumber, noLeft, queue ).
+     *
+     */
+    private  void reset()
+    {
+
+        for ( Pixels [] pixelLine : this.getMaximums() )
+        {
+            for (Pixels pixels : pixelLine)
+            if ( pixels != null )
+            {
+                pixels.resetSideCoordinate();
+            }
+        }
+        LOGGER.info( "Ose reset" ) ;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/surface/AllSurfaceConstruction.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/surface/AllSurfaceConstruction.java
new file mode 100644
index 0000000000000000000000000000000000000000..2478f9c9f2f2d222b01bd5846fc85b52506a48b3
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/surface/AllSurfaceConstruction.java
@@ -0,0 +1,164 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.surface;
+
+
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.*;
+
+import java.util.ArrayList;
+
+
+/**
+ *
+ */
+public class AllSurfaceConstruction
+{
+
+    private final ArrayList< Surface > surfaces = new ArrayList<>();
+    private final OSEListArray oseListArray;
+    private final int width;
+    private final double connexity;
+    private final int overlap;
+
+    private int smallSurfaceCount;
+
+    public AllSurfaceConstruction( OSEListArray oseLists, int width, int overlap, double connexity )
+    {
+        this.oseListArray = oseLists;
+        this.width = width;
+        this.connexity = connexity;
+        this.overlap = overlap;
+    }
+
+    public static ArrayList< Surface > run( OSEListArray oseListArray, int surfaceLineLength, int overlap, double connexity )
+    {
+        AllSurfaceConstruction reconstruction = new AllSurfaceConstruction( oseListArray, surfaceLineLength, overlap, connexity );
+        reconstruction.buildAllSurfaces2();
+        return reconstruction.surfaces;
+    }
+
+
+    /**
+     * Returns a list of TempSurface constructed from the specified OSList array.
+     */
+//    public void buildAllSurfaces()
+//    {
+//        // Construction of the list of output TempSurface.
+//        smallSurfaceCount = 0;
+//        int finalIndex = findIndexValue( 0 );
+//        do
+//        {
+//            // All the OSLists are set to "not visited".
+//            reset();
+//            int startingIndex = finalIndex;
+//            AbstractOSE firstOSE = getFirstOs( finalIndex );
+//            if ( firstOSE != null )
+//            {
+//                Surface surface = OneSurfaceConstruction.run( oseLists, firstOSE, width, overlap, connexity );
+//                checkSurface( surface );
+//                finalIndex = findIndexValue( startingIndex );
+//            }
+//        }
+//        while ( finalIndex <= oseLists.length - 2
+//                && ( oseLists[ finalIndex ] != null
+//                && ! oseLists[ finalIndex ].isEmpty()
+//                && oseLists[ finalIndex ].containsAStart() ) );
+//        System.out.println( "smallSurfaceCount = " + smallSurfaceCount );
+//    }
+
+    public void buildAllSurfaces2()
+    {
+        while ( true )
+        {
+            // All the OSLists are set to "not visited".
+            AbstractOSE startingOse = oseListArray.getAStartingOse();
+            if ( startingOse != null )
+            {
+                Surface surface = OneSurfaceConstruction.run( oseListArray, startingOse, width, overlap, connexity );
+                checkSurface( surface );
+            }
+            else
+            {
+                break;
+            }
+        }
+        System.out.println( "smallSurfaceCount = " + smallSurfaceCount );
+    }
+
+//    /**
+//     * Returns the index value of the first OSList containing a starting OS.
+//     *
+//     * @param index - the previous index value
+//     * @return the value of the first OSList containing a starting OS
+//     */
+//    private int findIndexValue( int index )
+//    {
+//        int i = index;
+//        int limitValue;
+//        limitValue = oseLists.length - 1;
+//        while ( i <= limitValue - 2 )
+//        {
+//            if ( oseLists[ i ] != null
+//                    && ! oseLists[ i ].isEmpty()
+//                    && oseLists[ i ].containsAStart() )
+//            {
+//                return i;
+//            }
+//            i++;
+//        }
+//        index = limitValue;
+//        return index;
+//    }
+
+//    /**
+//     * Returns the first OS with a start status in the OSList array.
+//     *
+//     * @param index the previous index value
+//     * @return the first OS with a true Start status
+//     */
+//    private AbstractOSE getFirstOs( int index )
+//    {
+//        for ( AbstractOSE os : oseLists[ index ] )
+//        {
+//            if ( os.isAStart() )
+//            {
+//                os.setVisited();
+//                return os;
+//            }
+//        }
+//        return null;
+//    }
+
+    /**
+     * Surface validation check. if the current surface is valid it will be added to the surfaces list.
+     *
+     * @param surface the surface to check.
+     */
+    private void checkSurface( Surface surface )
+    {
+        if ( surface.getSize() >= width * oseListArray.getLength() * 0.01 )
+        {
+            surfaces.add( surface );
+        }
+        else
+        {
+            smallSurfaceCount++;
+            System.out.println( "searching.....from " );
+        }
+    }
+
+//    /**
+//     * Resets the "visited" value of each OS contained in each OSList to FALSE.
+//     */
+//    private void reset()
+//    {
+//        for ( OSEList oseList : oseLists )
+//        {
+//            oseList.reset(); // empty list instead of null
+//        }
+//    }
+
+    public int getSmallSurfaceCount()
+    {
+        return smallSurfaceCount;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/surface/OneSurfaceConstruction.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/surface/OneSurfaceConstruction.java
new file mode 100644
index 0000000000000000000000000000000000000000..65630020f436d06a5567524dc2e63eeb590a679a
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/surface/OneSurfaceConstruction.java
@@ -0,0 +1,200 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.surface;
+
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.AbstractOSE;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEList;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEListArray;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine.SurfaceLine;
+
+import java.util.ArrayList;
+
+public class OneSurfaceConstruction
+{
+
+    private final OSEListArray oseLists;
+    private final AbstractOSE firstOSE;
+    private final Surface surface;
+    private final int overlap;
+    private final double connexity;
+
+
+
+    public static Surface run(OSEListArray oseListArray, AbstractOSE firstOSE, int width, int overlap, double connexity )
+    {
+        OneSurfaceConstruction construction = new OneSurfaceConstruction( oseListArray, firstOSE, width, overlap, connexity );
+        construction.set();
+        construction.build();
+        return construction.surface;
+    }
+
+
+    public OneSurfaceConstruction( OSEListArray oseListArray, AbstractOSE firstOSE, int width, int overlap, double connexity )
+    {
+        this.oseLists = oseListArray;
+        this.firstOSE = firstOSE;
+        int height = oseListArray.getLength();
+        this.surface = new Surface( width,height );
+        this.overlap = overlap;
+        this.connexity = connexity;
+    }
+
+
+
+    private void set()
+    {
+        firstOSE.setFirstOSE( surface );
+    }
+
+    private void build()
+    {
+        SurfaceLine next;
+        /* Sweep until no more OSE can be added to the current surface.*/
+        int size = 0;
+        while ( size != surface.getSize() )
+        {
+            size = surface.getSize();
+            for ( int i = surface.getHeight() - 1; i > 0; i-- )
+            {
+                if ( surface.get( i ) != null )
+                {
+                    SurfaceLine previous = searchBackward( surface.get( i ) );
+                    if ( previous != null )
+                    {
+                        surface.set( i - 1, previous );
+                    }
+                }
+            }
+            for ( int i = 0; i <= surface.getHeight() - 2; i++ )
+            {
+                if ( surface.get( i ) != null )
+                {
+                    next = searchForward( surface.get( i ) );
+                    if ( next != null )
+                    {
+                        surface.set( i + 1, next );
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Returns the SurfaceLine matching the current in a specific direction
+     *
+     * @param next        - the OSList to search into
+     * @param currentLine - the {@link SurfaceLine } to match.
+     * @param j           - the direction of the search (1 or -1)
+     * @return the OSList matching SurfaceLine
+     */
+    private SurfaceLine search( OSEList next, SurfaceLine currentLine, int j )
+    {
+        ArrayList< SurfaceLine > list = new ArrayList<>();
+        for ( AbstractOSE os : next )
+        {
+            if ( ! os.isVisited() ) // The OS is already added to the referenceSurface
+            {
+                SurfaceLine line = currentLine.match( os, j, overlap, connexity );
+                if ( line != null )
+                {
+                    list.add( line );
+                }
+            }
+        }
+        if ( list.isEmpty() )
+        {
+            return null;
+        }
+        merge( list );
+        return list.get( 0 );
+    }
+
+    private SurfaceLine search2( OSEList next, SurfaceLine currentLine, int j )
+    {
+        ArrayList< SurfaceLine > list = new ArrayList<>();
+        for ( AbstractOSE os : next )
+        {
+            if ( ! os.isVisited() ) // The OS is already added to the referenceSurface
+            {
+                SurfaceLine line = currentLine.match( os, j, overlap, connexity );
+                if ( line != null && line.isInAdequacyWith(  surface.get(currentLine.getLine() + j)))
+                {
+                    os.setVisited();
+                    surface.set( currentLine.getLine() + j, line );// the line is directly added to the surface
+                }
+            }
+        }
+        if ( list.isEmpty() )
+        {
+            return null;
+        }
+        merge( list );
+        return list.get( 0 );
+    }
+
+
+
+    /**
+     * Returns the SurfaceLine generated from the specified OSList array matching the current SurfaceLine
+     *
+     * @param current - the {@link SurfaceLine } to match
+     * @return the SurfaceLine generated from the specified OSList array matching the current SurfaceLine
+     */
+//    private SurfaceLine searchForward( SurfaceLine current )
+//    {
+//        if ( current.getLine() + 1 <= oseLists.length - 1 )
+//        {
+//            return search( oseLists[ current.getLine() + 1 ], current, 1 );
+//        }
+//        return null;
+//    }
+
+    private SurfaceLine searchForward( SurfaceLine current )
+    {
+        if ( current.getLine() + 1 <= oseLists.getLength() - 1 )
+        {
+            return search2( oseLists.get( current.getLine() + 1 ), current, 1 );
+        }
+        return null;
+    }
+
+    /**
+     * @param current - the current SurfaceLine to match with.
+     * @return - the matching SurfaceLine.
+     */
+//    private SurfaceLine searchBackward( SurfaceLine current )
+//    {
+//        if ( current.getCoordinatesNumber() != 0 && current.getLine() > 0 )
+//        {
+//            return search( oseLists[ current.getLine() - 1 ], current, - 1 );
+//        }
+//        return null;
+//    }
+
+    private SurfaceLine searchBackward( SurfaceLine current )
+    {
+        if ( current.getCoordinatesNumber() != 0 && current.getLine() > 0 )
+        {
+            return search2( oseLists.get( current.getLine() - 1 ), current, - 1 );
+        }
+        return null;
+    }
+
+    /**
+     * Merges the SurfaceLine objects in the specified list.
+     *
+     * @param list - the list to merge.
+     */
+    private void merge( ArrayList< SurfaceLine > list )
+    {
+        if ( list.size() >= 2 ) //more than one SurfaceLines
+        {
+            int index = list.size() - 1;
+            while ( list.size() != 1 )
+            {
+                list.get( index - 1 ).merge( list.remove( index ) );
+                index--;
+            }
+        }
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ReferenceSurface.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ReferenceSurface.java
index d2462d8b0646e05210f2e09c3e742db314a27bf8..6d49c8ff212694babbd9c38d76c5d98655d5aafb 100644
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ReferenceSurface.java
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ReferenceSurface.java
@@ -44,6 +44,7 @@ public class ReferenceSurface< T extends RealType< T > & NativeType< T > >
                 projectionType.equals( "Minimum Intensity" ) )
         {
             elevationMap = StackProjection.getElevationMap ( input, zMap, projectionType, delta );
+//            ImageJFunctions.show( elevationMap, "elevationMap" );
              projection = StackProjection.projection1( input,factory, elevationMap, projectionType );
         }
         else
@@ -83,6 +84,10 @@ public class ReferenceSurface< T extends RealType< T > & NativeType< T > >
         }
     }
 
+    public Img< UnsignedShortType > getZMap()
+    {
+        return zMap;
+    }
 }
 
 
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/Surface.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/Surface.java
index 5dee004e442256035a7d4feff2aa47c10d4b2bd1..813b46c361090f8358a27d0cce7fa2df4a98adb6 100644
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/Surface.java
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/Surface.java
@@ -1,6 +1,5 @@
 package fr.pasteur.ida.zellige.surfaceConstruction.element;
 
-import fr.pasteur.ida.zellige.surfaceConstruction.construction.ReferenceSurfaceExtraction;
 import fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine.SurfaceLine;
 import fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine.SurfaceLineX;
 import fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine.SurfaceLineY;
@@ -9,7 +8,6 @@ import net.imglib2.FinalDimensions;
 import net.imglib2.RandomAccess;
 import net.imglib2.img.Img;
 import net.imglib2.img.ImgFactory;
-import net.imglib2.img.display.imagej.ImageJFunctions;
 import net.imglib2.type.numeric.integer.UnsignedShortType;
 import net.imglib2.util.Util;
 
@@ -19,15 +17,16 @@ public class Surface
 {
 
     private final SurfaceLine[] surfaceLines;
-    private final int dimension;
+    private final int width, height;
 
-
-    public Surface( int dimension, int length )
+    public Surface( int width, int height )
     {
-        this.dimension = dimension;
-        this.surfaceLines = new SurfaceLine[ length ];
+        this.width = width;
+        this.height = height;
+        this.surfaceLines = new SurfaceLine[ height ];
     }
 
+//
 
     /**
      * Returns true if the instance has a {@link Pixels }which the size is superior to 1 (at least 2{@link Coordinate})
@@ -99,6 +98,37 @@ public class Surface
         return ( r ) > 0.70;
     }
 
+    public double overlappingRate(  Surface other )
+    {
+        int inCommon = 0;
+        int count = 0;
+        for ( int i = 0; i <= this.getHeight() - 1; i++ )
+        {
+            SurfaceLine refLine = this.get( i );
+            if ( refLine != null )
+            {
+                for ( int j = 0; j < refLine.getLength(); j++ )
+                {
+                    Pixels refPixels = refLine.get( j );
+                    if ( refPixels != null )
+                    {
+                        count++;
+                        SurfaceLine toTest = other.get(i);
+
+                        if ( toTest != null && refPixels.equals( other.get( i ).get( j ) ))
+                        {
+                            inCommon++;
+                        }
+                    }
+                }
+
+            }
+
+        }
+        return  inCommon / (double) count;
+    }
+    
+    
 
     /**
      * Checks if this object shares a majority of {@link Pixels} with an other {@link Surface} object.
@@ -147,20 +177,12 @@ public class Surface
      *
      * @return the identical transposed {@link Surface}
      */
-    public Surface transpose( int length )
+    public Surface transpose()
     {
-        Surface surface = new Surface( Math.abs( this.dimension - 1 ), length );
-        Class< ? > theClass;
-
-        if ( this.dimension == 0 )
-        {
-            theClass = SurfaceLineY.class;
-        }
-        else
-        {
-            theClass = SurfaceLineX.class;
-        }
-
+        int height = this.getWidth();
+        int width = this.getHeight();
+        Surface surface = new Surface( width, height );
+        Class< ? > theClass = getTransposedClass();
         for ( int i = 0; i <= this.getHeight() - 1; i++ )
         {
             SurfaceLine surfaceLine = this.get( i );
@@ -176,7 +198,7 @@ public class Surface
                         {
                             try
                             {
-                                newSurfaceLine = ( SurfaceLine ) theClass.getDeclaredConstructors()[ 1 ].newInstance( length, j );
+                                newSurfaceLine = ( SurfaceLine ) theClass.getDeclaredConstructors()[ 1 ].newInstance( width, j );
                             }
                             catch ( InstantiationException | IllegalAccessException | InvocationTargetException e )
                             {
@@ -215,21 +237,27 @@ public class Surface
     }
 
     /**
-     * Sets the specified {@link SurfaceLine} at the specified index position into the {@link SurfaceLine} array of
-     * the instance.
+     * Sets the specified {@link SurfaceLine} at the specified index position. If the Surfaline at the specified index
+     * not null, the both are merged.
      *
      * @param index       the position of the SurfaceLine
      * @param surfaceLine the SurfaceLine object to set
      */
     public void set( int index, SurfaceLine surfaceLine )
     {
-        this.surfaceLines[ index ] = surfaceLine;
+        if ( this.surfaceLines[ index ] != null )
+        {
+            surfaceLines[ index ].merge( surfaceLine );
+        }
+        else
+        {
+            this.surfaceLines[ index ] = surfaceLine;
+        }
     }
 
 
     public Img< UnsignedShortType > getZMap()
     {
-//        ReferenceSurfaceExtraction.displaySurface( this );
         int count = 0;
         Dimensions dim = FinalDimensions.wrap( new long[]{ getHeight(), getWidth() } );
         ImgFactory< UnsignedShortType > factory = Util.getArrayOrCellImgFactory( dim, new UnsignedShortType() );
@@ -306,21 +334,45 @@ public class Surface
     }
 
 
-    public int getWidth()
+    public Class< ? > getTransposedClass()
     {
-        for ( SurfaceLine surfaceLine : surfaceLines
-        )
+
+        for ( SurfaceLine surfaceLine : surfaceLines )
         {
             if ( surfaceLine != null )
             {
-                return surfaceLine.getLength();
+                return surfaceLine.getClass() == SurfaceLineX.class ? SurfaceLineY.class : SurfaceLineX.class;
             }
         }
-        return 0;
+        return null;
+    }
+
+
+    public int getWidth()
+    {
+        return width;
     }
 
     public int getHeight()
     {
-        return this.surfaceLines.length;
+        return height;
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null || getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        Surface other = (Surface ) obj;
+        {
+            System.out.println(overlappingRate( other ));
+            return overlappingRate( other ) == 1;
+        }
     }
 }
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OSE.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/AbstractOSE.java
similarity index 60%
rename from src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OSE.java
rename to src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/AbstractOSE.java
index eeddbe41f8c6d65723c4691953535537e58d2670..8dca542e75d440a0419c34dbe5fefc492344aeb3 100644
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OSE.java
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/AbstractOSE.java
@@ -1,15 +1,14 @@
 package fr.pasteur.ida.zellige.surfaceConstruction.element.ose;
 
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound.OSEStartingStatus;
 import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
 
-import java.util.*;
+import java.util.ArrayList;
 
-
-/**
- * OS stands for Orthogonal Surface Element which is list of ordered Coordinates being part of the same 1D surface.
- */
-public class OSE extends ArrayList< Coordinate >
+public abstract class AbstractOSE extends ArrayList< Coordinate >
 {
+
     public static int sizeSum = 0;
     /* Not necessary for the program.*/
     private static int count = 0;
@@ -26,7 +25,7 @@ public class OSE extends ArrayList< Coordinate >
      */
     private boolean start = true;
 
-    public OSE( OSEStartingStatus startingStatus )
+    public AbstractOSE( OSEStartingStatus startingStatus )
     {
         this.startingStatus = startingStatus;
     }
@@ -56,27 +55,32 @@ public class OSE extends ArrayList< Coordinate >
      * Test if the current instance is adjacent to the next OS instance.
      *
      * @param next      - the other OS instance.
-     * @param dimension - the dimension in witch the OS has been constructed.
      * @return true if the two OS are next to each other, false otherwise.
      */
-    public boolean isNextTo( OSE next, int dimension )
+    public abstract boolean isNextTo( AbstractOSE next );
     {
-        if ( dimension == 0 )
-        {
-            return ( next.get( 0 ).getX() - this.get( this.size() - 1 ).getX() == 1 // the two OS are next to each other
-                    && this.get( this.size() - 1 ).getRightNumber() == 1 // this OS has only one possible right coordinate
-                    && next.get( 0 ).getLeftNumber() == 1  // the next OS has only one possible left coordinate
-                    && this.get( this.size() - 1 ).isNext( next.get( 0 ), 1 ) );// the difference between the z values equals 1
-        }
-        else
-        {
-            return ( next.get( 0 ).getY() - this.get( this.size() - 1 ).getY() == 1 // the two OS are next to each other
-                    && this.get( this.size() - 1 ).getRightNumber() == 1 // this OS has only one possible right coordinate
-                    && next.get( 0 ).getLeftNumber() == 1  // the next OS has only one possible left coordinate
-                    && this.get( this.size() - 1 ).isNext( next.get( 0 ), 1 ) );// the difference between the z values equals 1
-        }
+//        if ( dimension == 0 )
+//        {
+//            return ( next.get( 0 ).getX() - this.get( this.size() - 1 ).getX() == 1 // the two OS are next to each other
+//                    && this.get( this.size() - 1 ).getRightNumber() == 1 // this OS has only one possible right coordinate
+//                    && next.get( 0 ).getLeftNumber() == 1  // the next OS has only one possible left coordinate
+//                    && this.get( this.size() - 1 ).isNext( next.get( 0 ), 1 ) );// the difference between the z values equals 1
+//        }
+//        else
+//        {
+//            return ( next.get( 0 ).getY() - this.get( this.size() - 1 ).getY() == 1 // the two OS are next to each other
+//                    && this.get( this.size() - 1 ).getRightNumber() == 1 // this OS has only one possible right coordinate
+//                    && next.get( 0 ).getLeftNumber() == 1  // the next OS has only one possible left coordinate
+//                    && this.get( this.size() - 1 ).isNext( next.get( 0 ), 1 ) );// the difference between the z values equals 1
+//        }
     }
 
+    public abstract void createCoordinate( Coordinate coordinate );
+
+    public abstract void setFirstOSE( Surface surface);
+
+    public abstract int startingIndex(Coordinate current);
+
     /**
      * Returns true if the OS has been visited.
      *
@@ -132,13 +136,13 @@ public class OSE extends ArrayList< Coordinate >
      */
     public boolean isAStart()
     {
-        return ( this.size() >= this.startingStatus.getMinimumSize() && start );
+        return ( this.size() >= this.startingStatus.getStartingSize() && start );
     }
 
+    public abstract int getCoordinate(int index);
     /* Not necessary for the program.*/
     public String toString()
     {
         return ( " " + name );
     }
-
 }
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OSEList.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OSEList.java
index c1c69856fc4ffbaff319ea3cb47e10b3cf8edf3f..7cd25e829bd9cca6e2e41641bd0523e4bcd5f72e 100644
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OSEList.java
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OSEList.java
@@ -6,16 +6,16 @@ import java.util.Collection;
 /**
  * An OSList object is simply an ArrayList of {@link OSE}
  */
-public class OSEList extends ArrayList < OSE >
+public class OSEList extends ArrayList< AbstractOSE >
 {
 
 
-    public OSEList( )
+    public OSEList()
     {
     }
 
     @Override
-    public boolean add( OSE os )
+    public boolean add( AbstractOSE os )
     {
         if ( this.contains( os ) )
         {
@@ -28,52 +28,37 @@ public class OSEList extends ArrayList < OSE >
     }
 
     @Override
-    public boolean addAll( Collection < ? extends OSE > c )
+    public boolean addAll( Collection< ? extends AbstractOSE > c )
     {
         boolean add = false;
-        for ( OSE os : c )
+        for ( AbstractOSE os : c )
         {
             add = add( os );
         }
         return add;
     }
 
-
-    public int getSize( )
+    public int getSize()
     {
         int size = 0;
-        for ( OSE os : this )
+        for ( AbstractOSE os : this )
         {
             size = size + os.size();
         }
         return size;
     }
 
-//    public boolean isVisited()
-//    {
-//        boolean visited = true;
-//        for ( OS os : this
-//        )
-//        {
-//            if ( !os.isVisited() )
-//            {
-//                visited = false;
-//            }
-//        }
-//        return visited;
-//    }
-
-    public void reset( )
+    public void reset()
     {
-        for ( OSE os : this )
+        for ( AbstractOSE os : this )
         {
             os.setVisited( false );
         }
     }
 
-    public boolean containsAStart( )
+    public boolean containsAStart()
     {
-        for ( OSE os : this )
+        for ( AbstractOSE os : this )
         {
             if ( os.isAStart() )
             {
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OSEListArray.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OSEListArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..ccb6eb85d207f54b49e429b89403a8884c216be0
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OSEListArray.java
@@ -0,0 +1,89 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.element.ose;
+
+public class OSEListArray
+{
+
+    private final OSEList [] oseLists;
+    private int index = 0;
+
+    public OSEListArray( int length )
+    {
+        this.oseLists = new OSEList[length];
+    }
+
+    /**
+     * Returns the index value of the first OSList containing a starting OS.
+     *
+     * @param index - the previous index value
+     * @return the value of the first OSList containing a starting OS
+     */
+    private int findIndexValue( int index )
+    {
+        int i = index;
+        int limitValue;
+        limitValue = oseLists.length - 1;
+        while ( i <= limitValue - 2 )
+        {
+            if ( oseLists[ i ] != null
+                    && ! oseLists[ i ].isEmpty()
+                    && oseLists[ i ].containsAStart() )
+            {
+                return i;
+            }
+            i++;
+        }
+        index = limitValue;
+        return index;
+    }
+
+    /**
+     * Returns the first OS with a start status in the OSList array.
+     *
+     * @return the first OS with a true Start status
+     */
+    public AbstractOSE getAStartingOse()
+    {
+       reset();
+       index = findIndexValue( index );
+        for ( AbstractOSE os : oseLists[ index ] )
+        {
+            if ( os.isAStart() )
+            {
+                os.setVisited();
+                return os;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Resets the "visited" value of each OS contained in each OSList to FALSE.
+     */
+    public void reset()
+    {
+        for ( OSEList oseList : oseLists )
+        {
+            oseList.reset(); // empty list instead of null
+        }
+    }
+
+    public void set(int i, OSEList oseList)
+    {
+        this.oseLists[i] = oseList;
+    }
+
+    public OSEList get(int index)
+    {
+        return oseLists[index];
+    }
+
+    public int getLength()
+    {
+        return oseLists.length;
+    }
+
+    public OSEList[] getOseLists()
+    {
+        return oseLists;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OSEStartingStatus.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OSEStartingStatus.java
deleted file mode 100644
index be3f4c2906574bb0fac1b2df050b34369c97338a..0000000000000000000000000000000000000000
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OSEStartingStatus.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package fr.pasteur.ida.zellige.surfaceConstruction.element.ose;
-
-import java.util.TreeMap;
-
-public class OSEStartingStatus extends TreeMap<Integer, Integer>
-{
-    private final int dimension;
-    private int minimumSize;
-
-    public OSEStartingStatus( int dimension )
-    {
-        this.dimension = dimension;
-    }
-
-    public  void setStartingStatus()
-    {
-        //TODO user parameter ?
-       
-        if (this.size() != 0)
-        {
-
-            if ( this.dimension == 0 )
-            {
-                for ( int i = 0; this.size() > 20 && i <= this.size()* 0.75 ;i++ )
-                {
-                    this.remove( this.lastKey() );
-                }
-            }
-            else
-            {
-                for ( int i = 0; this.size() > 2 && i <= this.size() / 10; i++ )
-                {
-                    this.remove( this.lastKey()  );
-                }
-            }
-            this.minimumSize = this.lastKey() ;
-
-        }}
-
-    public int getMinimumSize()
-    {
-        return minimumSize;
-    }
-}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OseXZ.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OseXZ.java
new file mode 100644
index 0000000000000000000000000000000000000000..4e78dee2eb4c9ae346642f19096cbd14909b7e76
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OseXZ.java
@@ -0,0 +1,48 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.element.ose;
+
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound.OSEStartingStatus;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine.SurfaceLineX;
+
+public class OseXZ extends AbstractOSE
+{
+    public OseXZ( OSEStartingStatus startingStatus )
+    {
+        super( startingStatus );
+    }
+
+    @Override
+    public boolean isNextTo( AbstractOSE next )
+    {
+        return ( next.get( 0 ).getX() - this.get( this.size() - 1 ).getX() == 1 // the two OS are next to each other
+                && this.get( this.size() - 1 ).getRightNumber() == 1 // this OS has only one possible right coordinate
+                && next.get( 0 ).getLeftNumber() == 1  // the next OS has only one possible left coordinate
+                && this.get( this.size() - 1 ).isNext( next.get( 0 ), 1 ) );// the difference between the z values equals 1
+    }
+
+    @Override
+    public void createCoordinate( Coordinate current )
+    {
+        this.add( new Coordinate( current.getX() + 1, current.getY(), current.getZ() ) );
+    }
+
+    @Override
+    public void setFirstOSE( Surface surface )
+    {
+        int i = this.get(0). getY();
+        int lineLength = surface.getWidth();
+        surface.set( i, new SurfaceLineX( lineLength, this ) );
+    }
+
+
+    public int getCoordinate(int index)
+    {
+       return this.get(index).getX();
+    }
+    @Override
+    public int startingIndex( Coordinate current )
+    {
+        return current.getX();
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OseYZ.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OseYZ.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b9717bc8829590c290fcd12bc73764c96886160
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/ose/OseYZ.java
@@ -0,0 +1,49 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.element.ose;
+
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound.OSEStartingStatus;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine.SurfaceLineY;
+
+public class OseYZ extends AbstractOSE
+{
+    public OseYZ( OSEStartingStatus startingStatus )
+    {
+        super( startingStatus );
+    }
+
+
+    @Override
+    public boolean isNextTo( AbstractOSE next )
+    {
+        return ( next.get( 0 ).getY() - this.get( this.size() - 1 ).getY() == 1 // the two OS are next to each other
+                && this.get( this.size() - 1 ).getRightNumber() == 1 // this OS has only one possible right coordinate
+                && next.get( 0 ).getLeftNumber() == 1  // the next OS has only one possible left coordinate
+                && this.get( this.size() - 1 ).isNext( next.get( 0 ), 1 ) );// the difference between the z values equals 1
+    }
+
+    @Override
+    public void createCoordinate( Coordinate current )
+    {
+        this.add( new Coordinate( current.getX(), current.getY() + 1, current.getZ() ) );
+    }
+
+    @Override
+    public void setFirstOSE( Surface surface )
+    {
+        int i = this.get( 0 ).getX();
+        int lineLength = surface.getWidth();
+        surface.set( i, new SurfaceLineY( lineLength, this ) );
+    }
+
+    @Override
+    public int getCoordinate(int index)
+    {
+        return this.get(index).getY();
+    }
+    @Override
+    public int startingIndex( Coordinate current )
+    {
+        return current.getY();
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/surfaceLine/SurfaceLine.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/surfaceLine/SurfaceLine.java
index 54321fb750330488b0fa68f5a2f988cd11a30b23..de7d167c4a674d8ac6e10c2fa358ff2dfa6453f6 100644
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/surfaceLine/SurfaceLine.java
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/surfaceLine/SurfaceLine.java
@@ -2,7 +2,9 @@ package fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine;
 
 import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
 import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSE;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.AbstractOSE;
+
+import static fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound.constructSurface.ConstructionRounds.adequacy;
 
 public abstract class SurfaceLine
 {
@@ -37,19 +39,58 @@ public abstract class SurfaceLine
      *
      * @param os - a list of Coordinates to fill the pixel array.
      */
-    public SurfaceLine(int length , OSE os)
+    public SurfaceLine(int length , AbstractOSE os)
     {
             this.dimension = new Pixels[ length ] ;
             set( os );
     }
-
-    public SurfaceLine( OSE os, int size )
+    
+    
+    public SurfaceLine( AbstractOSE os, int size )
     {
         this.dimension = new Pixels[ size] ;
         set( os );
     }
 
-    public void set( OSE os )
+    public SurfaceLine match2( AbstractOSE os, int overlap, double connexity, SurfaceLine surfaceLine )
+    {
+        int match = 0;
+        int k = 0;
+        for ( int i = 0; i <= os.size() - 1; i++ )
+        {
+            int j = os.getCoordinate( i );
+            Coordinate coordinate = os.get( i );
+            if ( this.get( j ) != null )
+            {
+                k++;
+                if ( isAMatch( this.get( j ), coordinate ) )
+                {
+                    match++;
+                }
+            }
+            surfaceLine.set( j, coordinate );
+        }
+        if ( k == 0 || match == 0 )
+        {
+            return null;
+        }
+        else if ( ( double ) match / ( double ) k >= connexity && k >= overlap )
+        {
+//            System.out.println("percent = " + ( double ) match / ( double ) k);
+//            System.out.println("k = " + k);
+//            os.setVisited();
+            return surfaceLine;
+        }
+        else
+        {
+//            System.out.println("* percent = " + ( double ) match / ( double ) k);
+//            System.out.println("* k = " + k);
+            return null;
+        }
+    }
+
+
+    public void set( AbstractOSE os )
     {
         for ( Coordinate coordinate : os )
         {
@@ -66,16 +107,28 @@ public abstract class SurfaceLine
         }
     }
 
+    public boolean isInAdequacyWith( SurfaceLine surfaceLine)
+    {
+//        if ( surfaceLine != null )
+//        {
+//            System.out.println("is in adequacy ? " + overlappingRate( surfaceLine ));
+//        }
+        return ( surfaceLine == null ) || overlappingRate( surfaceLine ) < adequacy;
+
+    }
+
+
+
     /**
      * Tests if the OS matches the SurfaceLine instance and creates a new SurfaceLine object if so.
      *
      * @param os      - the OS to test against the SurfaceLine instance.
      * @param j       - an integer witch indicates the line of the resulting SurfaceLine.
-     * @param percent - the minimum percentage of match between the OS and the current instance.
-     * @param matched - the minimum number of matching coordinates.
+     * @param overlap - the minimum number of matching coordinates.
+     * @param connexity - the minimum percentage of match between the OS and the current instance.
      * @return - a new SurfaceLine if there is a match, null otherwise.
      */
-    public abstract SurfaceLine match( OSE os, int j, double percent, int matched );
+    public abstract SurfaceLine match( AbstractOSE os, int j, int overlap, double connexity );
 
 
     /**
@@ -129,6 +182,9 @@ public abstract class SurfaceLine
      */
     public void merge( SurfaceLine other )
     {
+        double o = overlappingRate( other );
+//        System.out.println("overlap = " + o);
+//        if (o < 0.30)
         for ( int i = 0; i <= this.dimension.length - 1; i++ )
         {
             // only two situations where we have to do something
@@ -143,6 +199,20 @@ public abstract class SurfaceLine
         }
     }
 
+    public double overlappingRate(SurfaceLine other)
+    {
+        int overlappedCoordinates = 0;
+        for ( int i = 0; i <= this.dimension.length - 1; i++ )
+        {
+            // only two situations where we have to do something
+            if ( this.get( i ) != null && other.get( i ) != null )
+            {
+                overlappedCoordinates ++;
+            }
+        }
+        return overlappedCoordinates/ (double) this.getCoordinatesNumber();
+    }
+
     /**
      * Combines two Pixels
      *
@@ -150,8 +220,7 @@ public abstract class SurfaceLine
      * @param list2 - the second pixel list.
      * @return a pixel list containing the specified Pixels.
      */
-    public Pixels merge( Pixels list1, Pixels list2
-                            )
+    public Pixels merge( Pixels list1, Pixels list2 )
     {
         if (! list1.equals( list2 ))
         {
@@ -171,8 +240,8 @@ public abstract class SurfaceLine
      */
     public boolean isAMatch( Pixels pixels, Coordinate c )
     {
-        if (pixels.size() <= 3)//TODO how many Coordinates authorized ?
-        {
+//        if (pixels.size() <= 3)//TODO how many Coordinates authorized ?
+//        {
             for ( Coordinate coordinate : pixels.get() )
             {
                 if ( ( Math.abs( c.getZ() - coordinate.getZ() ) ) <= 1 )
@@ -180,7 +249,11 @@ public abstract class SurfaceLine
                     return true;
                 }
             }
-        }
+//        }
+//        else
+//        {
+//            System.out.println(" sup to 3");
+//        }
         return false;
     }
 
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/surfaceLine/SurfaceLineX.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/surfaceLine/SurfaceLineX.java
index 9fe02a4d25843339ccdf4aaa82439701bdfaed4d..432befddea8cee98390b6849ceb97b3072260f95 100644
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/surfaceLine/SurfaceLineX.java
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/surfaceLine/SurfaceLineX.java
@@ -1,7 +1,6 @@
 package fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine;
 
-import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSE;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.AbstractOSE;
 
 public class SurfaceLineX extends SurfaceLine
 {
@@ -12,12 +11,67 @@ public class SurfaceLineX extends SurfaceLine
      *
      * @param os - a list of Coordinates to fill the pixel array.
      */
-    public SurfaceLineX( int length, OSE os )
+//    public SurfaceLineX( int length, OSE os )
+//    {
+//        super( length, os );
+//        this.setLine( os.get( 0 ).getY() );
+//    }
+
+    public SurfaceLineX( int length, AbstractOSE os )
     {
         super( length, os );
         this.setLine( os.get( 0 ).getY() );
     }
 
+    public SurfaceLine match( AbstractOSE os, int direction, int overlap, double connexity )
+    {
+        SurfaceLineX surfaceLineX = new SurfaceLineX( this.getLength(), this.getLine() + direction );
+        return this.match2( os, overlap, connexity, surfaceLineX);
+    }
+    /**
+     * Tests if the OS matches the SurfaceLine instance and creates a new SurfaceLine object if so.
+     *
+     * @param os      - the OS to test against the SurfaceLine instance.
+     * @param j       - an integer witch indicates the line of the resulting SurfaceLine.
+     * @param percent - the minimum percentage of match between the OS and the current instance.
+     * @param matched - the minimum number of matching coordinates.
+     * @return - a new SurfaceLine if there is a match, null otherwise.
+     */
+//    @Override
+//    public SurfaceLine match( AbstractOSE os, int j, double percent, int matched )
+//    {
+//        SurfaceLineX surfaceLine = new SurfaceLineX(this.getLength(), this.getLine() + j );
+//        int match = 0;
+//        int k = 0;
+//        for ( int i = 0; i <= os.size() - 1; i++ )
+//        {
+//            int x = os.get( i ).getX();
+//            Coordinate coordinate = os.get( i );
+//            if ( this.get( x ) != null )
+//            {
+//                k++;
+//                if ( isAMatch( this.get( x ), coordinate ) )
+//                {
+//                    match++;
+//                }
+//            }
+//            surfaceLine.set( x, coordinate );
+//        }
+//        if ( k == 0 || match == 0 )
+//        {
+//            return null;
+//        }
+//        else if ( ( double ) match / ( double ) k >= percent && k >= matched )
+//        {
+//            os.setVisited();
+//            return surfaceLine;
+//        }
+//        else
+//        {
+//            return null;
+//        }
+//    }
+
     /**
      * Constructor.
      *
@@ -28,52 +82,18 @@ public class SurfaceLineX extends SurfaceLine
         super(length,  line );
     }
 
-    public SurfaceLineX( OSE os, int size )
+//    public SurfaceLineX( OSE os, int size )
+//    {
+//        super( os , size);
+//        this.setLine( os.get( 0 ).getY() );
+//    }
+
+    public SurfaceLineX( AbstractOSE os, int size )
     {
         super( os , size);
         this.setLine( os.get( 0 ).getY() );
     }
-    /**
-     * Tests if the OS matches the SurfaceLine instance and creates a new SurfaceLine object if so.
-     *
-     * @param os      - the OS to test against the SurfaceLine instance.
-     * @param j       - an integer witch indicates the line of the resulting SurfaceLine.
-     * @param percent - the minimum percentage of match between the OS and the current instance.
-     * @param matched - the minimum number of matching coordinates.
-     * @return - a new SurfaceLine if there is a match, null otherwise.
-     */
-    public SurfaceLine match( OSE os, int j, double percent, int matched )
-    {
-        SurfaceLineX surfaceLine = new SurfaceLineX(this.getLength(), this.getLine() + j );
-        int match = 0;
-        int k = 0;
-        for ( int i = 0; i <= os.size() - 1; i++ )
-        {
-            int x = os.get( i ).getX();
-            Coordinate coordinate = os.get( i );
-            if ( this.get( x ) != null )
-            {
-                k++;
-                if ( isAMatch( this.get( x ), coordinate ) )
-                {
-                    match++;
-                }
-            }
-            surfaceLine.set( x, coordinate );
-        }
-        if ( k == 0 || match == 0 )
-        {
-            return null;
-        }
-        else if ( ( double ) match / ( double ) k >= percent && k >= matched )
-        {
-            os.setVisited();
-            return surfaceLine;
-        }
-        else
-        {
-            return null;
-        }
-    }
+
+
 
 }
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/surfaceLine/SurfaceLineY.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/surfaceLine/SurfaceLineY.java
index 9204b511cf3cdbfd54b4bc70a0eeda5065000278..66071ea9e79e12dd7210fadfedb4f5f04a0f647f 100644
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/surfaceLine/SurfaceLineY.java
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/element/surfaceLine/SurfaceLineY.java
@@ -1,7 +1,6 @@
 package fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine;
 
-import fr.pasteur.ida.zellige.surfaceConstruction.element.Coordinate;
-import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSE;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.AbstractOSE;
 
 public class SurfaceLineY extends SurfaceLine
 {
@@ -11,7 +10,7 @@ public class SurfaceLineY extends SurfaceLine
      *
      * @param os - a list of Coordinates to fill the pixel array.
      */
-    public SurfaceLineY( int length, OSE os )
+    public SurfaceLineY( int length, AbstractOSE os )
     {
         super(length,  os );
         this.setLine( os.get( 0 ).getX() );
@@ -32,46 +31,55 @@ public class SurfaceLineY extends SurfaceLine
      * Tests if the OS matches the SurfaceLine instance and creates a new SurfaceLine object if so.
      *
      * @param os      - the OS to test against the SurfaceLine instance.
-     * @param j       - an integer witch indicates the line of the resulting SurfaceLine.
-     * @param percent - the minimum percentage of match between the OS and the current instance.
-     * @param matched - the minimum number of matching coordinates.
+     * @param direction       - an integer witch indicates the line of the resulting SurfaceLine.
+     * @param overlap - the minimum number of matching coordinates.
+     * @param connexity - the minimum percentage of match between the OS and the current instance.
      * @return - a new SurfaceLine if there is a match, null otherwise.
      */
-    public SurfaceLine match( OSE os, int j, double percent, int matched )
+//    public SurfaceLine match( AbstractOSE os, int j, double percent, int matched )
+//    {
+//        SurfaceLineY surfaceLine = new SurfaceLineY(this.getLength(), this.getLine() + j );
+//        int match = 0;
+//        int k = 0;
+//        for ( int i = 0; i <= os.size() - 1; i++ )
+//        {
+//            int y = os.get( i ).getY();
+//            Coordinate coordinate = os.get( i );
+//            if ( this.get( y ) != null )
+//            {
+//                k++;
+//                if ( isAMatch( this.get( y ), coordinate ) )
+//                {
+//                    match++;
+//                }
+//            }
+//            surfaceLine.set( y, coordinate );
+//        }
+//        if ( k == 0 || match == 0 )
+//        {
+//            return null;
+//        }
+//        else if ( ( double ) match / ( double ) k >= percent && k >= matched )
+//        {
+////            System.out.println("percent = " + ( double ) match / ( double ) k);
+////            System.out.println("k = " + k);
+//            os.setVisited();
+//            return surfaceLine;
+//        }
+//        else
+//        {
+////            System.out.println("* percent = " + ( double ) match / ( double ) k);
+////            System.out.println("* k = " + k);
+//            return null;
+//        }
+//    }
+
+
+
+    public SurfaceLine match( AbstractOSE os, int direction, int overlap, double connexity )
     {
-        SurfaceLineY surfaceLine = new SurfaceLineY(this.getLength(), this.getLine() + j );
-        int match = 0;
-        int k = 0;
-        for ( int i = 0; i <= os.size() - 1; i++ )
-        {
-            int y = os.get( i ).getY();
-            Coordinate coordinate = os.get( i );
-            if ( this.get( y ) != null )
-            {
-                k++;
-                if ( isAMatch( this.get( y ), coordinate ) )
-                {
-                    match++;
-                }
-            }
-            surfaceLine.set( y, coordinate );
-        }
-        if ( k == 0 || match == 0 )
-        {
-            return null;
-        }
-        else if ( ( double ) match / ( double ) k >= percent && k >= matched )
-        {
-//            System.out.println("percent = " + ( double ) match / ( double ) k);
-//            System.out.println("k = " + k);
-            os.setVisited();
-            return surfaceLine;
-        }
-        else
-        {
-//            System.out.println("* percent = " + ( double ) match / ( double ) k);
-//            System.out.println("* k = " + k);
-            return null;
-        }
+        SurfaceLineY surfaceLineY = new SurfaceLineY( this.getLength(), this.getLine() + direction );
+        return this.match2( os, overlap, connexity, surfaceLineY);
     }
+
 }
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/AdvancedUserParameters.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/AdvancedUserParameters.java
deleted file mode 100644
index 1f91632024362c725cdfba3dca8391f57afff9c2..0000000000000000000000000000000000000000
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/AdvancedUserParameters.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package fr.pasteur.ida.zellige.surfaceConstruction.parameters;
-
-public class AdvancedUserParameters
-{
-    private int k1;
-    private double percent1;
-    private int k2;
-    private double percent2;
-
-    public AdvancedUserParameters( int k1, double percent1, int k2, double percent2 )
-    {
-        this.k1 = k1;
-        this.percent1 = percent1;
-        this.k2 = k2;
-        this.percent2 = percent2;
-    }
-
-    public int getK1()
-    {
-        return k1;
-    }
-
-    public void setK1( int k1 )
-    {
-        this.k1 = k1;
-    }
-
-    public double getPercent1()
-    {
-        return percent1;
-    }
-
-    public void setPercent1( double percent1 )
-    {
-        this.percent1 = percent1;
-    }
-
-    public int getK2()
-    {
-        return k2;
-    }
-
-    public void setK2( int k2 )
-    {
-        this.k2 = k2;
-    }
-
-    public double getPercent2()
-    {
-        return percent2;
-    }
-
-    public void setPercent2( double percent2 )
-    {
-        this.percent2 = percent2;
-    }
-}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/ConstructionParameters.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/ConstructionParameters.java
new file mode 100644
index 0000000000000000000000000000000000000000..a344dbf66671d221e09c02992c64293eb30c1667
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/ConstructionParameters.java
@@ -0,0 +1,32 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.parameters;
+
+public class ConstructionParameters
+{
+
+   private final double startingSizeThreshold;
+   private final int overlap;
+   private final double connexityRate;
+
+    public ConstructionParameters( double startingSizeThreshold, int overlap, double connexityRate )
+    {
+        this.startingSizeThreshold = startingSizeThreshold;
+        this.overlap = overlap;
+        this.connexityRate = connexityRate;
+    }
+
+
+    public double getStartingSizeThreshold()
+    {
+        return startingSizeThreshold;
+    }
+
+    public int getOverlap()
+    {
+        return overlap;
+    }
+
+    public double getConnexityRate()
+    {
+        return connexityRate;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/Parameters.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/Parameters.java
new file mode 100644
index 0000000000000000000000000000000000000000..a4aecc425b50e04a5a4f522b30ac7172d53005df
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/Parameters.java
@@ -0,0 +1,5 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.parameters;
+
+public class Parameters
+{
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/ProjectionParameters.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/ProjectionParameters.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f7c0b46542622c1c11176fe2920b7808a76a75e
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/ProjectionParameters.java
@@ -0,0 +1,66 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.parameters;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+
+public class ProjectionParameters
+{
+
+    private final int delta;
+    private final String projectionMethod;
+
+
+    public ProjectionParameters( int delta, String projectionMethod ) throws DataValidationException
+    {
+        projectionParametersValidationCheck( delta, projectionMethod );
+        this.delta = delta;
+        this.projectionMethod = projectionMethod;
+    }
+
+    /**
+     * Checks if the delta value is superior or equal to zero and throws an {@link DataValidationException} otherwise.
+     * @param value the delta value choose by the user. //TODO javadoc : extracted volume defined as delta x 2 + 1
+     * @throws DataValidationException - if the value is under zero.
+     */
+    private void deltaValidationCheck( int value ) throws DataValidationException
+    {
+        if ( value < 0 )
+        {
+            throw new DataValidationException( "The value of parameter Delta has to be superior to zero !" );
+        }
+    }
+
+    /**
+     *
+     * @param projectionMethod the method choose to projection the extracted surface.
+     * @throws DataValidationException if the method is not implemented (implemented methods are MIP, Mean, Median and MinIP).
+     */
+    private void projectionMethodValidationCheck( String projectionMethod ) throws DataValidationException
+    {
+        if ( ! projectionMethod.equals( "MIP" ) && ! projectionMethod.equals( "Mean" ) && ! projectionMethod.equals( "MinIP" ) && ! projectionMethod.equals( "Median" ) )
+        {
+            throw new DataValidationException( String.format( "The method %s is not implemented in Zellige !", projectionMethod ) );
+        }
+    }
+
+    /**
+     *  Checks the validity of both parameters.
+     * @param delta the extracted stack parameters //TODO javadoc : extracted volume defined as delta x 2 + 1
+     * @param projectionMethod the method choose to projection the extracted surface.
+     * @throws DataValidationException if at least one parameter is not valid.
+     */
+    private void projectionParametersValidationCheck( int delta, String projectionMethod ) throws DataValidationException
+    {
+        deltaValidationCheck( delta );
+        projectionMethodValidationCheck( projectionMethod );
+    }
+
+    public int getDelta()
+    {
+        return delta;
+    }
+
+    public String getProjectionType()
+    {
+        return projectionMethod;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/UserParameters.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/UserParameters.java
deleted file mode 100644
index 61352462a9825e5692f6934516bbfc7f680164d2..0000000000000000000000000000000000000000
--- a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/UserParameters.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package fr.pasteur.ida.zellige.surfaceConstruction.parameters;
-
-public class UserParameters
-{
-
-    private double amplitude;
-    private double threshold;
-    private double sigmas;
-    private int delta;
-    private String projectionType;
-
-
-    public UserParameters( double amplitude, double threshold, double sigmas, int delta , String projectionType)
-    {
-        this.amplitude = amplitude;
-        this.threshold = threshold;
-        this.sigmas = sigmas;
-        this.delta = delta;
-        this.projectionType = projectionType;
-
-    }
-
-    public double getAmplitude()
-    {
-        return amplitude;
-    }
-
-    public void setAmplitude( double amplitude )
-    {
-        this.amplitude = amplitude;
-    }
-
-    public double getThreshold()
-    {
-        return threshold;
-    }
-
-    public void setThreshold( double threshold )
-    {
-        this.threshold = threshold;
-    }
-
-    public double getSigmas()
-    {
-        return sigmas;
-    }
-
-    public void setSigmas( int sigmas )
-    {
-        this.sigmas = sigmas;
-    }
-
-    public int getDelta()
-    {
-        return delta;
-    }
-
-    public void setDelta( int delta )
-    {
-        this.delta = delta;
-    }
-
-    public String getProjectionType()
-    {
-        return projectionType;
-    }
-
-    public void setProjectionType( String projectionType )
-    {
-        this.projectionType = projectionType;
-    }
-}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/maximumSelection/PixelClassificationParameters.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/maximumSelection/PixelClassificationParameters.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ee37bffc13129d0127ee4621c939a75069ce7ea
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/maximumSelection/PixelClassificationParameters.java
@@ -0,0 +1,59 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection.Util;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.Parameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PixelClassificationParameters extends Parameters
+{
+    private final static Logger LOGGER = LoggerFactory.getLogger( PixelClassificationParameters.class );
+
+    private final double amplitudeThreshold, otsuThreshold;
+    public PixelClassificationParameters( double amplitudeThreshold, double otsuThreshold ) throws DataValidationException
+    {
+        classificationParametersValidationCheck( amplitudeThreshold, otsuThreshold );
+        this.amplitudeThreshold = amplitudeThreshold;
+        this.otsuThreshold = otsuThreshold;
+    }
+
+    /**
+     *
+     * @param name the parameter name to display in the error message.
+     * @param value the value of the parameter tested.
+     * @throws DataValidationException if the value is inferior to zero.
+     */
+    private void valueValidationCheck( String name, double value ) throws DataValidationException
+    {
+        if ( value < 0 )
+        {
+            throw new DataValidationException( "The value of parameter " + name + " has to be superior to zero !" );
+        }
+
+    }
+
+
+    /**
+     * Checks the four parameters validity.
+     * @param amplitudeThreshold - the value choose as amplitude threshold.
+     * @param otsuThreshold - the value choose as otsu threshold.
+     * @throws DataValidationException if at least one parameter is not valid.
+     */
+    public void classificationParametersValidationCheck( double amplitudeThreshold, double otsuThreshold) throws DataValidationException
+    {
+        valueValidationCheck( "Amplitude Threshold", amplitudeThreshold );
+        valueValidationCheck( "Otsu Threshold", otsuThreshold );
+    }
+
+
+    public double getAmplitudeThreshold()
+    {
+        return amplitudeThreshold;
+    }
+
+    public double getOtsuThreshold()
+    {
+        return otsuThreshold;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/maximumSelection/PixelSelectionParameters.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/maximumSelection/PixelSelectionParameters.java
new file mode 100644
index 0000000000000000000000000000000000000000..7326264ab854235eb16f555c7f8bcd203943b786
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/maximumSelection/PixelSelectionParameters.java
@@ -0,0 +1,32 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+
+public class PixelSelectionParameters
+{
+    PretreatmentParameters pretreatmentParameters;
+    PixelClassificationParameters classificationParameters;
+    PostTreatmentParameters postTreatmentParameters;
+
+    public PixelSelectionParameters( PretreatmentParameters pretreatmentParameters, PixelClassificationParameters classificationParameters, PostTreatmentParameters postTreatmentParameters )
+    {
+        this.pretreatmentParameters = pretreatmentParameters;
+        this.classificationParameters = classificationParameters;
+        this.postTreatmentParameters = postTreatmentParameters;
+    }
+
+    public PretreatmentParameters getPretreatmentParameters()
+    {
+        return pretreatmentParameters;
+    }
+
+    public PixelClassificationParameters getClassificationParameters()
+    {
+        return classificationParameters;
+    }
+
+    public PostTreatmentParameters getPostTreatmentParameters()
+    {
+        return postTreatmentParameters;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/maximumSelection/PostTreatmentParameters.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/maximumSelection/PostTreatmentParameters.java
new file mode 100644
index 0000000000000000000000000000000000000000..0786164b02de60cdbd9faee854277cba3949bdd2
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/maximumSelection/PostTreatmentParameters.java
@@ -0,0 +1,85 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.Parameters;
+
+public class PostTreatmentParameters extends Parameters
+{
+
+    public static final String SIGMA_XY = "Sigma XY";
+    public static final String SIGMA_Z = "Sigma Z";
+    public static final String ISLAND_SIZE = "Island size";
+    public static final String CONNEXITY = "connexity";
+    private final double sigmaXY,  sigmaZ;
+    private final int islandSize, connexity;
+
+
+    public PostTreatmentParameters( double sigmaXY, double sigmaZ, int islandSize, int connexity ) throws DataValidationException
+    {
+        postTreatmentParametersValidationCheck( sigmaXY, sigmaZ , islandSize);
+        this.sigmaXY = sigmaXY;
+        this.sigmaZ = sigmaZ;
+        this.islandSize = islandSize;
+        this.connexity = connexity;
+
+    }
+
+
+    /**
+     * Checks the four parameters validity.
+     * @param sigmaXY the value choose for the XY image dilatation.
+     * @param sigmaZ the value choose for the Z image dilatation.
+     * @throws DataValidationException if at least one parameter is not valid.
+     */
+    public void postTreatmentParametersValidationCheck( double sigmaXY, double sigmaZ, int islandSize) throws DataValidationException
+    {
+        valueValidationCheck( SIGMA_XY, sigmaXY );
+        valueValidationCheck( SIGMA_Z, sigmaZ);
+        valueValidationCheck( ISLAND_SIZE , islandSize);
+    }
+
+    /**
+     *
+     * @param name the parameter name to display in the error message.
+     * @param value the value of the parameter tested.
+     * @throws DataValidationException if the value is inferior to zero.
+     */
+    private void valueValidationCheck( String name, double value ) throws DataValidationException
+    {
+        if (name.equals( CONNEXITY ))
+        {
+            if (value!= 4 && value!= 8)
+            {
+                throw new DataValidationException( "The value of parameter " + name + " has to be 4 or 8 !" );
+            }
+        }
+        else
+        {
+            if ( value < 0 )
+            {
+                throw new DataValidationException( "The value of parameter " + name + " has to be superior to zero !" );
+            }
+        }
+
+    }
+
+    public double getSigmaXY()
+    {
+        return sigmaXY;
+    }
+
+    public double getSigmaZ()
+    {
+        return sigmaZ;
+    }
+
+    public int getIslandSize()
+    {
+        return islandSize;
+    }
+
+    public int getConnexity()
+    {
+        return connexity;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/maximumSelection/PretreatmentParameters.java b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/maximumSelection/PretreatmentParameters.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9bc13adee1926837370884028f46aac2b1b8a97
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/maximumSelection/PretreatmentParameters.java
@@ -0,0 +1,76 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.Parameters;
+
+public class PretreatmentParameters extends Parameters
+{
+    public static final String MEDIAN = "Median";
+    public static final String GAUSSIAN_BLUR = "GaussianBlur";
+    public static final String NOT_IMPLEMENTED = "not implemented";
+    private final String method;
+    private final double[] parameters;
+
+
+    public PretreatmentParameters( String method, double[] parameters ) throws DataValidationException
+    {
+        this.checkParameters(method, parameters);
+        this.method = method;
+        this.parameters = parameters;
+    }
+
+    /**
+     * Checks if the method end the arguments methods are valid
+     * @param method the method choose
+     * @param parameters the method arguments
+     * @throws DataValidationException if at least one is not valid
+     */
+    private void checkParameters( String method, double[] parameters ) throws DataValidationException
+    {
+        checkDenoisingMethod( method );
+        checkParametersLength(method, parameters);
+    }
+
+    /**
+     * Checks the length of the parameters according to the method choose
+     * @param method the method choose
+     * @param parameters the method arguments
+     * @throws DataValidationException if at the pramaters legnth (the number of arguments) is not valid according to the method choose
+     */
+    private void checkParametersLength( String method, double[] parameters ) throws DataValidationException
+    {
+        if (method.equals( GAUSSIAN_BLUR ) && parameters.length != 3)
+        {
+            throw new DataValidationException( "The parameters for the " + method + " requires 3 arguments " +
+                    "(one for each image dimensions)");
+        }
+        if (method.equals( MEDIAN ) && parameters.length != 1)
+        {
+            throw new DataValidationException( "The " + method + "method requires only one arguments " +
+                    "(radius)" );
+        }
+    }
+
+    /**
+     * Check if the denoising method is valid.
+     * @param denoisingMethod the input denoising method
+     * @throws DataValidationException if the method is not valid
+     */
+    public void checkDenoisingMethod( String denoisingMethod ) throws DataValidationException
+    {
+        if ( ! denoisingMethod.equals( GAUSSIAN_BLUR ) && ! denoisingMethod.equals( MEDIAN ) )
+        {
+            throw new DataValidationException( "The denoising method " + denoisingMethod + " is " + NOT_IMPLEMENTED + " in the program" );
+        }
+    }
+
+    public String getMethod()
+    {
+        return method;
+    }
+
+    public double[] getParameters()
+    {
+        return parameters;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/utils/CSVWriter.java b/src/main/java/fr/pasteur/ida/zellige/utils/CSVWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..8d6492be1cf7b1b867231562e6882396751a841f
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/utils/CSVWriter.java
@@ -0,0 +1,78 @@
+package fr.pasteur.ida.zellige.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+
+public class CSVWriter
+{
+
+    private BufferedWriter bw;
+    private final static String EXTENSION = ".csv";
+
+    private final static Logger LOGGER = LoggerFactory.getLogger( CSVWriter.class );
+
+    public CSVWriter( String testedFileName )
+    {
+        String path = "target/" +testedFileName + EXTENSION;
+
+        LOGGER.info( "CSV file name : {}", path );
+        File csvOutputFile = new File( path );
+        try
+        {
+            bw = new BufferedWriter( new FileWriter( csvOutputFile ) );
+            LOGGER.info("CSV location : " + "target/" + testedFileName + EXTENSION);
+        }
+       catch ( IOException ioException )
+       {
+           LOGGER.debug(" The csv file has not be created");
+       }
+    }
+
+    public void writeToFile( String line ) throws IOException
+    {
+        bw.write(line);
+        bw.newLine();
+        LOGGER.info( " New line added in CSV file" );
+    }
+
+    public void writeToFile( String testedParameter, String testedParameterValue, int pixelNumber, double Rmse, double coverage ) throws IOException
+    {
+        String line = convertToCSV( testedParameter,testedParameterValue, pixelNumber, Rmse, coverage );
+        writeToFile( line );
+    }
+
+    public String convertToCSV( String testedParameter, String testedParameterValue, int pixelNumber, double Rmse, double coverage ) {
+        String [] data = buildStringLine(testedParameter,testedParameterValue, pixelNumber, Rmse, coverage );
+        return String.join( ";", data );
+    }
+
+
+    public String [] buildStringLine( String testedParameter, String testedParameterValue, int pixelNumber, double Rmse, double coverage, double weightedRMSE )
+    {
+        return new String[]{testedParameter, testedParameterValue, String.valueOf( pixelNumber ), String.valueOf( Rmse ), String.valueOf( coverage ), String.valueOf(  weightedRMSE )};
+    }
+
+    public void writeToFile( String testedParameter, String testedParameterValue, int pixelNumber, double Rmse, double coverage, double weightedRMSE ) throws IOException
+    {
+        String line = convertToCSV( testedParameter,testedParameterValue, pixelNumber, Rmse, coverage , weightedRMSE);
+        writeToFile( line );
+    }
+
+    public String convertToCSV( String testedParameter, String testedParameterValue, int pixelNumber, double Rmse, double coverage, double weightedRMSE ) {
+        String [] data = buildStringLine(testedParameter,testedParameterValue, pixelNumber, Rmse, coverage, weightedRMSE );
+        return String.join( ";", data );
+    }
+
+
+    public String [] buildStringLine( String testedParameter, String testedParameterValue, int pixelNumber, double Rmse, double coverage )
+    {
+        return new String[]{testedParameter, testedParameterValue, String.valueOf( pixelNumber ), String.valueOf( Rmse ), String.valueOf( coverage )};
+    }
+
+    public void close() throws IOException
+    {
+        bw.close();
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/utils/LocalOtsuClassification.java b/src/main/java/fr/pasteur/ida/zellige/utils/LocalOtsuClassification.java
deleted file mode 100644
index c7a4ecb329d9af6847222aaf45bad4fac5673e09..0000000000000000000000000000000000000000
--- a/src/main/java/fr/pasteur/ida/zellige/utils/LocalOtsuClassification.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package fr.pasteur.ida.zellige.utils;
-
-import net.imglib2.*;
-import net.imglib2.algorithm.util.Grids;
-import net.imglib2.img.Img;
-import net.imglib2.img.ImgFactory;
-import net.imglib2.img.display.imagej.ImageJFunctions;
-import net.imglib2.type.NativeType;
-import net.imglib2.type.logic.BitType;
-import net.imglib2.type.numeric.RealType;
-import net.imglib2.util.Util;
-import net.imglib2.view.IntervalView;
-import net.imglib2.view.Views;
-
-import java.util.List;
-
-/**
- *
- */
-public class LocalOtsuClassification
-{
-
-    /**
-     * @param input   the input {@link Img}
-     * @param percent the percentage of global otsu value
-     * @param <T>     the type on the input
-     * @return a 3D binary {@link Img<BitType>}
-     */
-    public static < T extends RealType< T > & NativeType< T > > Img< BitType > find( final RandomAccessibleInterval< T > input,ImgFactory<T> factory, double percent )
-    {
-        // Prepare output.
-        final ImgFactory< BitType > bitTypeImgFactory = Util.getArrayOrCellImgFactory( input, new BitType() );
-        Img< BitType > binary = bitTypeImgFactory.create( input );
-        new OtsuThreshold<>( input,factory, binary, percent );
-        return binary;
-    }
-
-
-    /**
-     * @param <T>
-     */
-    private static final class OtsuThreshold< T extends RealType< T > & NativeType< T > >
-    {
-        private final RandomAccessibleInterval< T > source;
-        private final ImgFactory<T> factory;
-        private final RandomAccessibleInterval< T > grid;
-        private final Img< BitType > binary;
-        private final double percent;
-
-        /**
-         * @param source  the input {@link Img}
-         * @param binary  the resulting binary image as a {@link Img<BitType> }
-         * @param percent the percentage of global otsu value
-         */
-        private OtsuThreshold( final RandomAccessibleInterval< T > source, final ImgFactory<T> factory, final Img< BitType > binary, double percent )
-        {
-            this.source = source;
-            this.factory = factory;
-            this.binary = binary;
-            this.percent = percent;
-            this.grid = factory.create( source );
-            run();
-        }
-
-        /**
-         *
-         */
-        public void run()
-        {
-            computeLocalThreshold( source, factory, grid );
-            applyLocalThreshold( Views.iterable( source) ,Views.iterable(  grid), binary, percent );
-        }
-
-
-        /**
-         * @param input the input {@link Img}
-         * @param grid  the image containing the grid of local thresholds
-         * @param <T>   the type on the input
-         */
-        public static < T extends RealType< T > & NativeType< T > > void
-        computeLocalThreshold( RandomAccessibleInterval< T > input, ImgFactory<T> factory,RandomAccessibleInterval< T > grid )
-        {
-            long width = input.dimension( 0 );
-            long height = input.dimension( 1 );
-            long depth = input.dimension( 2 );
-            List< Interval > intervals = Grids.collectAllContainedIntervals( new long[]{ width, height, depth },
-                    new int[]{ 50, 50, 3 } );//TODO Size of a grid cube ?
-
-            for ( Interval interval : intervals )
-            {
-                computeLocalThreshold( input, grid, interval );
-            }
-            grid = Utils.gaussConvolution(  grid,factory,  new double[]{ 5, 5, 1 } );
-        }
-
-        public static < T extends RealType< T > & NativeType< T > > void
-        computeLocalThreshold( RandomAccessibleInterval< T > input, RandomAccessibleInterval< T > grid, Interval interval )
-        {
-            IntervalView< T > viewSource = Views.offsetInterval( input, interval );
-            IntervalView< T > viewGrid = Views.offsetInterval( grid, interval );
-            T threshold = Otsu.getThreshold( viewSource );
-            viewGrid.forEach( pixel -> pixel.set( threshold ) );
-        }
-
-        /**
-         * @param input   the input image as an {@link IterableInterval}
-         * @param grid    the image containing the grid of local thresholds as an {@link IterableInterval}
-         * @param binary  the resulting binary image as a {@link RandomAccessibleInterval<BitType> }
-         * @param percent the percentage of global otsu value
-         * @param <T>     the input type
-         */
-        public static < T extends RealType< T > & NativeType< T > > void
-        applyLocalThreshold( IterableInterval< T > input, IterableInterval< T > grid, RandomAccessibleInterval< BitType > binary, double percent )
-        {
-            double threshold = Threshold.getThreshold( input, percent ).getRealDouble();
-            Cursor< T > sourceCursor = input.localizingCursor();
-            Cursor< T > outputCursor = grid.cursor();
-            RandomAccess< BitType > randomAccess = binary.randomAccess();
-            while ( sourceCursor.hasNext() )
-            {
-                sourceCursor.fwd();
-                outputCursor.fwd();
-                final double s = sourceCursor.get().getRealDouble();
-                final double o = outputCursor.get().getRealDouble();
-                {
-                    if ( s >= Math.max( o, threshold ) )// background subtraction
-                    {
-                        randomAccess.setPosition( sourceCursor );
-                        randomAccess.get().set( true );
-                    }
-                }
-            }
-            ImageJFunctions.show( binary, "binary" );
-        }
-
-
-        /**
-         * @return the image containing the grid of local thresholds
-         */
-        public Img< BitType > getGrid()
-        {
-            return binary;
-        }
-    }
-
-
-}
-
-
-
diff --git a/src/main/java/fr/pasteur/ida/zellige/utils/MaximumAmplitudeClassification.java b/src/main/java/fr/pasteur/ida/zellige/utils/MaximumAmplitudeClassification.java
deleted file mode 100644
index 178d6d6633c4fd30cd8a6641830f89419aa2ae3c..0000000000000000000000000000000000000000
--- a/src/main/java/fr/pasteur/ida/zellige/utils/MaximumAmplitudeClassification.java
+++ /dev/null
@@ -1,269 +0,0 @@
-package fr.pasteur.ida.zellige.utils;
-
-import net.imglib2.Cursor;
-import net.imglib2.Interval;
-import net.imglib2.RandomAccess;
-import net.imglib2.RandomAccessibleInterval;
-import net.imglib2.algorithm.binary.Thresholder;
-import net.imglib2.algorithm.util.Grids;
-import net.imglib2.img.Img;
-import net.imglib2.img.ImgFactory;
-import net.imglib2.img.array.ArrayImgFactory;
-import net.imglib2.img.display.imagej.ImageJFunctions;
-import net.imglib2.type.NativeType;
-import net.imglib2.type.logic.BitType;
-import net.imglib2.type.numeric.RealType;
-import net.imglib2.type.numeric.real.FloatType;
-import net.imglib2.util.Util;
-import net.imglib2.view.IntervalView;
-import net.imglib2.view.Views;
-
-import java.util.List;
-
-/**
- * This class makes it possible to get a binary classification of the pixels (background/ foreground) according to their amplitude and their amplitude's neighborhood.
- * First, the amplitude of all local maximums is computed and stored as an {@link Img}. This {@link Img}  is cut into squares (15x15) then depending on the number of pixels contained in
- * each square, the latter will be classified as background or foreground.
- */
-public class MaximumAmplitudeClassification
-{
-
-    /**
-     * @param input              - the input image as a {@link RandomAccessibleInterval}
-     * @param amplitudeThreshold - the parameter user value to apply to the first mode of the image histogram.
-     * @param sizePercent        the minimum percentage of pixels for isolated pixel elimination
-     * @param <T>                - the type of the input
-     * @return a binary image of background foreground classification
-     */
-    public static < T extends RealType< T > & NativeType< T > > Img< FloatType > find( final RandomAccessibleInterval< T > input,
-                                                                                       final ImgFactory< T > factory, double amplitudeThreshold, double sizePercent )
-    {
-        // Prepare output.
-        Img< BitType > amplitude = new ArrayImgFactory<>( new BitType() ).create( input );
-        MaximumAmplitude< T > maximumAmplitude = new MaximumAmplitude<>( input, factory, amplitude, amplitudeThreshold );
-        final ImgFactory< FloatType > floatTypeImgFactory = Util.getArrayOrCellImgFactory( input, new FloatType() );
-        Img< FloatType > output = floatTypeImgFactory.create( input );
-        new BackgroundForegroundGrid( maximumAmplitude.getAmplitude(), output, sizePercent );
-        Utils.gaussConvolution( output.copy(), output, new double[]{ 0, 0, 0.5 } );
-        ImageJFunctions.show( output, "new class amplitude" );
-        return output;
-    }
-
-    /**
-     * This class generate a binary image according to a percentage of the smallest mode value  of the input image
-     *
-     * @param <T> the type of the input {@link Img}
-     */
-    private static final class MaximumAmplitude< T extends RealType< T > & NativeType< T > >
-    {
-        private final RandomAccessibleInterval< T > input;
-        private final ImgFactory< T > factory;
-        private final double amplitudeThreshold;
-        private RandomAccessibleInterval< BitType > amplitude;
-
-        public MaximumAmplitude( RandomAccessibleInterval< T > input, ImgFactory< T > factory, RandomAccessibleInterval< BitType > amplitude, double amplitudeThreshold )
-        {
-            this.input = input;
-            this.factory = factory;
-            this.amplitude = amplitude;
-            this.amplitudeThreshold = amplitudeThreshold;
-            run();
-        }
-
-        /**
-         * @param max the image containing only the values of local maximums
-         * @param min the image containing only the values of local minimums
-         * @param <T> the type of both images {@link Img}
-         * @return an image containing the value of the maximums amplitude
-         */
-        private static < T extends RealType< T > & NativeType< T > > Img< T > getAmplitude(
-                RandomAccessibleInterval< T > max, ImgFactory< T > factory, RandomAccessibleInterval< T > min )
-        {
-            Img< T > amp = factory.create( max );
-            RandomAccess< T > maxAccess = max.randomAccess();
-            RandomAccess< T > minAccess = min.randomAccess();
-            RandomAccess< T > ampAccess = amp.randomAccess();
-            for ( int x = 0; x <= max.dimension( 0 ) - 1; x++ )
-            {
-                maxAccess.setPosition( x, 0 );
-                for ( int y = 0; y <= max.dimension( 1 ) - 1; y++ )
-                {
-                    maxAccess.setPosition( y, 1 );
-                    for ( int z = 0; z <= max.dimension( 2 ) - 1; z++ )
-
-                    {
-                        maxAccess.setPosition( z, 2 );
-                        double maxValue = maxAccess.get().getRealDouble();
-                        if ( maxValue != 0 )
-                        {
-                            minAccess.setPosition( maxAccess );
-                            double amplitude = getAmplitude( maxValue, minAccess, ( int ) max.dimension( 2 ) );
-                            ampAccess.setPosition( maxAccess );
-                            ampAccess.get().setReal( amplitude );
-                        }
-                    }
-                }
-            }
-            ImageJFunctions.show (amp," neutral amp");
-            return amp;
-        }
-
-        /**
-         * @param maxValue  the intensity value at local maximum positioned at minAccess location
-         * @param minAccess - the random access positioned at  the same specific local maximum location
-         * @param <T>       the type of the {@link RandomAccess}
-         * @return the chosen amplitude value of the local maximum positioned at minAccess location
-         */
-        private static < T extends RealType< T > & NativeType< T > > double getAmplitude( double maxValue, RandomAccess< T > minAccess, int depth )
-        {
-            double up = findValueUp( minAccess, maxValue );
-            double down = findValueDown( minAccess, maxValue, depth );
-            double result = Math.max( Math.abs( maxValue - up ), Math.abs( maxValue - down ) );
-            if ( result == 0 )
-            {
-                return maxValue;
-
-            }
-            return ( result );
-        }
-
-        /**
-         * @param minAccess the random access of the local minimum image
-         * @param maxValue  the intensity value of the local maximum located at minAccess position
-         * @param <T>       the type of the {@link RandomAccess}
-         * @return the amplitude value above the local maximum location in the Z dimension
-         */
-        private static < T extends RealType< T > & NativeType< T > > double findValueUp(
-                RandomAccess< T > minAccess, double maxValue )
-        {
-            int start = minAccess.getIntPosition( 2 );
-            for ( int z = start - 1; z >= 0; z-- )
-            {
-                minAccess.setPosition( z, 2 );
-                double value = minAccess.get().getRealDouble();
-                if ( value != 0 )
-                {
-                    return value;
-                }
-            }
-            return maxValue;
-        }
-
-        /**
-         * @param minAccess the random access of the local minimum image
-         * @param maxValue  the intensity value of the local maximum located at minAccess position
-         * @param <T>       the type of the {@link RandomAccess}
-         * @return the amplitude value below the local maximum location in the Z dimension
-         */
-        private static < T extends RealType< T > & NativeType< T > > double findValueDown(
-                RandomAccess< T > minAccess, double maxValue, int depth )
-        {
-            int start = minAccess.getIntPosition( 2 );
-            for ( int z = start + 1; z <= depth - 1; z++ )
-            {
-                minAccess.setPosition( z, 2 );
-                double value = minAccess.get().getRealDouble();
-                if ( value != 0 )
-                {
-                    return value;
-                }
-            }
-            return maxValue;
-        }
-
-        public void run()
-        {
-            Img< T > maximums = LocalExtremaDetection.findMaxima( input, factory );
-            Img< T > minimums = LocalExtremaDetection.findMinima( input, factory );
-            Img< T > amp = getAmplitude( maximums, factory, minimums );
-            ImageJFunctions.show(amp, "neutral amp 2");
-            T TMax = Threshold.getFirstMaxValue( amp, false );
-            System.out.println("Amplitude threshold value before user = " + TMax);
-            TMax.mul( amplitudeThreshold );
-            System.out.println("Amplitude threshold value after user = " + TMax);
-            this.amplitude = Thresholder.threshold( amp.copy(), TMax, true, 2 );
-
-        }
-
-        public RandomAccessibleInterval< BitType > getAmplitude()
-        {
-            return amplitude;
-        }
-    }
-
-    /**
-     * This class allows the elimination of isolated pixels. the image is containing the amplitude values of each local maximums is split into {15 x 15 x 1} sections,
-     * and the sections containing less than  the size percent value are set to zero.
-     */
-    private static final class BackgroundForegroundGrid
-    {
-        private final RandomAccessibleInterval< BitType > source;
-        private final RandomAccessibleInterval< FloatType > output;
-        private final double sizePercent;
-
-        /**
-         * @param source      - the input  as a 2D {@link Img<BitType> }
-         * @param output      - the output as a 2D {@link Img<FloatType> }
-         * @param sizePercent - the minimum percentage of positive pixels
-         */
-        private BackgroundForegroundGrid( final RandomAccessibleInterval< BitType > source, Img< FloatType > output, double sizePercent )
-        {
-            this.source = source;
-            this.output = output;
-            this.sizePercent = sizePercent;
-            run();
-        }
-
-        /**
-         * @param intervalView a sub 2D image
-         * @param sizePercent  the minimum percentage of pixels for isolated pixel elimination
-         * @param <T>          the type of the sub image
-         * @return true if the sub image does contain enough foreground pixels false otherwise
-         */
-        public static < T extends RealType< T > & NativeType< T > > boolean isForeground( IntervalView< T > intervalView, double sizePercent )
-        {
-            double sum = 0;
-            Cursor< T > cursor = intervalView.cursor();
-            while ( cursor.hasNext() )
-            {
-                cursor.fwd();
-                if ( cursor.get().getRealDouble() != 0 )
-                {
-                    sum++;
-                }
-            }
-            return ( sum ) > ( intervalView.dimension( 0 ) * intervalView.dimension( 1 ) * sizePercent );
-        }
-
-        /**
-         *
-         */
-        public void run()
-        {
-            long width = source.dimension( 0 );
-            long height = source.dimension( 1 );
-            long depth = source.dimension( 2 );
-            List< Interval > intervals = Grids.collectAllContainedIntervals( new long[]{ width, height, depth },
-                    new int[]{ 15, 15, 1 } );
-
-            for ( Interval interval : intervals )
-            {
-                IntervalView< BitType > viewSource = Views.offsetInterval( source, interval );
-                IntervalView< FloatType > viewOutput = Views.offsetInterval( output, interval );
-                int foreground = isForeground( viewSource, sizePercent ) ? 1 : 0;
-                viewOutput.forEach( pixel -> pixel.setReal( foreground ) );
-            }
-            // Slight dilatation in z dimension
-
-        }
-
-        /**
-         * @return the smoothed amplitude classified image
-         */
-        public RandomAccessibleInterval< FloatType > getOutput()
-        {
-            return output;
-        }
-    }
-
-}
diff --git a/src/main/java/fr/pasteur/ida/zellige/utils/MaximumAmplitudeClassification2.java b/src/main/java/fr/pasteur/ida/zellige/utils/MaximumAmplitudeClassification2.java
deleted file mode 100644
index b8168a6c938f359b7fa1d4e3356632c3c0b0732a..0000000000000000000000000000000000000000
--- a/src/main/java/fr/pasteur/ida/zellige/utils/MaximumAmplitudeClassification2.java
+++ /dev/null
@@ -1,177 +0,0 @@
-package fr.pasteur.ida.zellige.utils;
-
-import net.imglib2.RandomAccess;
-import net.imglib2.RandomAccessibleInterval;
-import net.imglib2.algorithm.binary.Thresholder;
-import net.imglib2.img.Img;
-import net.imglib2.img.ImgFactory;
-import net.imglib2.img.array.ArrayImgFactory;
-import net.imglib2.img.display.imagej.ImageJFunctions;
-import net.imglib2.type.NativeType;
-import net.imglib2.type.logic.BitType;
-import net.imglib2.type.numeric.RealType;
-
-/**
- * This class makes it possible to get a binary classification of the pixels (background/ foreground) according to their amplitude and their amplitude's neighborhood.
- * First, the amplitude of all local maximums is computed and stored as an {@link Img}. This {@link Img}  is cut into squares (15x15) then depending on the number of pixels contained in
- * each square, the latter will be classified as background or foreground.
- */
-public class MaximumAmplitudeClassification2
-{
-
-    /**
-     * @param <T>                - the type of the input
-     * @param input              - the input image as a {@link RandomAccessibleInterval}
-     * @param amplitudeThreshold - the parameter user value to apply to the first mode of the image histogram.
-     * @return a binary image of background foreground classification
-     */
-    public static < T extends RealType< T > & NativeType< T > > Img< BitType > find( final RandomAccessibleInterval< T > input,
-                                                                                     final ImgFactory< T > factory, double amplitudeThreshold )
-    {
-        // Prepare output.
-        Img< BitType > amplitude = new ArrayImgFactory<>( new BitType() ).create( input );
-        MaximumAmplitude< T > maximumAmplitude = new MaximumAmplitude<>( input, factory, amplitude, amplitudeThreshold );
-//        Utils.gaussConvolution( maximumAmplitude.getAmplitude().copy(), maximumAmplitude.getAmplitude(), new double[]{ 0, 0, 0.5 } );
-        return maximumAmplitude.getAmplitude();
-    }
-
-    /**
-     * This class generate a binary image according to a percentage of the smallest mode value  of the input image
-     *
-     * @param <T> the type of the input {@link Img}
-     */
-    private static final class MaximumAmplitude< T extends RealType< T > & NativeType< T > >
-    {
-        private final RandomAccessibleInterval< T > input;
-        private final ImgFactory< T > factory;
-        private final double amplitudeThreshold;
-        private Img< BitType > amplitude;
-
-        public MaximumAmplitude( RandomAccessibleInterval< T > input, ImgFactory< T > factory, Img< BitType > amplitude, double amplitudeThreshold )
-        {
-            this.input = input;
-            this.factory = factory;
-            this.amplitude = amplitude;
-            this.amplitudeThreshold = amplitudeThreshold;
-            run();
-        }
-
-        public void run()
-        {
-            Img< T > maximums = LocalExtremaDetection.findMaxima( input, factory );
-            Img< T > minimums = LocalExtremaDetection.findMinima( input, factory );
-            Img< T > amp = getAmplitude( maximums, factory, minimums );
-            T TMax = Threshold.getFirstMaxValue( maximums, false );
-            System.out.println("Amplitude threshold value before user = " + TMax);
-            TMax.mul( amplitudeThreshold );
-            System.out.println("Amplitude threshold value after user = " + TMax);
-            this.amplitude = Thresholder.threshold( amp.copy(), TMax, true, 2 );
-        }
-
-        /**
-         * @param max the image containing only the values of local maximums
-         * @param min the image containing only the values of local minimums
-         * @param <T> the type of both images {@link Img}
-         * @return an image containing the value of the maximums amplitude
-         */
-        private static < T extends RealType< T > & NativeType< T > > Img< T > getAmplitude(
-                RandomAccessibleInterval< T > max, ImgFactory< T > factory, RandomAccessibleInterval< T > min )
-        {
-            Img< T > amp = factory.create( max );
-            RandomAccess< T > maxAccess = max.randomAccess();
-            RandomAccess< T > minAccess = min.randomAccess();
-            RandomAccess< T > ampAccess = amp.randomAccess();
-            for ( int x = 0; x <= max.dimension( 0 ) - 1; x++ )
-            {
-                maxAccess.setPosition( x, 0 );
-                for ( int y = 0; y <= max.dimension( 1 ) - 1; y++ )
-                {
-                    maxAccess.setPosition( y, 1 );
-                    for ( int z = 0; z <= max.dimension( 2 ) - 1; z++ )
-
-                    {
-                        maxAccess.setPosition( z, 2 );
-                        double maxValue = maxAccess.get().getRealDouble();
-                        if ( maxValue != 0 )
-                        {
-                            minAccess.setPosition( maxAccess );
-                            double amplitude = getAmplitude( maxValue, minAccess, ( int ) max.dimension( 2 ) );
-                            ampAccess.setPosition( maxAccess );
-                            ampAccess.get().setReal( amplitude );
-                        }
-                    }
-                }
-            }
-            ImageJFunctions.show (amp," neutral amp");
-            return amp;
-        }
-
-        /**
-         * @param maxValue  the intensity value at local maximum positioned at minAccess location
-         * @param minAccess - the random access positioned at  the same specific local maximum location
-         * @param <T>       the type of the {@link RandomAccess}
-         * @return the chosen amplitude value of the local maximum positioned at minAccess location
-         */
-        private static < T extends RealType< T > & NativeType< T > > double getAmplitude( double maxValue, RandomAccess< T > minAccess, int depth )
-        {
-            double up = findValueUp( minAccess, maxValue );
-            double down = findValueDown( minAccess, maxValue, depth );
-            double result = Math.max( Math.abs( maxValue - up ), Math.abs( maxValue - down ) );
-            if ( result == 0 )
-            {
-                return maxValue;
-
-            }
-            return ( result );
-        }
-
-        /**
-         * @param minAccess the random access of the local minimum image
-         * @param maxValue  the intensity value of the local maximum located at minAccess position
-         * @param <T>       the type of the {@link RandomAccess}
-         * @return the amplitude value above the local maximum location in the Z dimension
-         */
-        private static < T extends RealType< T > & NativeType< T > > double findValueUp(
-                RandomAccess< T > minAccess, double maxValue )
-        {
-            int start = minAccess.getIntPosition( 2 );
-            for ( int z = start - 1; z >= 0; z-- )
-            {
-                minAccess.setPosition( z, 2 );
-                double value = minAccess.get().getRealDouble();
-                if ( value != 0 )
-                {
-                    return value;
-                }
-            }
-            return maxValue;
-        }
-
-        /**
-         * @param minAccess the random access of the local minimum image
-         * @param maxValue  the intensity value of the local maximum located at minAccess position
-         * @param <T>       the type of the {@link RandomAccess}
-         * @return the amplitude value below the local maximum location in the Z dimension
-         */
-        private static < T extends RealType< T > & NativeType< T > > double findValueDown(
-                RandomAccess< T > minAccess, double maxValue, int depth )
-        {
-            int start = minAccess.getIntPosition( 2 );
-            for ( int z = start + 1; z <= depth - 1; z++ )
-            {
-                minAccess.setPosition( z, 2 );
-                double value = minAccess.get().getRealDouble();
-                if ( value != 0 )
-                {
-                    return value;
-                }
-            }
-            return maxValue;
-        }
-
-        public Img< BitType > getAmplitude()
-        {
-            return amplitude;
-        }
-    }
-}
diff --git a/src/main/java/fr/pasteur/ida/zellige/utils/MaximumAmplitudeClassification3.java b/src/main/java/fr/pasteur/ida/zellige/utils/MaximumAmplitudeClassification3.java
deleted file mode 100644
index 07626f2b40bb2e588951228be74ce6822800ea05..0000000000000000000000000000000000000000
--- a/src/main/java/fr/pasteur/ida/zellige/utils/MaximumAmplitudeClassification3.java
+++ /dev/null
@@ -1,271 +0,0 @@
-package fr.pasteur.ida.zellige.utils;
-
-import net.imglib2.Cursor;
-import net.imglib2.Interval;
-import net.imglib2.RandomAccess;
-import net.imglib2.RandomAccessibleInterval;
-import net.imglib2.algorithm.binary.Thresholder;
-import net.imglib2.algorithm.util.Grids;
-import net.imglib2.img.Img;
-import net.imglib2.img.ImgFactory;
-import net.imglib2.img.array.ArrayImgFactory;
-import net.imglib2.img.display.imagej.ImageJFunctions;
-import net.imglib2.type.NativeType;
-import net.imglib2.type.logic.BitType;
-import net.imglib2.type.numeric.RealType;
-import net.imglib2.type.numeric.real.FloatType;
-import net.imglib2.util.Util;
-import net.imglib2.view.IntervalView;
-import net.imglib2.view.Views;
-
-import java.util.List;
-
-/**
- * This class makes it possible to get a binary classification of the pixels (background/ foreground) according to their amplitude and their amplitude's neighborhood.
- * First, the amplitude of all local maximums is computed and stored as an {@link Img}. This {@link Img}  is cut into squares (15x15) then depending on the number of pixels contained in
- * each square, the latter will be classified as background or foreground.
- */
-public class MaximumAmplitudeClassification3
-{
-
-    /**
-     * @param input              - the input image as a {@link RandomAccessibleInterval}
-     * @param amplitudeThreshold - the parameter user value to apply to the first mode of the image histogram.
-     * @param sizePercent        the minimum percentage of pixels for isolated pixel elimination
-     * @param <T>                - the type of the input
-     * @return a binary image of background foreground classification
-     */
-    public static < T extends RealType< T > & NativeType< T > > Img< FloatType > find( final RandomAccessibleInterval< T > input,
-                                                                                       final ImgFactory< T > factory, double amplitudeThreshold, double sizePercent )
-    {
-        // Prepare output.
-        Img< BitType > amplitude = new ArrayImgFactory<>( new BitType() ).create( input );
-        MaximumAmplitude< T > maximumAmplitude = new MaximumAmplitude<>( input, factory, amplitude, amplitudeThreshold );
-        final ImgFactory< FloatType > floatTypeImgFactory = Util.getArrayOrCellImgFactory( input, new FloatType() );
-        Img< FloatType > output = floatTypeImgFactory.create( input );
-        new BackgroundForegroundGrid( maximumAmplitude.getAmplitude(), output, sizePercent );
-//        Utils.gaussConvolution( output.copy(), output, new double[]{ 0, 0, 0.5 } );
-        ImageJFunctions.show( output, "new class amplitude" );
-        return output;
-    }
-
-    /**
-     * This class generate a binary image according to a percentage of the smallest mode value  of the input image
-     *
-     * @param <T> the type of the input {@link Img}
-     */
-    private static final class MaximumAmplitude< T extends RealType< T > & NativeType< T > >
-    {
-        private final RandomAccessibleInterval< T > input;
-        private final ImgFactory< T > factory;
-        private final double amplitudeThreshold;
-        private RandomAccessibleInterval< BitType > amplitude;
-
-        public MaximumAmplitude( RandomAccessibleInterval< T > input, ImgFactory< T > factory, RandomAccessibleInterval< BitType > amplitude, double amplitudeThreshold )
-        {
-            this.input = input;
-            this.factory = factory;
-            this.amplitude = amplitude;
-            this.amplitudeThreshold = amplitudeThreshold;
-            run();
-        }
-
-        /**
-         * @param max the image containing only the values of local maximums
-         * @param min the image containing only the values of local minimums
-         * @param <T> the type of both images {@link Img}
-         * @return an image containing the value of the maximums amplitude
-         */
-        private static < T extends RealType< T > & NativeType< T > > Img< T > getAmplitude(
-                RandomAccessibleInterval< T > max, ImgFactory< T > factory, RandomAccessibleInterval< T > min )
-        {
-            Img< T > amp = factory.create( max );
-            RandomAccess< T > maxAccess = max.randomAccess();
-            RandomAccess< T > minAccess = min.randomAccess();
-            RandomAccess< T > ampAccess = amp.randomAccess();
-            for ( int x = 0; x <= max.dimension( 0 ) - 1; x++ )
-            {
-                maxAccess.setPosition( x, 0 );
-                for ( int y = 0; y <= max.dimension( 1 ) - 1; y++ )
-                {
-                    maxAccess.setPosition( y, 1 );
-                    for ( int z = 0; z <= max.dimension( 2 ) - 1; z++ )
-
-                    {
-                        maxAccess.setPosition( z, 2 );
-                        double maxValue = maxAccess.get().getRealDouble();
-                        if ( maxValue != 0 )
-                        {
-                            minAccess.setPosition( maxAccess );
-                            double amplitude = getAmplitude( maxValue, minAccess, ( int ) max.dimension( 2 ) );
-                            ampAccess.setPosition( maxAccess );
-                            ampAccess.get().setReal( amplitude );
-                        }
-                    }
-                }
-            }ImageJFunctions.show (amp," neutral amp");
-            return amp;
-        }
-
-        /**
-         * @param maxValue  the intensity value at local maximum positioned at minAccess location
-         * @param minAccess - the random access positioned at  the same specific local maximum location
-         * @param <T>       the type of the {@link RandomAccess}
-         * @return the chosen amplitude value of the local maximum positioned at minAccess location
-         */
-        private static < T extends RealType< T > & NativeType< T > > double getAmplitude( double maxValue, RandomAccess< T > minAccess, int depth )
-        {
-            double up = findValueUp( minAccess, maxValue );
-            double down = findValueDown( minAccess, maxValue, depth );
-            double result = Math.max( Math.abs( maxValue - up ), Math.abs( maxValue - down ) );
-            if ( result == 0 )
-            {
-                return maxValue;
-
-            }
-            return ( result );
-        }
-
-        /**
-         * @param minAccess the random access of the local minimum image
-         * @param maxValue  the intensity value of the local maximum located at minAccess position
-         * @param <T>       the type of the {@link RandomAccess}
-         * @return the amplitude value above the local maximum location in the Z dimension
-         */
-        private static < T extends RealType< T > & NativeType< T > > double findValueUp(
-                RandomAccess< T > minAccess, double maxValue )
-        {
-            int start = minAccess.getIntPosition( 2 );
-            for ( int z = start - 1; z >= 0; z-- )
-            {
-                minAccess.setPosition( z, 2 );
-                double value = minAccess.get().getRealDouble();
-                if ( value != 0 )
-                {
-                    return value;
-                }
-            }
-            return maxValue;
-        }
-
-        /**
-         * @param minAccess the random access of the local minimum image
-         * @param maxValue  the intensity value of the local maximum located at minAccess position
-         * @param <T>       the type of the {@link RandomAccess}
-         * @return the amplitude value below the local maximum location in the Z dimension
-         */
-        private static < T extends RealType< T > & NativeType< T > > double findValueDown(
-                RandomAccess< T > minAccess, double maxValue, int depth )
-        {
-            int start = minAccess.getIntPosition( 2 );
-            for ( int z = start + 1; z <= depth - 1; z++ )
-            {
-                minAccess.setPosition( z, 2 );
-                double value = minAccess.get().getRealDouble();
-                if ( value != 0 )
-                {
-                    return value;
-                }
-            }
-            return maxValue;
-        }
-
-        public void run()
-        {
-            Img< T > maximums = LocalExtremaDetection.findMaxima( input, factory );
-            Img< T > minimums = LocalExtremaDetection.findMinima( input, factory );
-            Img< T > amp = getAmplitude( maximums, factory, minimums );
-            T TMax = Threshold.getFirstMaxValue( maximums, false );
-            System.out.println("Amplitude threshold value before user = " + TMax);
-            TMax.mul( amplitudeThreshold );
-            System.out.println("Amplitude threshold value after user = " + TMax);
-            this.amplitude = Thresholder.threshold( amp.copy(), TMax, true, 2 );
-
-        }
-
-        public RandomAccessibleInterval< BitType > getAmplitude()
-        {
-            return amplitude;
-        }
-    }
-
-    /**
-     * This class allows the elimination of isolated pixels. the image is containing the amplitude values of each local maximums is split into {15 x 15 x 1} sections,
-     * and the sections containing less than  the size percent value are set to zero.
-     */
-    private static final class BackgroundForegroundGrid
-    {
-        private final RandomAccessibleInterval< BitType > source;
-        private final RandomAccessibleInterval< FloatType > output;
-        private final double sizePercent;
-
-        /**
-         * @param source      - the input  as a 2D {@link Img<BitType> }
-         * @param output      - the output as a 2D {@link Img<FloatType> }
-         * @param sizePercent - the minimum percentage of positive pixels
-         */
-        private BackgroundForegroundGrid( final RandomAccessibleInterval< BitType > source, Img< FloatType > output, double sizePercent )
-        {
-            this.source = source;
-            this.output = output;
-            this.sizePercent = sizePercent;
-            run();
-        }
-
-        /**
-         * @param intervalView a sub 2D image
-         * @param sizePercent  the minimum percentage of pixels for isolated pixel elimination
-         * @param <T>          the type of the sub image
-         * @return true if the sub image does contain enough foreground pixels false otherwise
-         */
-        public static < T extends RealType< T > & NativeType< T > > boolean isForeground( IntervalView< T > intervalView, double sizePercent )
-        {
-            double sum = 0;
-            Cursor< T > cursor = intervalView.cursor();
-            while ( cursor.hasNext() )
-            {
-                cursor.fwd();
-                if ( cursor.get().getRealDouble() != 0 )
-                {
-                    sum++;
-                }
-            }
-            return ( sum ) > ( intervalView.dimension( 0 ) * intervalView.dimension( 1 ) * sizePercent );
-        }
-
-        /**
-         *
-         */
-        public void run()
-        {
-            long width = source.dimension( 0 );
-            long height = source.dimension( 1 );
-            long depth = source.dimension( 2 );
-            List< Interval > intervals = Grids.collectAllContainedIntervals( new long[]{ width, height, depth },
-                    new int[]{ 15, 15, 1 } );
-
-            for ( Interval interval : intervals )
-            {
-                IntervalView< BitType > viewSource = Views.offsetInterval( source, interval );
-                IntervalView< FloatType > viewOutput = Views.offsetInterval( output, interval );
-                int foreground = isForeground( viewSource, sizePercent ) ? 1 : 0;
-                if (foreground == 0)
-                viewOutput.forEach( pixel -> pixel.setReal( foreground ) );
-                else{
-                   Utils.convertBitTypeIntoFloatType( viewSource, viewOutput );
-            }
-            }
-            // Slight dilatation in z dimension
-
-        }
-
-        /**
-         * @return the smoothed amplitude classified image
-         */
-        public RandomAccessibleInterval< FloatType > getOutput()
-        {
-            return output;
-        }
-    }
-
-}
diff --git a/src/main/java/fr/pasteur/ida/zellige/utils/ParameterSweepFiles.java b/src/main/java/fr/pasteur/ida/zellige/utils/ParameterSweepFiles.java
new file mode 100644
index 0000000000000000000000000000000000000000..93906b35797ec70133d2f660b2fbf2ddeaae2de3
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/utils/ParameterSweepFiles.java
@@ -0,0 +1,48 @@
+package fr.pasteur.ida.zellige.utils;
+
+import io.scif.img.IO;
+import io.scif.img.SCIFIOImgPlus;
+import net.imglib2.img.Img;
+import net.imglib2.type.numeric.integer.IntType;
+import net.imglib2.type.numeric.real.FloatType;
+
+public class ParameterSweepFiles
+{
+    private final Img<IntType> ref;
+    private final Img<FloatType> tested;
+    private final String path;
+
+    public ParameterSweepFiles()
+    {
+        /* The reference height map*/
+        final String refImagePath = "doc/Ground truth Height map.tif";
+//        final String refImagePath = "C:\\Users\\ctrebeau\\Desktop\\phantom_tests_snr_1surf\\phantoms_1surf_snrtest_zmap1_gt.tif";
+//                String p = "C:\\Users\\ctrebeau\\Desktop\\phantom_tests_snr_1surf\\phantoms_1surf_snrtest_zmap1_gt.tif";
+        final SCIFIOImgPlus< ? > refImgPlus = IO.openImgs( refImagePath ).get( 0 );
+       ref = ( Img< IntType > ) refImgPlus.getImg();
+
+        /* The raw image to test*/
+        final String imagePath = "doc/STK.tif";
+//        final String imagePath = "C:\\Users\\ctrebeau\\Desktop\\phantom_tests_snr_1surf\\phantoms_1surf_snr0.mat.tif";
+        final SCIFIOImgPlus< ? > imgPlus = IO.openImgs( imagePath ).get( 0 );
+        tested = ( Img< FloatType > ) imgPlus.getImg();
+
+                path ="STK";
+//                        ( imagePath.substring( 4 ) );
+    }
+
+    public Img< IntType > getRef()
+    {
+        return ref;
+    }
+
+    public Img< FloatType > getTested()
+    {
+        return tested;
+    }
+
+    public String getPath()
+    {
+        return path;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/utils/ReconstructionErrors.java b/src/main/java/fr/pasteur/ida/zellige/utils/ReconstructionErrors.java
new file mode 100644
index 0000000000000000000000000000000000000000..b1fe82b267763a80731fc3269b0e223c09bd5780
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/utils/ReconstructionErrors.java
@@ -0,0 +1,112 @@
+package fr.pasteur.ida.zellige.utils;
+
+import fr.pasteur.ida.zellige.exception.DifferentReferenceTestedSizeException;
+import fr.pasteur.ida.zellige.exception.NotAnHeightMapException;
+import net.imglib2.RandomAccess;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.RealType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ReconstructionErrors< T extends RealType< T > & NativeType< T >, R extends RealType< R > & NativeType< R > >
+{
+
+    private final static Logger LOGGER = LoggerFactory.getLogger( ReconstructionErrors.class );
+    private final RandomAccessibleInterval< T > ref;
+    private final RandomAccessibleInterval< R > tested;
+    private double reconstructedPixelsPercentage = 0;
+    private double RMSEValue;
+    private double RMSEWithPenalty;
+
+    public ReconstructionErrors( RandomAccessibleInterval< T > ref,
+                                 RandomAccessibleInterval< R > tested ) throws NotAnHeightMapException, DifferentReferenceTestedSizeException
+    {
+        inputCheck( ref, tested );
+        this.ref = ref;
+        this.tested = tested;
+    }
+
+
+    public void compute()
+    {
+        RandomAccess< T > refAccess = ref.randomAccess();
+        RandomAccess< R > testedAccess = tested.randomAccess();
+        int totalPixel = 0;
+        int testedPixelNumber = 0;
+        double meanSquareError = 0;
+        for ( int x = 0; x < ref.dimension( 0 ); x++ )
+        {
+            for ( int y = 0; y < ref.dimension( 1 ); y++ )
+            {
+                double refValue = Utils.setPositionAndGet( refAccess, x, y ).getRealDouble();
+                if ( refValue != 0 ) // there is a pixel in the ref height map
+                {
+                    totalPixel++;
+                    double testedValue = Utils.setPositionAndGet( testedAccess, x, y ).getRealDouble();
+                    if ( testedValue != 0 )
+                    {
+                        testedPixelNumber++;
+                        meanSquareError = + Math.pow( ( refValue - testedValue ), 2 );
+                    }
+                }
+            }
+        }
+        this.RMSEValue = Math.sqrt( meanSquareError / testedPixelNumber );
+        double penalty = totalPixel - testedPixelNumber;
+        this.RMSEWithPenalty = Math.sqrt( ( meanSquareError + ( penalty * 0.5 ) ) / totalPixel );
+        this.reconstructedPixelsPercentage = ( double ) testedPixelNumber / totalPixel;
+        LOGGER.info( "RMSE = {} ", this.RMSEValue );
+        LOGGER.info( "Reconstructed pixel percentage = {} ", this.reconstructedPixelsPercentage );
+        LOGGER.info( " Reconstruction Error Computation done." );
+    }
+
+    void inputCheck( RandomAccessibleInterval< T > ref,
+                     RandomAccessibleInterval< R > tested ) throws NotAnHeightMapException, DifferentReferenceTestedSizeException
+    {
+        if ( ref != null && tested != null )
+        {
+            if ( ref.numDimensions() > 2 )
+            {
+                LOGGER.error( "The reference height map has more than one dimension ! (It's not an height map)" );
+                throw new NotAnHeightMapException();
+            }
+            if ( tested.numDimensions() > 2 )
+            {
+                LOGGER.error( "The tested height map has more than one dimension ! (It's not an height map)" );
+                throw new NotAnHeightMapException();
+            }
+            if ( ref.dimension( 0 ) != tested.dimension( 0 ) || ref.dimension( 1 ) != tested.dimension( 1 ) )
+            {
+                LOGGER.error( "The reference and tested height maps have different size !" );
+                throw new DifferentReferenceTestedSizeException();
+            }
+            LOGGER.info( "Starting Reconstruction Error Computation." );
+        }
+        else if ( ref == null )
+        {
+            LOGGER.error( "The reference height map is null" );
+            throw new NullPointerException();
+        }
+        else
+        {
+            LOGGER.error( "The tested height map is null" );
+            throw new NullPointerException();
+        }
+    }
+
+    public double getReconstructedPixelsPercentage()
+    {
+        return reconstructedPixelsPercentage;
+    }
+
+    public double getRMSEValue()
+    {
+        return RMSEValue;
+    }
+
+    public double getRMSEWithPenalty()
+    {
+        return RMSEWithPenalty;
+    }
+}
diff --git a/src/main/java/fr/pasteur/ida/zellige/utils/Threshold.java b/src/main/java/fr/pasteur/ida/zellige/utils/Threshold.java
index 1b6538b11dc502b9d8776375ea30e37e9767a3a6..d7bddeffd834acbfbf0fa425c6f1e8047bff34ca 100644
--- a/src/main/java/fr/pasteur/ida/zellige/utils/Threshold.java
+++ b/src/main/java/fr/pasteur/ida/zellige/utils/Threshold.java
@@ -201,34 +201,8 @@ public class Threshold
         return threshold;
     }
 
-    public static < T extends RealType< T > & NativeType< T > > Img< T > classification(
-            IterableInterval< T > amplitude, ImgFactory< T > factory, Img< BitType > thresholds )
-    {
-        Img< T > output = factory.create( thresholds );
-        Cursor< T > amplitudeCursor = amplitude.localizingCursor();
-        RandomAccess< BitType > thresholdAccess = thresholds.randomAccess();
-        RandomAccess< T > outputAccess = output.randomAccess();
-        while ( amplitudeCursor.hasNext() )
-        {
-            amplitudeCursor.fwd();
-            if ( amplitudeCursor.get().getRealDouble() != 0 )
-            {
-                thresholdAccess.setPosition( amplitudeCursor );
-                if ( thresholdAccess.get().get() )
-                {
-                    outputAccess.setPosition( amplitudeCursor );
-                    outputAccess.get().setOne();
-                }
-            }
-        }
-        ImageJFunctions.show( output.copy(), "amp+thresh" );
-        return output;
-    }
-
-
     public static < T extends RealType< T > & NativeType< T > > T getFirstMaxValue( Img< T > input, boolean zero )
     {
-        ImageJFunctions.show(input.copy());
         T max = Threshold.findMax( input );
         T min = Threshold.findMin( input );
         int numBins = (int)max.getRealDouble();
diff --git a/src/test/java/fr/pasteur/ida/zellige/behavior/CrossSurfaceTest.java b/src/test/java/fr/pasteur/ida/zellige/behavior/CrossSurfaceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ea95d30b5839c8a9c8fd6ed4e4628169745abd0c
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/behavior/CrossSurfaceTest.java
@@ -0,0 +1,67 @@
+package fr.pasteur.ida.zellige.behavior;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+import fr.pasteur.ida.zellige.exception.EmptyOutputException;
+import fr.pasteur.ida.zellige.exception.NoClassificationException;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection.SurfacePixelSelection;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelClassificationParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelSelectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PostTreatmentParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters;
+import ij.ImageJ;
+import io.scif.img.IO;
+import io.scif.img.SCIFIOImgPlus;
+import net.imglib2.img.Img;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.RealType;
+import org.junit.jupiter.api.Test;
+
+
+public class CrossSurfaceTest
+{
+
+
+    @Test
+    < T extends RealType< T > & NativeType< T > > void someTest() throws DataValidationException, NoClassificationException, EmptyOutputException
+    {
+        /* Parameters*/
+        double amplitude = 0.2;
+        double otsu = 0.2;
+        double sigmaXY = 2;
+        double sigmaZ = 0;
+        PretreatmentParameters pretreatmentParameters = new PretreatmentParameters( "Median", new double[]{ 2 } );
+        PixelClassificationParameters classificationParameters = new PixelClassificationParameters( amplitude, otsu );
+        PostTreatmentParameters postTreatmentParameters = new PostTreatmentParameters( sigmaXY, sigmaZ, 5, 8 );
+        PixelSelectionParameters pixelSelectionParameters = new PixelSelectionParameters( pretreatmentParameters, classificationParameters, postTreatmentParameters );
+
+        final String imagePath = "doc/STK_08.tif";
+        final SCIFIOImgPlus< ? > imgPlus = IO.openImgs( imagePath ).get( 0 );
+        new ImageJ();
+        final Img< T > source = ( Img< T > ) imgPlus.getImg();
+
+        Pixels[][] maximums = SurfacePixelSelection.run( source, pixelSelectionParameters );
+//        displayMaximums(maximums);
+    }
+
+    public static< T extends RealType< T > & NativeType< T > >   void main( String[] args ) throws DataValidationException, NoClassificationException, EmptyOutputException
+    {
+        /* Parameters*/
+        double amplitude = 0;
+        double otsu = 0.2;
+        double sigmaXY = 2;
+        double sigmaZ = 1;
+        PretreatmentParameters pretreatmentParameters = new PretreatmentParameters( "Median", new double[]{ 2 } );
+        PixelClassificationParameters classificationParameters = new PixelClassificationParameters( amplitude, otsu );
+        PostTreatmentParameters postTreatmentParameters = new PostTreatmentParameters( sigmaXY, sigmaZ, 5, 8 );
+        PixelSelectionParameters pixelSelectionParameters = new PixelSelectionParameters( pretreatmentParameters, classificationParameters, postTreatmentParameters );
+
+        final String imagePath = "doc/phantoms_crossingsurf.tif";
+        final SCIFIOImgPlus< ? > imgPlus = IO.openImgs( imagePath ).get( 0 );
+        new ImageJ();
+        final Img< T > source = ( Img< T > ) imgPlus.getImg();
+
+        Pixels[][] maximums = SurfacePixelSelection.run( source, pixelSelectionParameters );
+//        displayMaximums(maximums);
+    }
+}
diff --git a/src/test/java/fr/pasteur/ida/zellige/behavior/GetFirstMaxValueBehaviorTest.java b/src/test/java/fr/pasteur/ida/zellige/behavior/GetFirstMaxValueBehaviorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..002086abf9be1da414b2305ea2da7ea77cf812d8
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/behavior/GetFirstMaxValueBehaviorTest.java
@@ -0,0 +1,53 @@
+package fr.pasteur.ida.zellige.behavior;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+import fr.pasteur.ida.zellige.exception.EmptyOutputException;
+import fr.pasteur.ida.zellige.exception.NoClassificationException;
+import fr.pasteur.ida.zellige.jzy3D.LocalMaximumsDisplay;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection.SurfacePixelSelection;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.ose.OseConstructionXZ;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEListArray;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelClassificationParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelSelectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PostTreatmentParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters;
+import io.scif.img.IO;
+import io.scif.img.SCIFIOImgPlus;
+import net.imglib2.img.Img;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.RealType;
+import org.junit.Ignore;
+import org.junit.jupiter.api.Test;
+
+
+class GetFirstMaxValueBehaviorTest < T extends RealType< T > & NativeType< T > >
+{
+    @Ignore
+    @Test
+    void GetFirstMaxValueBehaviorTest() throws DataValidationException, NoClassificationException, EmptyOutputException
+    {
+        /*
+        Test to show a specific behavior for few images when determining the First max value in
+        MaximumAmplitudeClassification class
+         */
+        // Parameters
+        double amplitude = 0.2;
+        double otsu = 0.2;
+        double sigmaXY = 2;
+        double sigmaZ = 0;
+        PretreatmentParameters pretreatmentParameters = new PretreatmentParameters( "Median", new double[]{ 2 } );
+        PixelClassificationParameters classificationParameters = new PixelClassificationParameters( amplitude, otsu );
+        PostTreatmentParameters postTreatmentParameters = new PostTreatmentParameters( sigmaXY, sigmaZ, 5, 8 );
+        PixelSelectionParameters pixelSelectionParameters = new PixelSelectionParameters( pretreatmentParameters, classificationParameters, postTreatmentParameters );
+
+        final String imagePath = "doc/STK_08.tif";
+        final SCIFIOImgPlus< ? > imgPlus = IO.openImgs( imagePath ).get( 0 );
+
+        final Img< T > source = ( Img< T > ) imgPlus.getImg();
+
+        Pixels[][] maximums = SurfacePixelSelection.run( source, pixelSelectionParameters );
+//        displayMaximums(maximums);
+
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/fr/pasteur/ida/zellige/behavior/OneSurfaceConstructionTest.java b/src/test/java/fr/pasteur/ida/zellige/behavior/OneSurfaceConstructionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3c4037e623215c6eea8bcc5c004f00306c028615
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/behavior/OneSurfaceConstructionTest.java
@@ -0,0 +1,19 @@
+package fr.pasteur.ida.zellige.behavior;
+
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ConstructionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ProjectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelClassificationParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelSelectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PostTreatmentParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class OneSurfaceConstructionTest
+{
+
+
+
+}
\ No newline at end of file
diff --git a/src/test/java/fr/pasteur/ida/zellige/behavior/PipelineTest.java b/src/test/java/fr/pasteur/ida/zellige/behavior/PipelineTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f852d41db2f1c8092aa1663b233c838ad948308
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/behavior/PipelineTest.java
@@ -0,0 +1,146 @@
+package fr.pasteur.ida.zellige.behavior;
+
+import fr.pasteur.ida.zellige.ReferenceSurfaceExtraction;
+import fr.pasteur.ida.zellige.exception.*;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ReferenceSurface;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ConstructionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ProjectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelClassificationParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelSelectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PostTreatmentParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters;
+import fr.pasteur.ida.zellige.utils.CSVWriter;
+import fr.pasteur.ida.zellige.utils.ParameterSweepFiles;
+import fr.pasteur.ida.zellige.utils.ReconstructionErrors;
+import net.imglib2.img.Img;
+import net.imglib2.img.ImgFactory;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.RealType;
+import net.imglib2.type.numeric.integer.IntType;
+import net.imglib2.type.numeric.integer.UnsignedShortType;
+import net.imglib2.type.numeric.real.FloatType;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvFileSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+
+public class PipelineTest< T extends RealType< T > & NativeType< T > >
+{
+
+    private final static Logger LOGGER = LoggerFactory.getLogger( CSVWriter.class );
+    static Img< IntType > ref;
+    static Img< FloatType > tested;
+    private static CSVWriter writer;
+
+    @BeforeAll
+    static void init()
+    {
+        ParameterSweepFiles files = new ParameterSweepFiles();
+        ref = files.getRef();
+        tested = files.getTested();
+        writer = new CSVWriter( files.getPath() );
+    }
+
+    @AfterAll
+    static void closeBw() throws IOException
+    {
+        writer.close();
+    }
+
+    @ParameterizedTest
+    @CsvFileSource( files = "src/test/resources/phantoms_1surf_snr0.mat_PS.csv", numLinesToSkip = 2, delimiterString = ";" )
+    void parameterSweep( String testedParameter, String testedParameterValue, String filter, int filterParameter,
+                         double amplitudeThreshold, double otsuThreshold,
+                         int ISConnexity, int ISSize,
+                         double XYSmoothing, double ZSmoothing,
+                         double startingThreshold1, int overlap1, double connexityRate1,
+                         double startingThreshold2, int overlap2, double connexityRate2 ) throws DataValidationException, NoClassificationException, EmptyOutputException, IOException
+    {
+        LOGGER.info( "Parameter sweep " );
+        ImgFactory< FloatType > factory = tested.factory();
+
+        PretreatmentParameters pretreatmentParameters = new PretreatmentParameters( filter, new double[]{ filterParameter } );
+        PixelClassificationParameters classificationParameters = new PixelClassificationParameters( amplitudeThreshold, otsuThreshold );
+        PostTreatmentParameters postTreatmentParameters = new PostTreatmentParameters( XYSmoothing, ZSmoothing, ISSize, ISConnexity );
+        PixelSelectionParameters selectionParameters = new PixelSelectionParameters( pretreatmentParameters, classificationParameters, postTreatmentParameters );
+
+        ProjectionParameters projectionParameters = new ProjectionParameters( 1, "MIP" );
+        ConstructionParameters[] constructionParameters = new ConstructionParameters[]{
+                new ConstructionParameters( startingThreshold1, overlap1, connexityRate1 ),
+                new ConstructionParameters( startingThreshold2, overlap2, connexityRate2 ) };
+
+        ReferenceSurfaceExtraction< FloatType > extraction = new ReferenceSurfaceExtraction<>( tested, factory,
+                selectionParameters, projectionParameters, constructionParameters );
+        extraction.select();
+        int pixelNumber = getPixelNumber( extraction.getMaximums() );
+        try
+        {
+            extraction.construct();
+            ArrayList< ReferenceSurface< FloatType > > surfaces = extraction.getReferenceSurfaces();
+            ArrayList<ReconstructionErrors<T, UnsignedShortType>> errorsList = new ArrayList<>();
+            for ( ReferenceSurface rf : surfaces )
+            {
+                ReconstructionErrors< T, UnsignedShortType > errors = new ReconstructionErrors<>( ref, rf.getZMap() );
+                errors.compute();
+                errorsList.add(errors);
+
+            }
+            ReconstructionErrors< T, UnsignedShortType > finalError = findRightSurface( errorsList );
+            writer.writeToFile( testedParameter, testedParameterValue, pixelNumber,
+                finalError.getRMSEValue(),
+                finalError.getReconstructedPixelsPercentage(),
+                finalError.getRMSEWithPenalty() );
+        }
+        catch ( Exception n )
+        {
+            writer.writeToFile( testedParameter, testedParameterValue, pixelNumber,
+                    100,
+                    0,
+                    100 );
+        }
+    }
+
+    private int getPixelNumber( Pixels[][] maximumCoordinates )
+    {
+        int n = 0;
+        for ( int i = 0; i <= maximumCoordinates[ 0 ].length - 1; i++ )
+        {
+            for ( int j = 0; j <= maximumCoordinates.length - 1; j++ )
+            {
+                if ( maximumCoordinates[ j ][ i ] != null )
+                {
+                    n += maximumCoordinates[ j ][ i ].size();
+                }
+            }
+        }
+        return n;
+    }
+
+
+    ReconstructionErrors <T, UnsignedShortType> findRightSurface(ArrayList<ReconstructionErrors<T, UnsignedShortType>> list)
+    {
+        if(list.size() > 1)
+        {
+            ReconstructionErrors< T, UnsignedShortType > errors = null;
+            double max = 0;
+            for ( ReconstructionErrors< T, UnsignedShortType > temp : list )
+            {
+                if ( temp.getReconstructedPixelsPercentage() > max )
+                {
+                    errors = temp;
+                }
+            }
+            return errors;
+        }
+        return list.get(0);
+    }
+
+}
diff --git a/src/test/java/fr/pasteur/ida/zellige/behavior/StartingOSE_SameSurfaceTest.java b/src/test/java/fr/pasteur/ida/zellige/behavior/StartingOSE_SameSurfaceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a1ddc0ee97466147afa9f71d258b1ccc7d31091
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/behavior/StartingOSE_SameSurfaceTest.java
@@ -0,0 +1,127 @@
+package fr.pasteur.ida.zellige.behavior;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+import fr.pasteur.ida.zellige.exception.EmptyOutputException;
+import fr.pasteur.ida.zellige.exception.NoClassificationException;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection.SurfacePixelSelection;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.ose.OseConstructionXZ;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.surface.OneSurfaceConstruction;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.AbstractOSE;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEList;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEListArray;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.surfaceLine.SurfaceLine;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelClassificationParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelSelectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PostTreatmentParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters;
+import io.scif.img.IO;
+import io.scif.img.SCIFIOImgPlus;
+import net.imglib2.img.Img;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.RealType;
+import org.junit.Ignore;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.util.*;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class StartingOSE_SameSurfaceTest
+{
+    @Ignore
+    @DisplayName( "Two starting OSE from the same surface don't necessarily produce the exact same surface" )
+    @Test
+   < T extends RealType< T > & NativeType< T > > void  TwoStartingOSEFromTheSameSurface_whenUseForStartASurface_DonTProduceTheExactSameSurface() throws DataValidationException, EmptyOutputException, NoClassificationException
+    {
+        /* Parameters*/
+        double amplitude = 0.2;
+        double otsu = 0.2;
+        double sigmaXY = 2;
+        double sigmaZ = 0;
+        double startingSizeThreshold = 0.9;
+        int overlap = 10;
+        double connexity = 0.5;
+        PretreatmentParameters pretreatmentParameters = new PretreatmentParameters( "Median", new double[]{ 2 } );
+        PixelClassificationParameters classificationParameters = new PixelClassificationParameters( amplitude, otsu );
+        PostTreatmentParameters postTreatmentParameters = new PostTreatmentParameters( sigmaXY, sigmaZ, 5, 8 );
+        PixelSelectionParameters pixelSelectionParameters = new PixelSelectionParameters( pretreatmentParameters, classificationParameters, postTreatmentParameters );
+
+        final String imagePath = "doc/STK_08.tif";
+        final SCIFIOImgPlus< ? > imgPlus = IO.openImgs( imagePath ).get( 0 );
+
+        final Img< T > source = ( Img< T > ) imgPlus.getImg();
+
+        Pixels[][] maximums = SurfacePixelSelection.run( source, pixelSelectionParameters );
+        OSEListArray oseLists = OseConstructionXZ.runConstruction( maximums, startingSizeThreshold );
+        int width = maximums[ 0 ].length;
+
+        ArrayList< AbstractOSE > list1 = findAllStartingOSE( oseLists );
+        AbstractOSE ose1 = oseLists.getAStartingOse();
+        Surface reference = OneSurfaceConstruction.run( oseLists, ose1, width, overlap, connexity );
+
+        ArrayList< AbstractOSE > list2 = findAllStartingOSE( oseLists );
+
+        ArrayList< AbstractOSE > osePartOfSurface = list1;
+        osePartOfSurface.removeAll( list2 );
+        System.out.println( "surface starting ose : " + osePartOfSurface.size() );
+        TreeMap< Double, Integer > uniqueSurface = new TreeMap<>();
+        for ( AbstractOSE ose : osePartOfSurface )
+        {
+            oseLists.reset();
+            Surface s = OneSurfaceConstruction.run( oseLists, ose, width, overlap, connexity );
+            double overlappingRate = overlappingRate( reference, s );
+            System.out.println( " This surface has an overlap rate of " + overlappingRate + " with the reference surface" );
+            Integer j = uniqueSurface.get(overlappingRate);
+            uniqueSurface.put( overlappingRate, ( j == null ) ? 1 : j + 1 );
+        }
+        System.out.println(uniqueSurface );
+        assertThat( uniqueSurface.size()> 1 );
+    }
+
+
+    public ArrayList<AbstractOSE> findAllStartingOSE (OSEListArray oseListArray)
+    {
+        ArrayList<AbstractOSE> list = new ArrayList<>();
+        for ( OSEList oseList : oseListArray.getOseLists()  )
+        {
+            for ( AbstractOSE ose :oseList  )
+            {
+                if(ose.isAStart())
+                {
+                    list.add(ose);
+                }
+            }
+        }
+        return list;
+    }
+
+    public double overlappingRate( Surface reference, Surface other )
+    {
+        int inCommon = 0;
+        int count = 0;
+        for ( int i = 0; i <= reference.getHeight() - 1; i++ )
+        {
+            SurfaceLine refLine = reference.get( i );
+            if ( refLine != null )
+            {
+                for ( int j = 0; j < refLine.getLength(); j++ )
+                {
+                    Pixels refPixels = refLine.get( j );
+                    if ( refPixels != null )
+                    {
+                        count++;
+                        if ( refPixels.equals (other.get( i ).get( j ) ))
+                        {
+                            inCommon++;
+                        }
+                    }
+                }
+
+            }
+        }
+        return  inCommon / (double) count * 100.0;
+    }
+}
diff --git a/src/test/java/fr/pasteur/ida/zellige/behavior/SurfaceConstructionBehaviorTest.java b/src/test/java/fr/pasteur/ida/zellige/behavior/SurfaceConstructionBehaviorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..542ac8c56ee54ad2740a0da3ec05667e19747f5d
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/behavior/SurfaceConstructionBehaviorTest.java
@@ -0,0 +1,76 @@
+package fr.pasteur.ida.zellige.behavior;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+import fr.pasteur.ida.zellige.exception.EmptyOutputException;
+import fr.pasteur.ida.zellige.exception.NoClassificationException;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.constructionRound.constructSurface.ConstructionRounds;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection.SurfacePixelSelection;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.ose.OseConstructionXZ;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.surface.OneSurfaceConstruction;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Pixels;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.Surface;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.AbstractOSE;
+import fr.pasteur.ida.zellige.surfaceConstruction.element.ose.OSEListArray;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.ConstructionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelClassificationParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelSelectionParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PostTreatmentParameters;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters;
+import ij.ImageJ;
+import io.scif.img.IO;
+import io.scif.img.SCIFIOImgPlus;
+import net.imglib2.img.Img;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.RealType;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+
+import static fr.pasteur.ida.zellige.ReferenceSurfaceExtraction.displaySurface;
+
+public class SurfaceConstructionBehaviorTest< T extends RealType< T > & NativeType< T > >
+{
+
+    @Test
+    void testIt() throws DataValidationException, NoClassificationException, EmptyOutputException
+    {
+        /* Parameters*/
+        double amplitude = 0;
+        double otsu = 1;
+        double sigmaXY = 2;
+        double sigmaZ = 0;
+        double startingSizeThreshold = 0.9;
+        int overlap = 10;
+        double connexity = 0.7;
+        int overlap1 = 30;
+        double connexity1 = 0.9;
+
+        PretreatmentParameters pretreatmentParameters = new PretreatmentParameters( "Median", new double[]{ 2 } );
+        PixelClassificationParameters classificationParameters = new PixelClassificationParameters( amplitude, otsu );
+        PostTreatmentParameters postTreatmentParameters = new PostTreatmentParameters( sigmaXY, sigmaZ, 5, 8 );
+        PixelSelectionParameters pixelSelectionParameters = new PixelSelectionParameters( pretreatmentParameters, classificationParameters, postTreatmentParameters );
+        ConstructionParameters[] constructionParameters = new ConstructionParameters[]{
+                new ConstructionParameters( 0.75, overlap, connexity ),
+                new ConstructionParameters( 0.1, overlap1, connexity1 )};
+        ij.ImageJ ij = new ImageJ();
+        final String imagePath = "doc/STK_08.tif";
+        final SCIFIOImgPlus< ? > imgPlus = IO.openImgs( imagePath ).get( 0 );
+
+        final Img< T > source = ( Img< T > ) imgPlus.getImg();
+
+        Pixels[][] maximums = SurfacePixelSelection.run( source, pixelSelectionParameters );
+        OSEListArray oseLists = OseConstructionXZ.runConstruction( maximums, startingSizeThreshold );
+
+//        displayMaximums( maximums );
+
+        ConstructionRounds rounds = new ConstructionRounds();
+        rounds.process( maximums, constructionParameters );
+        ArrayList<Surface> surfaces = rounds.getReferenceSurfaces();
+        for(Surface surface : surfaces)
+        {
+//            displaySurface( surface );
+        }
+
+        while(true);
+    }
+}
diff --git a/src/test/java/fr/pasteur/ida/zellige/behavior/SurfaceLineConstructionBehaviorTest.java b/src/test/java/fr/pasteur/ida/zellige/behavior/SurfaceLineConstructionBehaviorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb40f4f00b0ac454ce033294094ff3b5c79c323e
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/behavior/SurfaceLineConstructionBehaviorTest.java
@@ -0,0 +1,6 @@
+package fr.pasteur.ida.zellige.behavior;
+
+public class SurfaceLineConstructionBehaviorTest
+{
+
+}
diff --git a/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/SurfacePixelSelectionTest.java b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/SurfacePixelSelectionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e9de32a78a1313ea2d127faa3d79a5c98414edbe
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/SurfacePixelSelectionTest.java
@@ -0,0 +1,9 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class SurfacePixelSelectionTest
+{
+
+
+}
\ No newline at end of file
diff --git a/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/SurfacesReconstructionTest.java b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/SurfacesReconstructionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a9c7e7fe998e0432c96d5e87e69b2ff2a24a8759
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/SurfacesReconstructionTest.java
@@ -0,0 +1,9 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction;
+
+
+class SurfacesReconstructionTest
+{
+
+
+
+}
\ No newline at end of file
diff --git a/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PixelClassificationTest.java b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PixelClassificationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c0c3dda421771bbcf0ed04000ecfa6fb669b7ef1
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PixelClassificationTest.java
@@ -0,0 +1,85 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+import fr.pasteur.ida.zellige.exception.EmptyOutputException;
+import fr.pasteur.ida.zellige.exception.NoClassificationException;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelClassificationParameters;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.img.ImgFactory;
+import net.imglib2.img.array.ArrayImgFactory;
+import net.imglib2.type.numeric.real.FloatType;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.spy;
+
+
+class PixelClassificationTest
+{
+
+    @DisplayName( "When neither of the two thresholds is equals to Zero both classifications are done" )
+    @Test
+    void NoneZeroThresholdValue_usesBothClassifications() throws DataValidationException, NoClassificationException, EmptyOutputException
+    {
+        // Given
+        PixelClassificationParameters parameters = new PixelClassificationParameters( 1, 1 );
+        ImgFactory< FloatType > factory = new ArrayImgFactory<>( new FloatType() );
+        RandomAccessibleInterval< FloatType > rai = factory.create( 5, 5, 5 );
+        PixelClassification< FloatType > classificationSpy = spy( new PixelClassification<>() );
+        double amplitudeThreshold = parameters.getAmplitudeThreshold();
+        double otsuThreshold = parameters.getOtsuThreshold();
+        // When
+        classificationSpy.process( rai, factory, parameters );
+        // Then
+        Mockito.verify( classificationSpy, Mockito.times( 1 ) ).processBothClassification( rai, factory, amplitudeThreshold,otsuThreshold );
+    }
+
+    @DisplayName( "When both thresholds equal Zero a DataValidationException is raised" )
+    @Test
+    void ZeroThresholdValues_raisesAnException() throws DataValidationException
+    {
+        // Given
+        PixelClassificationParameters parameters = new PixelClassificationParameters( 0, 0 );
+        ImgFactory< FloatType > factory = new ArrayImgFactory<>( new FloatType() );
+        RandomAccessibleInterval< FloatType > rai = factory.create( 5, 5, 5 );
+        PixelClassification< FloatType > classification = new PixelClassification<>();
+
+        // When
+        assertThrows(NoClassificationException.class, () -> classification.process( rai, factory, parameters ));
+    }
+
+    @DisplayName( "When Amplitude Threshold equals Zero only the Otsu classification is done" )
+    @Test
+    void AnAmplitudeThresholdSetToZero_usesOnlyOtsuClassification() throws DataValidationException, NoClassificationException, EmptyOutputException
+    {
+        // Given
+        PixelClassificationParameters parameters = new PixelClassificationParameters( 0, 0.1 );
+        ImgFactory< FloatType > factory = new ArrayImgFactory<>( new FloatType() );
+        RandomAccessibleInterval< FloatType > rai = factory.create( 5, 5, 5 );
+        PixelClassification< FloatType > classificationSpy = spy( new PixelClassification<>() );
+        double otsuThreshold = parameters.getOtsuThreshold();
+        // When
+        classificationSpy.process( rai, factory, parameters );
+        // Then
+        Mockito.verify( classificationSpy, Mockito.times( 1 ) ).processOtsuClassification( rai, factory, otsuThreshold );
+    }
+
+    @DisplayName( "When Otsu Threshold equals Zero only the Amplitude classification is done" )
+    @Test
+    void AnOtsuThresholdSetToZero_usesOnlyAmplitudeClassification() throws DataValidationException, NoClassificationException, EmptyOutputException
+    {
+        // Given
+        PixelClassificationParameters parameters = new PixelClassificationParameters( 1, 0 );
+        ImgFactory< FloatType > factory = new ArrayImgFactory<>( new FloatType() );
+        RandomAccessibleInterval< FloatType > rai = factory.create( 5, 5, 5 );
+        PixelClassification< FloatType > classificationSpy = spy( new PixelClassification<>() );
+        double amplitudeThreshold = parameters.getAmplitudeThreshold();
+        // When
+        classificationSpy.process( rai, factory, parameters );
+        // Then
+        Mockito.verify( classificationSpy, Mockito.times( 1 ) ).processAmplitudeClassification( rai, factory, amplitudeThreshold );
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PostTreatmentTest.java b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PostTreatmentTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3c9e75ad13c20dc8a9d4d1768047e4c92b5730e
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PostTreatmentTest.java
@@ -0,0 +1,8 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class PostTreatmentTest
+{
+
+}
\ No newline at end of file
diff --git a/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PreTreatmentTest.java b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PreTreatmentTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3be9939d3401aeaf35cc2eff61253bf4fd545f12
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/construction/maximumSelection/PreTreatmentTest.java
@@ -0,0 +1,47 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+import fr.pasteur.ida.zellige.surfaceConstruction.construction.maximumSelection.Pretreatment;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.img.array.ArrayImgFactory;
+import net.imglib2.type.numeric.real.FloatType;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import static org.mockito.Matchers.any;
+
+public class PreTreatmentTest
+{
+
+    public static final String GAUSSIAN_BLUR = "GaussianBlur";
+    public static final String MEDIAN = "Median";
+
+
+@DisplayName("When MEDIAN is selected as method in PretreatmentParameters the medianFilterDenoising method is used" )
+    @Test
+    void aMedianFilterAsParameter_whenTreated_usesTheMedianFilterDenoisingMethod() throws DataValidationException
+    {
+
+        PretreatmentParameters parameters = new PretreatmentParameters( MEDIAN, new double []{2} );
+        RandomAccessibleInterval< FloatType > rai = new ArrayImgFactory<>(new FloatType()).create( 5, 5, 5 );
+        Pretreatment<FloatType> pretreatment = new Pretreatment<>(rai, parameters);
+        Pretreatment<FloatType> pretreatmentSpy = Mockito.spy( pretreatment );
+        pretreatmentSpy.run();
+        Mockito.verify(pretreatmentSpy, Mockito.times( 1 )).medianFilterDenoising(any(RandomAccessibleInterval.class));
+    }
+
+
+    @DisplayName("When GAUSSIAN_BLUR is selected as method in PretreatmentParameters the gaussianBlurFilterDenoising method is used" )
+    @Test
+    void aGaussianBlurFilterAsParameter_whenTreated_usesTheMedianFilterDenoisingMethod() throws DataValidationException
+    {
+        PretreatmentParameters parameters = new PretreatmentParameters( GAUSSIAN_BLUR, new double []{1, 1, 0} );
+        RandomAccessibleInterval<FloatType> rai = new ArrayImgFactory<>(new FloatType()).create( 5, 5, 5 );
+        Pretreatment<FloatType> pretreatment = new Pretreatment<>(rai, parameters);
+        Pretreatment<FloatType> pretreatmentSpy = Mockito.spy( pretreatment );
+        pretreatmentSpy.run();
+        Mockito.verify(pretreatmentSpy, Mockito.times( 1 )).gaussianBlurFilterDenoising(any(RandomAccessibleInterval.class));
+    }
+}
diff --git a/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/element/PixelsTest.java b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/element/PixelsTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e582ebf6897b82cce08e8f57fa36cec1b98efd79
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/element/PixelsTest.java
@@ -0,0 +1,79 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.element;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.*;
+
+class PixelsTest
+{
+
+    @DisplayName(" The check of a Coordinate already in a Pixel returns TRUE" )
+    @Test
+    void APixel_whenCheckingIfItContainsACoordinateAlreadyThere_ReturnsTrue()
+    {
+        Coordinate c1 = new Coordinate(0, 0, 0);
+        Coordinate c2 = new Coordinate( 0, 0, 4);
+
+       Pixels pixels = new Pixels( c1 );
+       pixels.add(c2);
+       assertThat(pixels.contains( c2 )).isTrue();
+
+
+    }
+
+    @Test
+    void add()
+    {
+    }
+
+    @Test
+    void addAll()
+    {
+    }
+
+    @Test
+    void get()
+    {
+    }
+
+    @Test
+    void resetSideCoordinate()
+    {
+    }
+
+    @Test
+    void size()
+    {
+    }
+
+    @Test
+    void testGet()
+    {
+    }
+
+    @Test
+    void containsAll()
+    {
+    }
+
+    @Test
+    void testEquals()
+    {
+        Coordinate c1 = new Coordinate(0, 0, 0);
+        Coordinate c2 = new Coordinate( 0, 0, 4);
+
+        Pixels pixels = new Pixels( c1 );
+        pixels.add(c2);
+
+        Pixels pixels2 = new Pixels( c1 );
+        pixels2.add( c2 );
+        assertThat( pixels ).isEqualTo( pixels2 );
+    }
+
+    @Test
+    void testToString()
+    {
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/element/SurfaceTest.java b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/element/SurfaceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc7a896d21df98b52ed1c5913e1822308984ee37
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/element/SurfaceTest.java
@@ -0,0 +1,70 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.element;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class SurfaceTest
+{
+
+    @Test
+    void hasDuplicate()
+    {
+    }
+
+    @Test
+    void sameSurface()
+    {
+    }
+
+    @Test
+    void merge()
+    {
+    }
+
+    @Test
+    void transpose()
+    {
+    }
+
+    @Test
+    void get()
+    {
+    }
+
+    @Test
+    void testGet()
+    {
+    }
+
+    @Test
+    void set()
+    {
+    }
+
+    @Test
+    void set1()
+    {
+
+    }
+
+    @Test
+    void getZMap()
+    {
+    }
+
+    @Test
+    void getSize()
+    {
+    }
+
+    @Test
+    void getWidth()
+    {
+    }
+
+    @Test
+    void getHeight()
+    {
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/PixelClassificationParametersTest.java b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/PixelClassificationParametersTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8da9a58322093217520ff43f4a6ddd5bf5ae1413
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/PixelClassificationParametersTest.java
@@ -0,0 +1,47 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.parameters;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelClassificationParameters;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class PixelClassificationParametersTest
+{
+    @DisplayName( "A good set of parameters don't raise any exception" )
+    @Test
+    void rightPixelClassificationParameters_whenCreatingANewInstance_DonTRaiseAValidationDataException()
+    {
+        double amplitudeThreshold = 1.0;
+        double otsuThreshold = 1.5;
+        assertDoesNotThrow( () -> new PixelClassificationParameters(amplitudeThreshold, otsuThreshold)  );
+    }
+
+
+    @DisplayName( " An amplitude threshold inferior to zero raises a ValidationDataException with a specific message" )
+    @Test
+    void amplitudeThresholdUnderZero_WhenCreatingANewInstance_raisesAValidationDataException()
+    {
+        double amplitudeThreshold = -1;
+        double otsuThreshold = 1.5;
+        DataValidationException exception = assertThrows(DataValidationException.class,  () ->
+                new PixelClassificationParameters(amplitudeThreshold, otsuThreshold)  );
+        assertThat(exception).hasMessageContaining( "Amplitude" );
+    }
+
+    @DisplayName( " An otsu threshold inferior to zero raises a ValidationDataException with a specific message " )
+    @Test
+    void otsuThresholdUnderZero_WhenCreatingANewInstance_raisesAValidationDataException()
+    {
+        double amplitudeThreshold = 1;
+        double otsuThreshold = -1;
+        DataValidationException exception = assertThrows(DataValidationException.class,  () ->
+                new PixelClassificationParameters(amplitudeThreshold, otsuThreshold)  );
+        assertThat(exception).hasMessageContaining( "Otsu" );
+    }
+
+
+}
diff --git a/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/PixelSelectionParametersTest.java b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/PixelSelectionParametersTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9fe6c848ee7ffbb11294030179f6007e10ac34d3
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/PixelSelectionParametersTest.java
@@ -0,0 +1,68 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.parameters;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PixelSelectionParameters;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.*;
+
+public class PixelSelectionParametersTest
+{
+
+//    @Test
+//    void rightPixelSelectionParameters_whenCreatingANewInstance_DonTRaiseAValidationDataException()
+//    {
+//        double amplitudeThreshold = 1.0;
+//        double otsuThreshold = 1.5;
+//        double sigmaXY = 2.0;
+//        double sigmaZ = 3.0;
+//        assertDoesNotThrow( () -> new PixelSelectionParameters(amplitudeThreshold, otsuThreshold, sigmaXY, sigmaZ)  );
+//    }
+//
+//
+//    @Test
+//    void amplitudeThresholdUnderZero_WhenCreatingANewInstance_raisesAValidationDataException()
+//    {
+//        double amplitudeThreshold = -1;
+//        double otsuThreshold = 1.5;
+//        double sigmaXY = 2.0;
+//        double sigmaZ = 3.0;
+//        DataValidationException exception = assertThrows(DataValidationException.class,  () -> new PixelSelectionParameters(amplitudeThreshold, otsuThreshold, sigmaXY, sigmaZ)  );
+//        assertThat(exception).hasMessageContaining( "Amplitude" );
+//    }
+//
+//    @Test
+//    void otsuThresholdUnderZero_WhenCreatingANewInstance_raisesAValidationDataException()
+//    {
+//        double amplitudeThreshold = 1;
+//        double otsuThreshold = -1;
+//        double sigmaXY = 2.0;
+//        double sigmaZ = 3.0;
+//        DataValidationException exception = assertThrows(DataValidationException.class,  () -> new PixelSelectionParameters(amplitudeThreshold, otsuThreshold, sigmaXY, sigmaZ)  );
+//        assertThat(exception).hasMessageContaining( "Otsu" );
+//    }
+//
+//    @Test
+//    void sigmaXYThresholdUnderZero_WhenCreatingANewInstance_raisesAValidationDataException()
+//    {
+//        double amplitudeThreshold = 1;
+//        double otsuThreshold = 1;
+//        double sigmaXY = -1;
+//        double sigmaZ = 3.0;
+//        DataValidationException exception = assertThrows(DataValidationException.class,  () -> new PixelSelectionParameters(amplitudeThreshold, otsuThreshold, sigmaXY, sigmaZ)  );
+//        assertThat(exception).hasMessageContaining( "XY" );
+//    }
+//
+//    @Test
+//    void sigmaZThresholdUnderZero_WhenCreatingANewInstance_raisesAValidationDataException()
+//    {
+//        double amplitudeThreshold = 1;
+//        double otsuThreshold = 1;
+//        double sigmaXY = 1;
+//        double sigmaZ = -1;
+//        DataValidationException exception = assertThrows(DataValidationException.class,  () -> new PixelSelectionParameters(amplitudeThreshold, otsuThreshold, sigmaXY, sigmaZ)  );
+//        assertThat(exception).hasMessageContaining( "Z" );
+//    }
+
+}
diff --git a/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/PretreatmentParametersTest.java b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/PretreatmentParametersTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c59e65261e891ffd6ad93dd15b6d93383f2f7357
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/PretreatmentParametersTest.java
@@ -0,0 +1,49 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.parameters;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+import fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvFileSource;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters.GAUSSIAN_BLUR;
+import static fr.pasteur.ida.zellige.surfaceConstruction.parameters.maximumSelection.PretreatmentParameters.MEDIAN;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class PretreatmentParametersTest
+{
+    @DisplayName( "Any method associated with the right number of parameters should not raise any exception" )
+    @ParameterizedTest
+    @CsvSource( {GAUSSIAN_BLUR +", 1, 1, 0",  GAUSSIAN_BLUR+", 2, 0, 3"} )
+    void gaussianBlurMethodWithThreeParameter_whenChecked_doesnTRaiseAnyException(String method, double a , double b, double c)
+    {
+        double [] values = new double []{a, b, c};
+        assertDoesNotThrow( () ->new PretreatmentParameters( method, values ));
+    }
+
+    @DisplayName( "A wrong number of parameters for any method should raise a DataValidationException with a specific message" )
+    @ParameterizedTest
+    @ValueSource(strings = { GAUSSIAN_BLUR, MEDIAN })
+
+    void gaussianBlurMethodWithLessThanThreeParameter_whenChecked_RaisesAnException(String method)
+    {
+        double [] values = new double []{0, 0, 0, 0};
+        DataValidationException exception = assertThrows(DataValidationException.class,  () -> new PretreatmentParameters( method, values));
+        assertThat(exception).hasMessageContaining( method );
+    }
+
+    @DisplayName( "The wrong number of parameters for the median Filter should raise an exception" )
+    @Test
+    void wrongDenoisingMethod_whenChecked_RaisesADataValidationException()
+    {
+        DataValidationException exception = assertThrows(DataValidationException.class,  () ->
+                new PretreatmentParameters( MEDIAN, new double [0] ));
+        assertThat(exception).hasMessageContaining( MEDIAN);
+    }
+
+}
diff --git a/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/ProjectionParametersTest.java b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/ProjectionParametersTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf407212d58edf026a7dcccc25a18918bcad3e74
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/surfaceConstruction/parameters/ProjectionParametersTest.java
@@ -0,0 +1,42 @@
+package fr.pasteur.ida.zellige.surfaceConstruction.parameters;
+
+import fr.pasteur.ida.zellige.exception.DataValidationException;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class ProjectionParametersTest
+{
+
+    @Test
+    void rightProjectionParameters_WhenCreatingANewInstance_raisesAValidationDataException()
+    {
+        int delta = 1;
+        String projectionType = "MIP";
+        assertDoesNotThrow( () -> new ProjectionParameters(delta, projectionType)  );
+    }
+
+    @Test
+    void deltaUnderZero_WhenCreatingANewInstance_raisesAValidationDataException()
+    {
+        int delta = -1;
+        String projectionMethod = "MPI";
+        DataValidationException exception = assertThrows(DataValidationException.class,  () ->
+                new ProjectionParameters( delta, projectionMethod) );
+        assertThat(exception).hasMessageContaining( "Delta" );
+    }
+
+    @Test
+    void unImplementedProjectionMethod_WhenCreatingANewInstance_raisesAValidationDataException()
+    {
+        int delta = 1;
+        String projectionMethod = "unknown method";
+        DataValidationException exception = assertThrows(DataValidationException.class,  () ->
+                new ProjectionParameters( delta, projectionMethod) );
+        assertThat(exception).hasMessageContaining( projectionMethod );
+    }
+
+
+}
diff --git a/src/test/java/fr/pasteur/ida/zellige/utils/LocalExtremaDetectionTest.java b/src/test/java/fr/pasteur/ida/zellige/utils/LocalExtremaDetectionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a2e2793e2cfa9e805bbd078b3b30380647bca23
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/utils/LocalExtremaDetectionTest.java
@@ -0,0 +1,19 @@
+package fr.pasteur.ida.zellige.utils;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class LocalExtremaDetectionTest
+{
+
+    @Test
+    void findMinima()
+    {
+    }
+
+    @Test
+    void findMaxima()
+    {
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/fr/pasteur/ida/zellige/utils/ReconstructionErrorsTest.java b/src/test/java/fr/pasteur/ida/zellige/utils/ReconstructionErrorsTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..38e905753d985dfdd682bcca4d044d1edb5e2452
--- /dev/null
+++ b/src/test/java/fr/pasteur/ida/zellige/utils/ReconstructionErrorsTest.java
@@ -0,0 +1,106 @@
+package fr.pasteur.ida.zellige.utils;
+
+import fr.pasteur.ida.zellige.exception.DifferentReferenceTestedSizeException;
+import fr.pasteur.ida.zellige.exception.NotAnHeightMapException;
+import io.scif.img.IO;
+import io.scif.img.SCIFIOImgPlus;
+import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.img.Img;
+import net.imglib2.img.ImgFactory;
+import net.imglib2.img.array.ArrayImgFactory;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.numeric.RealType;
+import net.imglib2.type.numeric.integer.IntType;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertThrows;
+
+public class ReconstructionErrorsTest
+{
+
+    @DisplayName( " The reference height map is not null" )
+    @Test
+    void whenTheReferenceHMisNullAnExceptionIsRaised()
+    {
+        ImgFactory< IntType> testedFactory = new ArrayImgFactory<>(new IntType());
+        RandomAccessibleInterval<IntType> tested = testedFactory.create( 4, 5 );
+        assertThrows( NullPointerException.class, ()-> new ReconstructionErrors<IntType, IntType>( null, tested ));
+    }
+
+    @DisplayName( " The tested height map is not null" )
+    @Test
+    void whenTheTestedHMisNullAnExceptionIsRaised()
+    {
+        ImgFactory< IntType> refFactory = new ArrayImgFactory<>(new IntType());
+        RandomAccessibleInterval< IntType > ref = refFactory.create( 5, 5 );
+        assertThrows( NullPointerException.class, ()-> new ReconstructionErrors<IntType, IntType>( ref, null ));
+    }
+
+    @DisplayName( "The reference height map is a 2D image" )
+    @Test
+    void a3DImageCannotBeAReferenceHeightMap()
+    {
+        ImgFactory< IntType> refFactory = new ArrayImgFactory<>(new IntType());
+        RandomAccessibleInterval< IntType > ref = refFactory.create( 5, 5, 5 );
+        ImgFactory< IntType> testedFactory = new ArrayImgFactory<>(new IntType());
+        RandomAccessibleInterval<IntType> tested = testedFactory.create( 4, 5 );
+        assertThrows( NotAnHeightMapException.class, ()-> new ReconstructionErrors<>( ref, tested ));
+    }
+
+    @DisplayName( "The tested height map is a 2D image" )
+    @Test
+    void a3DImageCannotBeATestedHeightMap()
+    {
+        ImgFactory< IntType> refFactory = new ArrayImgFactory<>(new IntType());
+        RandomAccessibleInterval< IntType > ref = refFactory.create( 5, 5 );
+        ImgFactory< IntType> testedFactory = new ArrayImgFactory<>(new IntType());
+        RandomAccessibleInterval<IntType> tested = testedFactory.create( 4, 5, 2 );
+        assertThrows( NotAnHeightMapException.class, ()-> new ReconstructionErrors<>( ref, tested ));
+    }
+
+    @DisplayName( " The reference height map has the same size as the tested height map" )
+    @Test
+    void whenTheReferenceHMAndTheTestedHMHaveADifferentSizeAnExceptionIsRaised()
+    {
+        ImgFactory< IntType> refFactory = new ArrayImgFactory<>(new IntType());
+        RandomAccessibleInterval< IntType > ref = refFactory.create( 5, 5 );
+        ImgFactory< IntType> testedFactory = new ArrayImgFactory<>(new IntType());
+        RandomAccessibleInterval<IntType> tested = testedFactory.create( 4, 5 );
+        assertThrows( DifferentReferenceTestedSizeException.class, ()-> new ReconstructionErrors<>( ref, tested ));
+    }
+
+
+    @DisplayName( "Two identical image has an RMSE equals to 0 " )
+    @Test
+    < T extends RealType< T > & NativeType< T >, R extends RealType< R > & NativeType< R > >
+    void whenTheRefHMAndTheTestedHMAreIdenticalTheRMSEEqualsZero() throws DifferentReferenceTestedSizeException, NotAnHeightMapException
+    {
+        final String imagePath = "doc/fakeHeightMap.tif";
+        final SCIFIOImgPlus< ? > imgPlus = IO.openImgs( imagePath ).get( 0 );
+
+        final Img< T > ref = ( Img< T > ) imgPlus.getImg();
+        final Img < R > tested = ( Img< R > ) imgPlus.getImg();
+        ReconstructionErrors< T, R > determination = new ReconstructionErrors<>( ref, tested );
+         determination.compute();
+         assertThat(determination.getRMSEValue() == 0 ).isTrue();
+
+    }
+
+    @DisplayName( "Two identical image has an reconstruction proportion equals to 1 " )
+    @Test
+    < T extends RealType< T > & NativeType< T >, R extends RealType< R > & NativeType< R > >
+    void whenTheRefHMAndTheTestedHMAreIdenticalTheReconstructionProportionEqualsOne() throws DifferentReferenceTestedSizeException, NotAnHeightMapException
+    {
+        final String imagePath = "doc/fakeHeightMap.tif";
+        final SCIFIOImgPlus< ? > imgPlus = IO.openImgs( imagePath ).get( 0 );
+
+        final Img< T > ref = ( Img< T > ) imgPlus.getImg();
+        final Img < R > tested = ( Img< R > ) imgPlus.getImg();
+        ReconstructionErrors< T, R > determination = new ReconstructionErrors<>( ref, tested );
+        determination.compute();
+        assertThat(determination.getReconstructedPixelsPercentage() == 1);
+
+    }
+}
diff --git a/src/test/java/fr/pasteur/ida/zellige/utils/islandSearch/SandTest.java b/src/test/java/fr/pasteur/ida/zellige/utils/islandSearch/SandTest.java
index 3780d51e8d843523d8bdc47ae43a400ec7cb2be1..361f5fc68942e111b64383ed1844f5344a44ae9a 100644
--- a/src/test/java/fr/pasteur/ida/zellige/utils/islandSearch/SandTest.java
+++ b/src/test/java/fr/pasteur/ida/zellige/utils/islandSearch/SandTest.java
@@ -7,12 +7,6 @@ import static org.junit.jupiter.api.Assertions.*;
 class SandTest
 {
 
-    @Test
-    void getIslandStatus()
-    {
-        Sand sand = new Sand( 0, 0, 0 );
-        assertEquals( 0, sand.getIslandStatus() );
-    }
 
     @Test
     void setIslandStatus()
diff --git a/src/test/java/fr/pasteur/ida/zellige/utils/islandSearch/WorldTest.java b/src/test/java/fr/pasteur/ida/zellige/utils/islandSearch/WorldTest.java
index f92aff74cc3c7ccc66d11c742c08ba366343c9e9..f2f14e76df1c955275af203eab336d1cf4eaa735 100644
--- a/src/test/java/fr/pasteur/ida/zellige/utils/islandSearch/WorldTest.java
+++ b/src/test/java/fr/pasteur/ida/zellige/utils/islandSearch/WorldTest.java
@@ -34,10 +34,10 @@ class WorldTest
 
 
 
-        world.run();
-        assertEquals( world.getSand( 0, 1, 0 ).getIslandStatus(), 1 );
-        assertEquals( world.getSand( 8, 0, 0 ).getIslandStatus(), - 1 );
-        assertEquals( world.getSand( 0, 0, 1 ).getIslandStatus(), 1 );
+//        world.run();
+//        assertEquals( world.getSand( 0, 1, 0 ).getIslandStatus(), 1 );
+//        assertEquals( world.getSand( 8, 0, 0 ).getIslandStatus(), - 1 );
+//        assertEquals( world.getSand( 0, 0, 1 ).getIslandStatus(), 1 );
     }
 
     @Test
@@ -77,12 +77,8 @@ class WorldTest
         Sand s5 = world.getSand(0, 2, 1 ) ;
         Sand s6 = world.getSand(0, 0, 1 ) ;
         assertEquals( s3.getIslandStatus(), 1 );
-        assertEquals( s4.getIslandStatus(), 0 );
-        assertEquals( s5.getIslandStatus(), 0 );
 
-        assertEquals( s6.getIslandStatus(), 0 );
-        world.setIslandStatus( s6 );
-        assertEquals( s6.getIslandStatus(), 1 );
+
     }
 
 
diff --git a/src/test/resources/MaximumsParameterSweep.csv b/src/test/resources/MaximumsParameterSweep.csv
new file mode 100644
index 0000000000000000000000000000000000000000..45b08fc5cb7e4f7e8ea7c77c86ec422c94bfeb55
--- /dev/null
+++ b/src/test/resources/MaximumsParameterSweep.csv
@@ -0,0 +1,50 @@
+;;Pretreatment;;Classification;;PostTreatment;;;;Construction;;;;;
+;;Filter ;Filter Parameters;Amplitude Threshold;Otsu Threshold;IS Connexity;IS minimum size;XY blur;Z Blur;Starting threshold %;overlap;connexity rate;Starting threshold %;overlap;connexity rate
+;;Median;2;0.5;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+AmplitudeThreshold;0;Median;2;0;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+AmplitudeThreshold;0.1;Median;2;0.1;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+AmplitudeThreshold;0.2;Median;2;0.2;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+AmplitudeThreshold;0.3;Median;2;0.3;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+AmplitudeThreshold;0.4;Median;2;0.4;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+AmplitudeThreshold;0.5;Median;2;0.5;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+AmplitudeThreshold;0.6;Median;2;0.6;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+AmplitudeThreshold;0.7;Median;2;0.7;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+AmplitudeThreshold;0.8;Median;2;0.8;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+AmplitudeThreshold;0.9;Median;2;0.9;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+AmplitudeThreshold;1;Median;2;1;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+Otsu Threshold;0;Median;2;0.5;0;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+Otsu Threshold;0.1;Median;2;0.5;0.1;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+Otsu Threshold;0.2;Median;2;0.5;0.2;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+Otsu Threshold;0.3;Median;2;0.5;0.3;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+Otsu Threshold;0.4;Median;2;0.5;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+Otsu Threshold;0.5;Median;2;0.5;0.5;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+Otsu Threshold;0.6;Median;2;0.5;0.6;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+Otsu Threshold;0.7;Median;2;0.5;0.7;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+Otsu Threshold;0.8;Median;2;0.5;0.8;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+Otsu Threshold;0.9;Median;2;0.5;0.9;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+Otsu Threshold;1;Median;2;0.5;1;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+IS Connexity;4;Median;2;0.5;0.4;4;5;2;1;0.75;15;0.8;0.1;10;0.9
+IS Connexity;8;Median;2;0.5;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+IS Min Size;0;Median;2;0.5;0.4;8;0;2;1;0.75;15;0.8;0.1;10;0.9
+IS Min Size;1;Median;2;0.5;0.4;8;1;2;1;0.75;15;0.8;0.1;10;0.9
+IS Min Size;2;Median;2;0.5;0.4;8;2;2;1;0.75;15;0.8;0.1;10;0.9
+IS Min Size;3;Median;2;0.5;0.4;8;3;2;1;0.75;15;0.8;0.1;10;0.9
+IS Min Size;4;Median;2;0.5;0.4;8;4;2;1;0.75;15;0.8;0.1;10;0.9
+IS Min Size;5;Median;2;0.5;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+IS Min Size;6;Median;2;0.5;0.4;8;6;2;1;0.75;15;0.8;0.1;10;0.9
+IS Min Size;7;Median;2;0.5;0.4;8;7;2;1;0.75;15;0.8;0.1;10;0.9
+IS Min Size;8;Median;2;0.5;0.4;8;8;2;1;0.75;15;0.8;0.1;10;0.9
+IS Min Size;9;Median;2;0.5;0.4;8;9;2;1;0.75;15;0.8;0.1;10;0.9
+IS Min Size;10;Median;2;0.5;0.4;8;10;2;1;0.75;15;0.8;0.1;10;0.9
+Blur XY;0;Median;2;0.5;0.4;8;5;0;1;0.75;15;0.8;0.1;10;0.9
+Blur XY;1;Median;2;0.5;0.4;8;5;1;1;0.75;15;0.8;0.1;10;0.9
+Blur XY;2;Median;2;0.5;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+Blur XY;3;Median;2;0.5;0.4;8;5;3;1;0.75;15;0.8;0.1;10;0.9
+Blur XY;4;Median;2;0.5;0.4;8;5;4;1;0.75;15;0.8;0.1;10;0.9
+Blur XY;5;Median;2;0.5;0.4;8;5;5;1;0.75;15;0.8;0.1;10;0.9
+BlurZ;0;Median;2;0.5;0.4;8;5;2;0;0.75;15;0.8;0.1;10;0.9
+BlurZ;1;Median;2;0.5;0.4;8;5;2;1;0.75;15;0.8;0.1;10;0.9
+BlurZ;2;Median;2;0.5;0.4;8;5;2;2;0.75;15;0.8;0.1;10;0.9
+BlurZ;3;Median;2;0.5;0.4;8;5;2;3;0.75;15;0.8;0.1;10;0.9
+BlurZ;4;Median;2;0.5;0.4;8;5;2;4;0.75;15;0.8;0.1;10;0.9
+BlurZ;5;Median;2;0.5;0.4;8;5;2;5;0.75;15;0.8;0.1;10;0.9
diff --git a/src/test/resources/TestTTT.csv b/src/test/resources/TestTTT.csv
new file mode 100644
index 0000000000000000000000000000000000000000..7322a1a9795b98925fec409ebe30207465af325b
--- /dev/null
+++ b/src/test/resources/TestTTT.csv
@@ -0,0 +1,2 @@
+Median;2
+Prout;1
diff --git a/src/test/resources/test.csv b/src/test/resources/test.csv
new file mode 100644
index 0000000000000000000000000000000000000000..eb2eaef1585db85b5b9e23a0d191eeaea7d68089
--- /dev/null
+++ b/src/test/resources/test.csv
@@ -0,0 +1,2 @@
+Median;1
+Median;2