diff --git a/src/main/java/fr/pasteur/ida/zellige/steps/selection/util/Unbinning.java b/src/main/java/fr/pasteur/ida/zellige/steps/selection/util/Unbinning.java
new file mode 100644
index 0000000000000000000000000000000000000000..a459cd24caccc9d677e90345d92c0d80cbda98ba
--- /dev/null
+++ b/src/main/java/fr/pasteur/ida/zellige/steps/selection/util/Unbinning.java
@@ -0,0 +1,139 @@
+package fr.pasteur.ida.zellige.steps.selection.util;
+
+import io.scif.img.ImgOpener;
+import net.imagej.ImageJ;
+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.type.numeric.integer.UnsignedByteType;
+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;
+
+/**
+ * Generates an unbinned image, according to the input image and bin value. Only for 2D images.
+ * @param <T> the image type
+ */
+public class Unbinning< T extends RealType< T > & NativeType< T > >
+{
+ private final static Logger LOGGER = LoggerFactory.getLogger( Unbinning.class );
+ private final Img< T > output;
+ private final RandomAccessibleInterval< T > binned;
+ private final int bin;
+
+
+ /**
+ *
+ * @param input a binned image
+ * @param factory the input image factory
+ * @param bin the bin size
+ * @return the input image unbinned
+ * @param <T> input and output image type
+ */
+ public static < T extends RealType< T > & NativeType< T> > Img<T> run( RandomAccessibleInterval<T> input, ImgFactory<T> factory, int bin)
+ {
+ Img <T> output = factory.create( input.dimension( 0 ) * bin, input.dimension( 1 ) * bin);
+ Unbinning<T> unbinning = new Unbinning<>( input, bin, output );
+ unbinning.run();
+ return output;
+ }
+
+ /**
+ * Constructor
+ * @param input a binned image
+ * @param bin the bin size
+ * @param output he input image unbinned
+ */
+ public Unbinning( RandomAccessibleInterval< T > input, int bin, Img< T > output )
+ {
+ this.binned = input;
+ this.bin = bin;
+ this.output = output;
+ }
+
+ /**
+ * Parses the binned image and assign the corresponding values to the unbinned image.
+ */
+ public void run()
+ {
+ LOGGER.debug( "Starting process..." );
+
+ double startTime = System.currentTimeMillis();
+
+ RandomAccess<T> binnedAccess = binned.randomAccess();
+ RandomAccess<T> outputAccess = output.randomAccess();
+
+ for ( int y = 0; y < binned.dimension( 1 ) ; y++ )
+ {
+ for ( int x = 0; x < binned.dimension( 0 ); x ++)
+ {
+ T value = setPositionAndGet( binnedAccess, x, y );
+ applyValueToGrid( x, y, bin, outputAccess, value);
+ }
+ }
+ double endTime = System.currentTimeMillis();
+
+ LOGGER.debug( "Process completed in {}s" , (endTime-startTime)/1000);
+ }
+
+
+ /**
+ *
+ * @param X the starting x value
+ * @param Y the starting y value
+ * @param bin the bin size
+ * @param access the unbinned image {@link RandomAccess<T>}
+ * @param value the pixel value to assign
+ */
+ private void applyValueToGrid( int X, int Y, int bin, RandomAccess< T > access, T value )
+ {
+ for ( int y = Y * bin; y < Y * bin + bin; y++ )
+ {
+ for ( int x = X * bin; x < X * bin + bin; x++ )
+ {
+ setPosition( access, x, y );
+ access.get().set( value );
+ }
+ }
+
+ }
+
+ public static void main( String[] args )
+ {
+ 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 = 4;
+ 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" );
+ }
+
+}
+