diff --git a/src/main/java/fr/pasteur/ida/zellige/steps/selection/pretreatment/Pretreatment.java b/src/main/java/fr/pasteur/ida/zellige/steps/selection/pretreatment/Pretreatment.java
index 24c51b30d3eccc68b46a53d92d3f69fa9799c125..c3733503dfe179d1852432e6c3c085bc8ad6485a 100644
--- a/src/main/java/fr/pasteur/ida/zellige/steps/selection/pretreatment/Pretreatment.java
+++ b/src/main/java/fr/pasteur/ida/zellige/steps/selection/pretreatment/Pretreatment.java
@@ -6,13 +6,13 @@
  * %%
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
- * 
+ *
  * 1. Redistributions of source code must retain the above copyright notice,
  *    this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright notice,
  *    this list of conditions and the following disclaimer in the documentation
  *    and/or other materials provided with the distribution.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -28,69 +28,79 @@
  */
 package fr.pasteur.ida.zellige.steps.selection.pretreatment;
 
+import fr.pasteur.ida.zellige.steps.Utils;
+import fr.pasteur.ida.zellige.steps.selection.exception.BinningFailedException;
+import fr.pasteur.ida.zellige.steps.selection.util.Binning;
+import fr.pasteur.ida.zellige.steps.selection.util.Unbinning;
 import io.scif.img.ImgOpener;
-import net.imglib2.RandomAccessible;
-import net.imglib2.RandomAccessibleInterval;
-import net.imglib2.algorithm.convolution.fast_gauss.FastGauss;
-import net.imglib2.algorithm.fft2.FFTConvolution;
-import net.imglib2.algorithm.gauss3.Gauss3;
+import net.imagej.ImageJ;
+import net.imglib2.*;
 import net.imglib2.algorithm.stats.Normalize;
-import net.imglib2.converter.Converters;
-import net.imglib2.converter.RealTypeConverters;
-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.Type;
 import net.imglib2.type.numeric.RealType;
-import net.imglib2.type.numeric.complex.ComplexFloatType;
+import net.imglib2.type.numeric.integer.UnsignedByteType;
 import net.imglib2.type.numeric.real.FloatType;
 import net.imglib2.util.ImgUtil;
-import net.imglib2.util.RealSum;
-import net.imglib2.view.IntervalView;
-import net.imglib2.view.Views;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+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;
+
 public class Pretreatment< T extends RealType< T > & NativeType< T > >
 {
     private final static Logger LOGGER = LoggerFactory.getLogger( Pretreatment.class );
 
-    private final RandomAccessibleInterval< T > input;
-    //    private final PretreatmentParameters pretreatmentParameters;
-    private final double radius;
-    private Img< FloatType > output;
-
 
-    Pretreatment( RandomAccessibleInterval< T > input, double radius )
+    public static < T extends RealType< T > & NativeType< T > > Img< FloatType >
+    run( Img< T > input, double radius )
     {
-        this.input = input;
-        this.radius = radius;
-    }
 
+        Pretreatment< T > pretreatment = new Pretreatment<>();
+        return pretreatment.runSteps( input, radius );
+    }
 
     public static < T extends RealType< T > & NativeType< T > > Img< FloatType >
-    run( RandomAccessibleInterval< T > input, double radius )
+    run( Img< T > input )
     {
-        LOGGER.debug( "Starting process..." );
-        Pretreatment< T > pretreatment = new Pretreatment<>( input, radius );
-        pretreatment.run();
-        LOGGER.debug( "Process complete." );
-        return pretreatment.getOutput();
+        return run( input, 2 );
     }
 
-    public static < T extends RealType< T > & NativeType< T > > Img< FloatType >
-    run( RandomAccessibleInterval< T > input )
+
+    private Img< FloatType > runSteps( Img< T > input, double radius )
     {
         LOGGER.debug( "Starting process..." );
-        Pretreatment< T > pretreatment = new Pretreatment<>( input, 2 );
-        pretreatment.run();
-        LOGGER.debug( "Process complete." );
-        return pretreatment.getOutput();
+        try
+        {
+            Img< T > temp = Binning.binning( input, getBin() ); // Binning op
+            if (temp == null)
+            {
+                throw new BinningFailedException();
+            }
+            Img< FloatType > output = gaussianBlurFilterDenoising( temp, temp.factory(), radius ); // Filtering op
+
+            // The denoised image is normalized between 0 and 255
+            output = normalizeImage( output, output.factory() ); // normalizing op
+            return output;
+        }
+
+        catch ( OutOfMemoryError oom )
+        {
+            LOGGER.error( "Out of memory", oom );
+            LOGGER.info( "The Input image is too large. Try Incrementing the Bin value or allow more memory to your Fiji" );
+            return null;
+        }
+        catch ( BinningFailedException bfe )
+        {
+            LOGGER.info("The binning process has failed. Please send a issue on gitlab");
+            return null;
+        }
     }
 
