diff --git a/src/main/java/fr/pasteur/ida/zellige/steps/selection/util/Binning.java b/src/main/java/fr/pasteur/ida/zellige/steps/selection/util/Binning.java
index ae6be221fe734d110c3142861ce58d74b7f242d4..97b1e5e60e9c2c64cccb8b345ab3a766c0baecdc 100644
--- a/src/main/java/fr/pasteur/ida/zellige/steps/selection/util/Binning.java
+++ b/src/main/java/fr/pasteur/ida/zellige/steps/selection/util/Binning.java
@@ -1,17 +1,14 @@
 package fr.pasteur.ida.zellige.steps.selection.util;
 
-import io.scif.img.ImgOpener;
+import io.scif.img.IO;
 import net.imagej.ImageJ;
-import net.imglib2.Cursor;
-import net.imglib2.RandomAccess;
-import net.imglib2.RandomAccessibleInterval;
+import net.imglib2.*;
 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.real.FloatType;
-import net.imglib2.view.IntervalView;
+import net.imglib2.util.Util;
 import net.imglib2.view.Views;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -23,9 +20,6 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
-import static fr.pasteur.ida.zellige.steps.Utils.setPosition;
-import static fr.pasteur.ida.zellige.steps.Utils.setPositionAndGet;
-import static fr.pasteur.ida.zellige.steps.selection.pretreatment.PretreatmentParameters.getBin;
 
 @SuppressWarnings( "unchecked" )
 public class Binning< T extends RealType< T > & NativeType< T > >
@@ -42,44 +36,56 @@ public class Binning< T extends RealType< T > & NativeType< T > >
 
 
     /**
-     * Reduces the size of a stack by binning groups of pixels of user-specified square sizes (bin). The resulting pixel is obtained by taking the upper left pixel of the group.
-     * The image is rescaled if the bin value is not a multiple of the image dimensions by adding lines and/or columns. The process is parallelized according to the number of available processors (1/4).
+     * Reduces the size of a stack by binning groups of pixels of user-specified square sizes (bin). The resulting pixel
+     * is obtained by taking the upper left pixel of the group.
+     * The process is parallelized according to the number of available processors (1/4).
      *
-     * @param <T>     the input type
-     * @param input   the image to binned
-     * @param bin     the bin size
+     * @param <T>   the input type
+     * @param input the image to binned
+     * @param bin   the bin size
      * @return the binned input image
      */
-    public static < T extends RealType< T > & NativeType< T > > Img< T > binning( Img <T> input,  int bin )
+    public static < T extends RealType< T > & NativeType< T > > Img< T >
+    run( final RandomAccessibleInterval< T > input, int bin )
     {
-        if (bin == 1)
+        if ( bin == 1 )
         {
-            return input;
+            return null;
         }
         LOGGER.debug( "Staring process...." );
         double startTime = System.currentTimeMillis();
-        Binning< T > binning = new Binning<>( resize( input, input.factory(), bin ), bin );
-        final int threads = Runtime.getRuntime().availableProcessors() / 4; //TODO Optimize the number of threads
+        final int threads = Runtime.getRuntime().availableProcessors() / 2;
         LOGGER.info( "Numbers of  processors: {}", threads );
-        final List< Integer > chunks = new ArrayList<>();
-        for ( int i = 0; i < input.dimension( 2 ); i++ )
+        int nbSlices = ( int ) input.dimension( input.numDimensions() - 1 );
+
+        Binning< T > binning = new Binning<>( input, bin );
+        final List< Integer > chunks = new ArrayList<>( nbSlices );
+        for ( int i = 0; i < nbSlices; i++ )
         {
             chunks.add( i ); // size equals to number of slices
         }
         final List< Runnable > runnables =
                 chunks.stream()
-                        .map( chunk -> new Binning2D<>( Views.hyperSlice( input, 2, chunk ), Views.hyperSlice( binning.getOutput(), 2, chunk ), bin ) )
+                        .map( chunk -> new Binning2D<>(
+                                Views.hyperSlice( input, 2, chunk ),
+                                Views.hyperSlice( binning.getOutput(), 2, chunk ),
+                                bin ) )
                         .collect( Collectors.toList() );
         final ExecutorService executorService = Executors.newFixedThreadPool( threads );
         runnables.forEach( executorService::submit );
+        for ( final Runnable r : runnables )
+        {
+            executorService.submit( r );
+            LOGGER.debug( "One task executed" );
+        }
         executorService.shutdown();
         try
         {
             if ( executorService.awaitTermination( 300, TimeUnit.SECONDS ) )
             {
                 double endTime = System.currentTimeMillis();
-                LOGGER.debug( "Image pretreated with a binning of {} by {}.", getBin(), getBin() );
-                LOGGER.debug( "Process completed in {}s" , (endTime-startTime)/1000);
+                LOGGER.debug( "Image pretreated with a binning of {} by {}.", bin, bin );
+                LOGGER.debug( "Process completed in {}s", ( endTime - startTime ) / 1000 );
                 return binning.getOutput();
             }
             else
@@ -90,35 +96,46 @@ public class Binning< T extends RealType< T > & NativeType< T > >
         }
         catch ( InterruptedException e )
         {
-
             throw new RuntimeException( e );
         }
-
     }
 
 
