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" ); } } + +