-
     /**
      * Normalizes the pixel values of an Img between 0 and 255.
      *
@@ -100,7 +110,7 @@ public class Pretreatment< T extends RealType< T > & NativeType< T > >
      * @return a new Img with normalize pixel intensity values.
      */
     private static < T extends RealType< T > & NativeType< T > > Img< T > normalizeImage(
-           RandomAccessibleInterval< T > image, ImgFactory< T > factory )
+            RandomAccessibleInterval< T > image, ImgFactory< T > factory )
     {
         LOGGER.debug( "Staring normalization." );
         Img< T > normalizedImage = factory.create( image.dimensionsAsLongArray() );
@@ -110,75 +120,57 @@ public class Pretreatment< T extends RealType< T > & NativeType< T > >
         T max = normalizedImage.firstElement().copy().createVariable();
         max.setReal( 255 );
         Normalize.normalize( normalizedImage, min, max );
-        LOGGER.debug( "End of normalization." );
+        LOGGER.debug( "Input normalized." );
         return normalizedImage;
     }
 
-    /**
-     * Applies the denoising step on the specified input according to the specified method
-     *
-     * @param input the noisy image as a {@link RandomAccessibleInterval}
-     * @return a denoised image as a  {@link Img}
-     */
-    Img< FloatType > denoisingStep( RandomAccessibleInterval< FloatType > input )
-    {
-        LOGGER.debug( "Starting denoising step..." );
-        RandomAccessibleInterval< FloatType > converted = Converters.convert( input, new RealFloatSamplerConverter<>() );
-
-        LOGGER.debug( "Denoising step complete, with gaussian filter" );
-        return gaussianBlurFilterDenoising( converted );
-
-    }
-
-    /**
-     * @param input   -  the source image as a {@link RandomAccessibleInterval}
-     * @param factory - the source and output factory
-     * @param sigma   - an array containing the standard deviations for each dimension.
-     * @param <T>     - source and output type
-     * @return - the filtered image as a {@link RandomAccessibleInterval}
-     */
-    public static < T extends RealType< T > & NativeType< T > > Img< T >
-    gaussianConvolution( RandomAccessibleInterval< T > input, ImgFactory< T > factory, double[] sigma )
-    {
-        Img< T > output = factory.create( input );
-        RandomAccessible< T > infiniteInput = Views.extendValue( input, input.randomAccess().get().getRealFloat() );
-        Gauss3.gauss( sigma, infiniteInput, output );
-        return output;
-    }
-
-    void run()
-    {
-        // The input is converted into FloatType
-        RandomAccessibleInterval< FloatType > converted = Converters.convert( input, new RealFloatSamplerConverter<>() );
-        LOGGER.debug( "Input converted." );
-        //The choose method of denoising is applied
-        Img< FloatType > denoised = denoisingStep( converted );
-        // The denoised image is normalized between 0 and 255
-        this.output = normalizeImage( denoised, denoised.factory() );
-        LOGGER.debug( "Input normalized." );
-
-    }
 
     /**
      * Applies a gaussian filter to a noisy image
      *
-     * @param input the noisy image as a {@link RandomAccessibleInterval}
+     * @param input   the noisy image as a {@link RandomAccessibleInterval}
+     * @param factory the input factory
      * @return a denoised image as a  {@link Img}
      */
-    Img< FloatType > gaussianBlurFilterDenoising( RandomAccessibleInterval< FloatType > input )
-    {
-        ImgFactory< FloatType > factory = new ArrayImgFactory<>( new FloatType() );
-        return gaussianConvolution( input, factory, new double[]{ radius, radius, 1 } );
-    }
-
-    public RandomAccessibleInterval< T > getInput()
+    private static < T extends RealType< T > & NativeType< T > > Img< FloatType > gaussianBlurFilterDenoising( RandomAccessibleInterval< T > input, ImgFactory< T > factory, double radius )
     {
-        return input;
+        ImgFactory< FloatType > newImgFactory = factory.imgFactory( new FloatType() );
+        Img< FloatType > output = newImgFactory.create( input.dimensionsAsLongArray() );
+        Utils.gaussianConvolution_( input, output, new double[]{ radius, radius, 1 } );
+        return output;
     }
 
 
-    public Img< FloatType > getOutput()
+    public static void main( String[] args )
     {
-        return output;
+        ImageJ ij = new ImageJ();
+        ij.launch( args );
+        final ImgOpener io = new ImgOpener();
+        @SuppressWarnings( "unchecked" ) final Img< UnsignedByteType > kernel = ( Img< UnsignedByteType > ) io.openImgs( "doc/Scan1_volume_crop.tif" ).get( 0 );
+        ImageJFunctions.show( kernel, "original" );
+        double time1 = System.currentTimeMillis();
+        int bin = 1;
+        Img< UnsignedByteType > output = Binning.binning( kernel,  bin );
+        double time2 = System.currentTimeMillis();
+        LOGGER.debug( "Multithreading time  = {}s", ( time2 - time1 ) / 1000 );
+        assert output != null;
+        ImageJFunctions.show( output, "output " );
+
+        Img< UnsignedByteType > i = kernel.factory().create( output.dimension( 0 ), output.dimension( 1 ) );
+        RandomAccess< UnsignedByteType > access = i.randomAccess();
+        RandomAccess< UnsignedByteType > cursor = output.randomAccess();
+        for ( int y = 0; y < i.dimension( 1 ); y++ )
+        {
+            for ( int x = 0; x < i.dimension( 0 ); x++ )
+            {
+                setPosition( access, x, y );
+                access.get().setReal( setPositionAndGet( cursor, x, y ).getRealDouble() );
+            }
+        }
+
+        Img< UnsignedByteType > output_unbinned = Unbinning.run( i, i.factory(), bin );
+        ImageJFunctions.show( output_unbinned, "unbinned 1" );
     }
 }
+
+