+    public static int nb = 0;
+
+
+
     /**
      * @param input the image to binned
      * @param bin   the bin size
      */
-    public Binning( Img< T > input, int bin )
+    public Binning( RandomAccessibleInterval< T > input, int bin )
     {
-        int[] dimensions = new int[]{
-                // X and Y dimensions are divided by the bin value, the other dimensions are the same
-                ( int ) input.dimension( 0 ) / ( bin ),
+        nb++;
+        int x = ( int ) input.dimension( 0 ) / ( bin );
+        int y = ( int ) input.dimension( 1 ) / ( bin );
+        int z = ( int ) input.dimension( 2 );
+
+        // X and Y dimensions are divided by the bin value, the other dimensions are the same
+
+        //output = input.factory().create( dimensions );
+        ImgFactory< T > factory = Util.getSuitableImgFactory( new FinalDimensions( ( int ) input.dimension( 0 ) / ( bin ),
                 ( int ) input.dimension( 1 ) / ( bin ),
-                ( int ) input.dimension( 2 ) };
-        output = input.factory().create( dimensions );
+                ( int ) input.dimension( 2 ) ), input.getType() );
+        output = factory.create( x, y, z );
     }
 
+
     /**
+     * Static class
      * Bins a 2D image.
+     *
      * @param <T> the image type
      */
-    private static final class Binning2D< T extends RealType< T > & NativeType< T > > implements Runnable
+    private static class Binning2D< T extends RealType< T > & NativeType< T > > implements Runnable
     {
-        private final IntervalView< T > inputSlice;
-        private final IntervalView< T > outputSlice;
+        private final RandomAccessibleInterval< T > inputSlice;
+        private final RandomAccessibleInterval< T > outputSlice;
         private final int bin;
 
         /**
@@ -128,93 +145,54 @@ public class Binning< T extends RealType< T > & NativeType< T > >
          * @param outputSlice the output binned image
          * @param bin         the bin size
          */
-        public Binning2D( IntervalView< T > inputSlice, IntervalView< T > outputSlice, int bin )
+        public Binning2D( RandomAccessibleInterval< T > inputSlice, RandomAccessibleInterval< T > outputSlice, int bin )
         {
             this.inputSlice = inputSlice;
             this.outputSlice = outputSlice;
             this.bin = bin;
         }
 
-
         /**
          * Binning process.
          */
         @Override
         public void run()
         {
-            RandomAccess< T > ra = inputSlice.randomAccess();
-            Cursor< T > c = outputSlice.cursor();
-
-            for ( int y = 0; y < inputSlice.dimension( 1 ); y = y + bin )
-
+            try
             {
-                for ( int x = 0; x < inputSlice.dimension( 0 ); x = x + bin )
-                {
-                    c.fwd();
-                    c.get().set( setPositionAndGet( ra, x, y ) );
-                }
-            }
-            LOGGER.info( "Binning : Section processed" );
-        }
-    }
-
-
-    /**
-     * Rescales a 3D image according to the bin value.
-     *
-     * @param <T>     the input type
-     * @param input   the image to binned
-     * @param factory the image factory
-     * @param bin     the bin size
-     * @return the input or the rescaled input if necessary
-     */
-    public static < T extends RealType< T > & NativeType< T > > Img< T > resize( RandomAccessibleInterval< T > input, ImgFactory< T > factory, int bin )
-    {
-        Img< T > output;
-        int moduloX = ( int ) ( input.dimension( 0 ) % bin );
-        int moduloY = ( int ) ( input.dimension( 1 ) % bin );
+                LOGGER.debug( "Starting to bin a section !" );
 
-        if ( moduloX == 0 && moduloY == 0 )
-        {
-            output = factory.create(input);
-            return output;
-        }
-        else
-        {
-            int dimX = ( int ) input.dimension( 0 ) + ( bin - moduloX );
-            int dimY = ( int ) input.dimension( 1 ) + ( bin - moduloY );
-            output = factory.create( dimX, dimY, input.dimension( input.numDimensions() - 1 ) );
-            RandomAccess< T > inputAccess = input.randomAccess();
-            RandomAccess< T > outputAccess = input.randomAccess();
-            for ( int z = 0; z < input.dimension( input.numDimensions() - 1 ) ; z++ )
-            {
-                for ( int y = 0; y < input.dimension( 1 ); y++ )
+                RandomAccess< T > ra = inputSlice.randomAccess( inputSlice );
+                RandomAccess< T > raOut = outputSlice.randomAccess();
+                for ( int y = 0; y < inputSlice.dimension( 1 ); y = y + bin )
                 {
-                    for ( int x = 0; x < input.dimension( 0 ); x++ )
+                    for ( int x = 0; x < inputSlice.dimension( 0 ); x = x + bin )
                     {
-                        setPosition( outputAccess, x, y, z );
-                        outputAccess.get().set( setPositionAndGet( inputAccess, x, y, z ) );
+                        raOut.setPositionAndGet( x / bin, y / bin ).set( ra.setPositionAndGet( x, y ) );
                     }
                 }
-                LOGGER.info( " The input image has been rescaled to fit the binning process." );
+                LOGGER.info( "Section processed" );
+            }
+            catch ( Exception e )
+            {
+                throw new RuntimeException( e );
             }
-            return output;
         }
-
     }
 
-    public static void main( String[] args )
+
+    public static < T extends RealType< T > & NativeType< T > > void main( String[] args ) throws InterruptedException
     {
         ImageJ ij = new ImageJ();
         ij.launch( args );
-        final ImgOpener io = new ImgOpener();
-        final Img< FloatType > kernel = ( Img< FloatType > ) io.openImgs( "doc/Scan1_volume_crop.tif" ).get( 0 );
-        ImageJFunctions.show( kernel, "original" );
-
-        Img< FloatType > output = Binning.binning( kernel, 7 );
+//        Thread.sleep( 20000 );
+        //final ImgOpener io = new ImgOpener();
+        // final Img< FloatType > kernel = ( Img< FloatType > ) io.openImgs( "doc/Scan1_volume.tif" ).get( 0 );
+        final Img< T > stackImage = ( Img< T > ) IO.openAll( "doc/Scan1_volume_crop.tif" ).get( 0 ).getImg(); // TODO Handling larger images
+//        ImageJFunctions.show( stackImage, "original" );
 
+        Img< T > output = Binning.run( stackImage, 2 );
         assert output != null;
-        ImageJFunctions.show( output, "output " );
-
+        ImageJFunctions.show(output, "binned");
     }
 }