Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 10-multi-channel-image-handling
  • 25-multithreads-heavy-tasks
  • 9-gui-features
  • dev
  • dev-batch-mode
  • dev-display
  • master
  • median-3d
  • Cnam
  • zellige-core-1.0.0
  • zellige-core-1.1.0
  • zellige-core-1.1.1
  • zellige-core-1.1.3
13 results

Target

Select target project
  • ida-public/zellige-core
1 result
Select Git revision
  • 10-multi-channel-image-handling
  • 25-multithreads-heavy-tasks
  • 9-gui-features
  • dev
  • dev-batch-mode
  • dev-display
  • master
  • median-3d
  • Cnam
  • zellige-core-1.0.0
  • zellige-core-1.1.0
  • zellige-core-1.1.1
  • zellige-core-1.1.3
13 results
Show changes
Showing
with 1119 additions and 440 deletions
......@@ -55,14 +55,12 @@ public class ClassificationParameters
{
if ( value < 0 )
{
throw new DataValidationException( "The value of parameter " + name + " has to be superior to zero !" );
throw new DataValidationException( "The value of parameter " + name + " has to be superior or equal to zero !" );
}
if ( value > 255 )
{
throw new DataValidationException( "The value of parameter " + name + " has to be inferior or equals to 50!" );
throw new DataValidationException( "The value of parameter " + name + " has to be inferior or equals to 255!" );
}
}
......
......@@ -64,7 +64,7 @@ public class OtsuClassification< T extends RealType< T > & NativeType< T > >
this.input = input;
this.output = output;
this.userThreshold = userThreshold;
this.grid = factory.create( input );
this.grid = factory.create( input.dimensionsAsLongArray() );
}
/**
......@@ -74,7 +74,7 @@ public class OtsuClassification< T extends RealType< T > & NativeType< T > >
private OtsuClassification( final RandomAccessibleInterval< T > input, final ImgFactory< T > factory )
{
this.input = input;
this.grid = factory.create( input );
this.grid = factory.create( input.dimensionsAsLongArray() );
}
/**
......@@ -91,7 +91,7 @@ public class OtsuClassification< T extends RealType< T > & NativeType< T > >
long start = System.currentTimeMillis();
// Prepare output.
final ImgFactory< BitType > bitTypeImgFactory = net.imglib2.util.Util.getArrayOrCellImgFactory( input, new BitType() );
Img< BitType > binary = bitTypeImgFactory.create( input );
Img< BitType > binary = bitTypeImgFactory.create( input.dimensionsAsLongArray() );
OtsuClassification< T > classification = new OtsuClassification<>( input, factory, binary, userThreshold );
classification.run();
long stop = System.currentTimeMillis();
......@@ -131,7 +131,7 @@ public class OtsuClassification< T extends RealType< T > & NativeType< T > >
{
long start = System.currentTimeMillis();
final ImgFactory< BitType > bitTypeImgFactory = net.imglib2.util.Util.getArrayOrCellImgFactory( input, new BitType() );
Img< BitType > output = bitTypeImgFactory.create( input );
Img< BitType > output = bitTypeImgFactory.create( input.dimensionsAsLongArray() );
Cursor< T > sourceCursor = input.localizingCursor();
Cursor< T > gridCursor = grid.cursor();
RandomAccess< BitType > randomAccess = output.randomAccess();
......
......@@ -52,31 +52,31 @@ public class Threshold
* @param <T> - the input type
* @return - the maximum value of the specified input
*/
public static < T extends RealType< T > & NativeType< T > > T findMax( final IterableInterval< T > input )
{
Cursor< T > iterator = input.cursor();
T max = input.firstElement().createVariable();
while ( iterator.hasNext() )
{
final T type = iterator.next();
if ( type.compareTo( max ) > 0 )
{
max.set( type );
}
}
return max;
}
public static < T extends RealType< T > & NativeType< T > > T findMin( final IterableInterval< T > input, boolean zero )
{
if ( zero )
{
return findMinBesideZero( input );
}
return findMin( input );
}
// public static < T extends RealType< T > & NativeType< T > > T findMax( final IterableInterval< T > input )
// {
// Cursor< T > iterator = input.cursor();
// T max = input.firstElement().createVariable();
// while ( iterator.hasNext() )
// {
// final T type = iterator.next();
//
// if ( type.compareTo( max ) > 0 )
// {
// max.set( type );
// }
// }
// return max;
// }
//
// public static < T extends RealType< T > & NativeType< T > > T findMin( final IterableInterval< T > input, boolean zero )
// {
// if ( zero )
// {
// return findMinBesideZero( input );
// }
// return findMin( input );
// }
/**
......@@ -86,183 +86,183 @@ public class Threshold
* @param <T> - the input type
* @return the minimal value of the specified input
*/
public static < T extends RealType< T > & NativeType< T > > T findMin( final IterableInterval< T > input )
{
Cursor< T > cursor = input.cursor();
T type = cursor.next();
T min = type.createVariable();
while ( cursor.hasNext() )
{
type = cursor.next().copy();
if ( type.compareTo( min ) <= 0 )
{
min.set( type.copy() );
}
}
return min;
}
public static < T extends RealType< T > & NativeType< T > > T findMinBesideZero( final IterableInterval< T > input )
{
Cursor< T > cursor = input.cursor();
double min = Max.findMax( input ).get().getRealDouble();
while ( cursor.hasNext() )
{
cursor.fwd();
final double value = cursor.get().getRealDouble();
if ( value > 0 && value < min )
{
min = value;
}
}
T minimum = input.firstElement().createVariable();
minimum.setReal( min );
return minimum;
}
// public static < T extends RealType< T > & NativeType< T > > T findMin( final IterableInterval< T > input )
// {
// Cursor< T > cursor = input.cursor();
// T type = cursor.next();
// T min = type.createVariable();
// while ( cursor.hasNext() )
// {
// type = cursor.next().copy();
// if ( type.compareTo( min ) <= 0 )
// {
// min.set( type.copy() );
// }
// }
// return min;
// }
//
//
// public static < T extends RealType< T > & NativeType< T > > T findMinBesideZero( final IterableInterval< T > input )
// {
// Cursor< T > cursor = input.cursor();
// double min = Max.findMax( input ).get().getRealDouble();
// while ( cursor.hasNext() )
// {
// cursor.fwd();
// final double value = cursor.get().getRealDouble();
// if ( value > 0 && value < min )
// {
// min = value;
// }
// }
//
// T minimum = input.firstElement().createVariable();
// minimum.setReal( min );
// return minimum;
// }
// TODO implements Otsu-2D ???
public static < T extends RealType< T > & NativeType< T > > int[] getHistogram( IterableInterval< T > image, T min, T max, int numBins )
{
HistogramZ< T > H = new HistogramZ<>( new RealBinMapper<>( min, max, numBins ), image );
H.process();
return H.getHistogram();
}
public static int OtsuCelebiIndex( int[] histogram )
{
// Otsu's threshold algorithm
// M. Emre Celebi 6.15.2007, Fourier Library https://sourceforge.net/projects/fourier-ipal/
// ported to ImageJ plugin by G.Landini
int ih;
int threshold;
int num_pixels = 0;
double total_mean; /* mean gray-level for the whole image */
double bcv, term; /* between-class variance, scaling term */
double max_bcv; /* max BCV */
double[] cnh = new double[ histogram.length ]; /* cumulative normalized histogram */
double[] mean = new double[ histogram.length ]; /* mean gray-level */
double[] h = new double[ histogram.length ];/* normalized histogram */
/* Calculate total number of pixels */
for ( ih = 0; ih < histogram.length; ih++ )
{
num_pixels = num_pixels + histogram[ ih ];
}
term = 1.0 / ( double ) num_pixels;
/* Calculate the normalized histogram */
for ( ih = 0; ih < histogram.length; ih++ )
{
h[ ih ] = term * histogram[ ih ];
}
/* Calculate the cumulative normalized histogram */
cnh[ 0 ] = h[ 0 ];
for ( ih = 1; ih < histogram.length; ih++ )
{
cnh[ ih ] = cnh[ ih - 1 ] + h[ ih ];
}
mean[ 0 ] = 0.0;
for ( ih = 1; ih < histogram.length; ih++ )
{
mean[ ih ] = mean[ ih - 1 ] + ih * h[ ih ];
}
total_mean = mean[ histogram.length - 1 ];
// Calculate the BCV at each gray-level and find the threshold that maximizes it
threshold = Integer.MIN_VALUE;
max_bcv = 0.0;
for ( ih = 0; ih < histogram.length; ih++ )
{
bcv = total_mean * cnh[ ih ] - mean[ ih ];
bcv *= bcv / ( cnh[ ih ] * ( 1.0 - cnh[ ih ] ) );
if ( max_bcv < bcv )
{
max_bcv = bcv;
threshold = ih;
}
}
return threshold;
}
public static < T extends RealType< T > & NativeType< T > > T getThreshold( IterableInterval< T > input )
{
T max = Threshold.findMax( input );
T min = Threshold.findMin( input );
int[] histogram = getHistogram( input, min, max, 256 );
return getThreshold( min, max, histogram );
}
public static < T extends RealType< T > & NativeType< T > > T getThreshold( IterableInterval< T > input, double percent )
{
T max = Threshold.findMax( input );
T min = Threshold.findMin( input );
int[] histogram = getHistogram( input, min, max, 256 );
T threshold = getThreshold( min, max, histogram );
threshold.mul( percent );
return threshold;
}
public static < T extends RealType< T > & NativeType< T > > T getThreshold( T min, T max, int[] histogram )
{
histogram[ 0 ] = 0;
int thresholdIndex = OtsuCelebiIndex( histogram );
return getBinValueFromIndex( min, max, histogram, thresholdIndex );
}
public static < T extends RealType< T > & NativeType< T > > T getBinValueFromIndex( T min, T max, int[] histogram, int thresholdIndex )
{
double binWidth = ( max.getRealDouble() - min.getRealDouble() ) / ( double ) histogram.length;
double result = ( ( double ) ( thresholdIndex + 1 ) * binWidth + min.getRealDouble() );
T threshold = min.createVariable();
threshold.setReal( result );
return threshold;
}
public static < T extends RealType< T > & NativeType< T > > T getFirstMaxValue( Img< T > input, boolean zero )
{
T max = Threshold.findMax( input );
T min = Threshold.findMin( input );
int numBins = (int)max.getRealDouble();
HistogramZ< T > H = new HistogramZ<>( new RealBinMapper<>( min, max, 256 ), input );
H.process();
int[] histogram = H.getHistogram();
if ( zero )
{
histogram[ 0 ] = 0;
}
int index = getFirstMaxIndex( histogram );
return H.getBinCenter( index );
}
public static int getFirstMaxIndex( int[] histogram )
{
for ( int i = 2; i <= histogram.length - 2; i++ )
{
if ( histogram[ i - 1 ] < histogram[ i ] && histogram[ i ] > histogram[ i + 1 ] )
{
return i;
}
}
return - 1; // no max ?
}
//
// public static < T extends RealType< T > & NativeType< T > > int[] getHistogram( IterableInterval< T > image, T min, T max, int numBins )
// {
// HistogramZ< T > H = new HistogramZ<>( new RealBinMapper<>( min, max, numBins ), image );
// H.process();
//
// return H.getHistogram();
// }
// public static int OtsuCelebiIndex( int[] histogram )
// {
// // Otsu's threshold algorithm
// // M. Emre Celebi 6.15.2007, Fourier Library https://sourceforge.net/projects/fourier-ipal/
// // ported to ImageJ plugin by G.Landini
//
// int ih;
// int threshold;
// int num_pixels = 0;
// double total_mean; /* mean gray-level for the whole image */
// double bcv, term; /* between-class variance, scaling term */
// double max_bcv; /* max BCV */
// double[] cnh = new double[ histogram.length ]; /* cumulative normalized histogram */
// double[] mean = new double[ histogram.length ]; /* mean gray-level */
// double[] h = new double[ histogram.length ];/* normalized histogram */
//
// /* Calculate total number of pixels */
// for ( ih = 0; ih < histogram.length; ih++ )
// {
// num_pixels = num_pixels + histogram[ ih ];
// }
//
// term = 1.0 / ( double ) num_pixels;
//
// /* Calculate the normalized histogram */
// for ( ih = 0; ih < histogram.length; ih++ )
// {
// h[ ih ] = term * histogram[ ih ];
// }
//
// /* Calculate the cumulative normalized histogram */
// cnh[ 0 ] = h[ 0 ];
// for ( ih = 1; ih < histogram.length; ih++ )
// {
// cnh[ ih ] = cnh[ ih - 1 ] + h[ ih ];
// }
//
// mean[ 0 ] = 0.0;
//
// for ( ih = 1; ih < histogram.length; ih++ )
// {
// mean[ ih ] = mean[ ih - 1 ] + ih * h[ ih ];
// }
//
// total_mean = mean[ histogram.length - 1 ];
//
// // Calculate the BCV at each gray-level and find the threshold that maximizes it
// threshold = Integer.MIN_VALUE;
// max_bcv = 0.0;
//
// for ( ih = 0; ih < histogram.length; ih++ )
// {
// bcv = total_mean * cnh[ ih ] - mean[ ih ];
// bcv *= bcv / ( cnh[ ih ] * ( 1.0 - cnh[ ih ] ) );
//
// if ( max_bcv < bcv )
// {
// max_bcv = bcv;
// threshold = ih;
// }
// }
// return threshold;
// }
// public static < T extends RealType< T > & NativeType< T > > T getThreshold( IterableInterval< T > input )
// {
// T max = Threshold.findMax( input );
// T min = Threshold.findMin( input );
// int[] histogram = getHistogram( input, min, max, 256 );
// return getThreshold( min, max, histogram );
// }
//
//
// public static < T extends RealType< T > & NativeType< T > > T getThreshold( IterableInterval< T > input, double percent )
// {
// T max = Threshold.findMax( input );
// T min = Threshold.findMin( input );
// int[] histogram = getHistogram( input, min, max, 256 );
// T threshold = getThreshold( min, max, histogram );
// threshold.mul( percent );
// return threshold;
// }
//
// public static < T extends RealType< T > & NativeType< T > > T getThreshold( T min, T max, int[] histogram )
// {
// histogram[ 0 ] = 0;
// int thresholdIndex = OtsuCelebiIndex( histogram );
// return getBinValueFromIndex( min, max, histogram, thresholdIndex );
// }
//
// public static < T extends RealType< T > & NativeType< T > > T getBinValueFromIndex( T min, T max, int[] histogram, int thresholdIndex )
// {
// double binWidth = ( max.getRealDouble() - min.getRealDouble() ) / ( double ) histogram.length;
// double result = ( ( double ) ( thresholdIndex + 1 ) * binWidth + min.getRealDouble() );
// T threshold = min.createVariable();
// threshold.setReal( result );
// return threshold;
// }
//
// public static < T extends RealType< T > & NativeType< T > > T getFirstMaxValue( Img< T > input, boolean zero )
// {
// T max = Threshold.findMax( input );
// T min = Threshold.findMin( input );
// int numBins = (int)max.getRealDouble();
// HistogramZ< T > H = new HistogramZ<>( new RealBinMapper<>( min, max, 256 ), input );
// H.process();
// int[] histogram = H.getHistogram();
//
// if ( zero )
// {
// histogram[ 0 ] = 0;
// }
// int index = getFirstMaxIndex( histogram );
//
// return H.getBinCenter( index );
// }
//
// public static int getFirstMaxIndex( int[] histogram )
// {
// for ( int i = 2; i <= histogram.length - 2; i++ )
// {
// if ( histogram[ i - 1 ] < histogram[ i ] && histogram[ i ] > histogram[ i + 1 ] )
// {
// return i;
// }
// }
// return - 1; // no max ?
// }
}
package fr.pasteur.ida.zellige.steps.selection.exception;
public class BinningFailedException extends Exception
{
}
package fr.pasteur.ida.zellige.steps.selection.exception;
public class ImageTooLargeException extends Exception
{
public ImageTooLargeException( )
{
super( "message" );
}
}
package fr.pasteur.ida.zellige.steps.selection.exception;
public class ParameterException extends Exception
{
public ParameterException( String message )
{
super( message );
}
}
......@@ -28,22 +28,17 @@
*/
package fr.pasteur.ida.zellige.steps.selection.postTreatment;
import fr.pasteur.ida.zellige.element.Coordinate;
import fr.pasteur.ida.zellige.element.Pixels;
import fr.pasteur.ida.zellige.steps.Utils;
import fr.pasteur.ida.zellige.steps.selection.exception.DataValidationException;
import fr.pasteur.ida.zellige.steps.selection.postTreatment.islandSearch.IslandSearch;
import fr.pasteur.ida.zellige.steps.selection.util.ExtremaDetection;
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.img.array.ArrayImgFactory;
import net.imglib2.type.NativeType;
import net.imglib2.img.display.imagej.ImageJFunctions;
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;
......@@ -52,7 +47,8 @@ public class PostTreatment
{
private final static Logger LOGGER = LoggerFactory.getLogger( PostTreatment.class );
private Pixels[][] output;
// private Pixels[][] output;
private Img<FloatType> output ;
private final Img< BitType > input;
......@@ -61,14 +57,14 @@ public class PostTreatment
this.input = input;
}
public static Pixels[][] run( Img< BitType > input, PostTreatmentParameters parameters ) throws DataValidationException
public static Img<FloatType> run( Img< BitType > input, PostTreatmentParameters parameters ) throws DataValidationException
{
PostTreatment postTreatment = new PostTreatment( input );
postTreatment.process( parameters );
return postTreatment.getOutput();
}
public static Pixels[][] run( Img< BitType > input, double sigmaXY, double sigmaZ, int islandSize ) throws DataValidationException
public static Img<FloatType> run( Img< BitType > input, double sigmaXY, double sigmaZ, int islandSize ) throws DataValidationException
{
PostTreatment postTreatment = new PostTreatment( input );
postTreatment.process( sigmaXY, sigmaZ, islandSize );
......@@ -82,7 +78,7 @@ public class PostTreatment
public static Img< FloatType > convertBitTypeIntoFloatType( IterableInterval< BitType > image )
{
final ImgFactory< FloatType > imgFactory = new ArrayImgFactory<>( new FloatType() );
final Img< FloatType > copy = imgFactory.create( image );
final Img< FloatType > copy = imgFactory.create( image.dimensionsAsLongArray() );
Cursor< BitType > bitTypeCursor = image.cursor();
Cursor< FloatType > floatTypeCursor = copy.cursor();
......@@ -118,49 +114,7 @@ public class PostTreatment
Utils.gaussianConvolution( input.copy(), input, new double[]{ sigmaXY, sigmaXY, sigmaZ } );
}
void runDilatation( Img< FloatType > input, PostTreatmentParameters parameters )
{
double sigmaXY = parameters.getSigmaXY();
double sigmaZ = parameters.getSigmaZ();
LOGGER.debug( "Running dilatation with sigma XY = {} and sigma Z = {}", sigmaXY, sigmaZ );
Utils.gaussianConvolution( 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 static < 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 static Pixels[][] runSmoothing( Img< BitType > ISImage, int sigmaXY, int sigmaZ ) throws DataValidationException
public static Img< FloatType > runSmoothing( Img< BitType > ISImage, int sigmaXY, int sigmaZ ) throws DataValidationException
{
Img< FloatType > converted = convertBitTypeIntoFloatType( ISImage );
// Use of Converter.convert() not possible because classifiedPixel type do not extend RealType
......@@ -170,30 +124,13 @@ public class PostTreatment
/* Final local maximum detection */
converted = ExtremaDetection.findMaxima( converted.copy(), converted.factory() );
return buildPixelArray( converted );
// ImageJFunctions.show(converted);
return converted;
}
public void process( PostTreatmentParameters parameters ) throws DataValidationException
{
LOGGER.debug( "Starting post treatment." );
/* Isolated Pixel removal */
int islandSize = parameters.getIslandSize();
Img< BitType > temp = input;
if ( islandSize != 0 )
{
temp = runIslandSearch( input, islandSize );
}
/* Conversion into FloatType before dilatation */
Img< FloatType > converted = convertBitTypeIntoFloatType( temp );
// Use of Converter.convert() not possible because classifiedPixel type do not extend RealType
/* Dilatation of the resulting image*/
runDilatation( converted, parameters );
/* Final local maximum detection */
converted = ExtremaDetection.findMaxima( converted.copy(), converted.factory() );
output = buildPixelArray( converted );
LOGGER.debug( "Post treatment complete" );
process(parameters.getSigmaXY(), parameters.getSigmaZ(), parameters.getIslandSize() );
}
public void process( double sigmaXY, double sigmaZ, int islandSize ) throws DataValidationException
......@@ -213,12 +150,12 @@ public class PostTreatment
runDilatation( converted, sigmaXY, sigmaZ );
/* Final local maximum detection */
converted = ExtremaDetection.findMaxima( converted.copy(), converted.factory() );
output = buildPixelArray( converted );
output= ExtremaDetection.findMaxima( converted.copy(), converted.factory() );
LOGGER.debug( "Post treatment complete" );
}
public Pixels[][] getOutput()
public Img<FloatType> getOutput()
{
return output;
}
......
......@@ -79,7 +79,7 @@ public class IslandSearch
{
long start = System.currentTimeMillis();
ImgFactory< BitType > factory = new ArrayImgFactory<>( new BitType() );
Img< BitType > output = factory.create( classifiedImage );
Img< BitType > output = factory.create( classifiedImage.dimensionsAsLongArray() );
ImgUtil.copy( classifiedImage, output );
new IslandSearch( classifiedImage, output, islandSize, connectivityType );
long stop = System.currentTimeMillis();
......
......@@ -28,60 +28,80 @@
*/
package fr.pasteur.ida.zellige.steps.selection.pretreatment;
import net.imglib2.RandomAccessible;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.algorithm.gauss3.Gauss3;
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.imagej.ImageJ;
import net.imglib2.*;
import net.imglib2.algorithm.stats.Normalize;
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.numeric.RealType;
import net.imglib2.type.numeric.integer.UnsignedByteType;
import net.imglib2.type.numeric.real.FloatType;
import net.imglib2.util.ImgUtil;
import net.imglib2.view.Views;
import net.imglib2.util.Util;
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;
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( RandomAccessibleInterval< T > input, double radius, int bin )
{
this.input = input;
this.radius = radius;
Pretreatment< T > pretreatment = new Pretreatment<>();
return pretreatment.runSteps( input, radius, bin );
}
public static < T extends RealType< T > & NativeType< T > > Img< FloatType >
run( RandomAccessibleInterval< T > input, double radius )
private Img< FloatType > runSteps( RandomAccessibleInterval< T > input, double radius, int bin )
{
LOGGER.debug( "Starting process..." );
Pretreatment< T > pretreatment = new Pretreatment<>( input, radius );
pretreatment.run();
LOGGER.debug( "Process complete." );
return pretreatment.getOutput();
Img< FloatType > output;
try
{
if (bin == 1)
{
output = gaussianBlurFilterDenoising( input, radius );
}
public static < T extends RealType< T > & NativeType< T > > Img< FloatType >
run( RandomAccessibleInterval< T > input )
else
{
LOGGER.debug( "Starting process..." );
Pretreatment< T > pretreatment = new Pretreatment<>( input, 2 );
pretreatment.run();
LOGGER.debug( "Process complete." );
return pretreatment.getOutput();
Img< T > temp = Binning.run( input, bin ); // Binning op
if (temp == null)
{
throw new BinningFailedException();
}
output = gaussianBlurFilterDenoising( temp, 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.
......@@ -92,83 +112,67 @@ 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(
Img< T > image, ImgFactory< T > factory )
RandomAccessibleInterval< T > image, ImgFactory< T > factory )
{
Img< T > normalizedImage = factory.create( image );
LOGGER.debug( "Staring normalization." );
Img< T > normalizedImage = factory.create( image.dimensionsAsLongArray() );
ImgUtil.copy( image, normalizedImage );
T min = normalizedImage.firstElement().createVariable();
min.setReal( 0 );
T max = normalizedImage.firstElement().copy().createVariable();
max.setReal( 255 );
Normalize.normalize( normalizedImage, min, max );
LOGGER.debug( "Input normalized." );
return normalizedImage;
}
/**
* Applies the denoising step on the specified input according to the specified method
* 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 > denoisingStep( RandomAccessibleInterval< FloatType > input )
private static < T extends RealType< T > & NativeType< T > > Img< FloatType > gaussianBlurFilterDenoising( RandomAccessibleInterval< T > input, double radius )
{
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 );
Dimensions dimensions = new FinalDimensions( input.dimension( 0 ), input.dimension( 1 ), input.dimension( 2 ) );
ImgFactory< FloatType > newImgFactory = Util.getArrayOrCellImgFactory(dimensions, new FloatType());
Img< FloatType > output = newImgFactory.create( input.dimensionsAsLongArray() );
Utils.gaussianConvolution_( input, output, new double[]{ radius, radius, 1 } );
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}
* @return a denoised image as a {@link Img}
*/
Img< FloatType > gaussianBlurFilterDenoising( RandomAccessibleInterval< FloatType > input )
public static void main( String[] args )
{
ImgFactory< FloatType > factory = new ArrayImgFactory<>( new FloatType() );
return gaussianConvolution( input, factory, new double[]{ radius, radius, 1 } );
}
public RandomAccessibleInterval< T > getInput()
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.run( 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++ )
{
return input;
setPosition( access, x, y );
access.get().setReal( setPositionAndGet( cursor, x, y ).getRealDouble() );
}
}
public Img< FloatType > getOutput()
{
return output;
Img< UnsignedByteType > output_unbinned = Unbinning.run( i, bin );
ImageJFunctions.show( output_unbinned, "unbinned 1" );
}
}
......@@ -28,72 +28,41 @@
*/
package fr.pasteur.ida.zellige.steps.selection.pretreatment;
import fr.pasteur.ida.zellige.steps.selection.exception.DataValidationException;
public class PretreatmentParameters
{
public static final String GAUSSIAN_BLUR = "GaussianBlur";
public static final String NOT_IMPLEMENTED = "not implemented";
private final String method;
private final double parameter;
private final int bin;
private final int channel;
public PretreatmentParameters( String method, double parameter ) throws DataValidationException
public PretreatmentParameters( int channel, int bin )
{
this.checkParameters( method, parameter );
this.method = method;
this.parameter = parameter;
this.channel = channel;
this.bin = bin;
}
/**
* Checks if the method end the arguments methods are valid
*
* @param method the method choose
* @param parameter the method arguments
* @throws DataValidationException if at least one is not valid
*/
private void checkParameters( String method, double parameter ) throws DataValidationException
public String getMethod()
{
checkDenoisingMethod( method );
checkParametersLength( parameter );
return "GaussianBlur"; // Constant for now
}
/**
* Checks the length of the parameters according to the method choose
*
* @param parameter the method arguments
* @throws DataValidationException if at the parameters' length (the number of arguments) is not valid according to the method choose
*/
private void checkParametersLength( double parameter ) throws DataValidationException
{
if ( parameter < 0 || parameter > 10 )
public double getRadius()
{
throw new DataValidationException( "The parameter value has to be comprise between 0 and 10" );
}
//TODO different thresholds values for methods ?
return 2; // Constant for now
}
/**
* 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 ) )
public int getChannel()
{
throw new DataValidationException( "The denoising method " + denoisingMethod + " is " + NOT_IMPLEMENTED + " in the program" );
}
return channel;
}
public String getMethod()
public int getBin()
{
return method;
return bin;
}
public double getParameter()
{
return parameter;
}
}
package fr.pasteur.ida.zellige.steps.selection.util;
import fr.pasteur.ida.zellige.gui.exception.NoA3DStackException;
import fr.pasteur.ida.zellige.gui.exception.TimeLapseException;
import fr.pasteur.ida.zellige.steps.selection.exception.ParameterException;
import net.imagej.Dataset;
import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.RealType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ArgumentCheck
{
private final static Logger LOGGER = LoggerFactory.getLogger( ArgumentCheck.class );
public static < T extends RealType< T > & NativeType< T > > Dataset input( Dataset dataset) throws TimeLapseException, NoA3DStackException
{
int nbDim = dataset.numDimensions();
int nbSlices = ( int ) dataset.getDepth();
int nbFrames = ( int ) dataset.getFrames();
int nbChannels = ( int ) dataset.getChannels();
// Set the file info label
if ( nbFrames > 1 )
{
LOGGER.debug( "TimeLapseException" );
throw new TimeLapseException() ;
}
if ( nbSlices == 1 )
{
LOGGER.debug( "NoA3DStackException" );
throw new NoA3DStackException() ;
}
LOGGER.info("Input: {}", dataset.getName());
LOGGER.info( "NUmber of dimensions: {}", nbDim );
LOGGER.info( "NUmber of channels: {}", nbChannels );
LOGGER.info( "Number of frames: {}", nbFrames );
return dataset;
}
public static int bin( String BIN) throws ParameterException
{
try
{
int bin = Integer.parseInt( BIN );
if ( bin < 0 )
{
throw new ParameterException( " The value of bin parameter can not be negative" );
}
if ( bin > 30 )
{
throw new ParameterException( " The value of bin parameter is to high" );
}
LOGGER.info( "Bin: {}", bin );
return bin;
}
catch (NumberFormatException nfe)
{
throw new ParameterException( " The bin value must be an integer" );
}
}
public static int channel( String CHANNEL, int channelNb) throws ParameterException
{
try
{
int channel = Integer.parseInt( CHANNEL );
if ( channel < 0 )
{
throw new ParameterException( " The value of channel parameter can not be negative" );
}
if ( channel > channelNb )
{
throw new ParameterException( String.format(" There is no channel %d in the input image " , channel));
}
LOGGER.info( "Target channel:: {}", channel );
return channel;
}
catch (NumberFormatException nfe)
{
throw new ParameterException( " The channel value must be an integer" );
}
}
public static int amplitude( String AMPLITUDE) throws ParameterException
{
try
{
int amplitude = Integer.parseInt( AMPLITUDE );
if ( amplitude < 0 )
{
throw new ParameterException( " The value of amplitude parameter can not be negative" );
}
if ( amplitude > 255 )
{
throw new ParameterException( " The value of amplitude parameter must be inferior or equal to 255" );
}
LOGGER.info( "Amplitude threshold: {}", amplitude );
return amplitude;
}
catch (NumberFormatException nfe)
{
throw new ParameterException( " The amplitude value must be an integer" );
}
}
public static int otsu( String OTSU) throws ParameterException
{
try
{
int otsu = Integer.parseInt( OTSU );
if ( otsu < 0 )
{
throw new ParameterException( " The value of otsu parameter can not be negative" );
}
if ( otsu > 255 )
{
throw new ParameterException( " The value of otsu parameter must be inferior or equal to 255" );
}
LOGGER.info( "Otsu threshold: {}", otsu );
return otsu;
}
catch (NumberFormatException nfe)
{
throw new ParameterException( " The otsu value must be an integer" );
}
}
public static int islandSize( String ISLAND_SIZE) throws ParameterException
{
try
{
int islandSize = Integer.parseInt( ISLAND_SIZE );
if ( islandSize < 0 )
{
throw new ParameterException( " The value of islandSize parameter can not be negative" );
}
if ( islandSize > 50 )
{
throw new ParameterException( " The value of islandSize parameter must be inferior or equal to 50" );
}
LOGGER.info( "Island size: {}", islandSize );
return islandSize;
}
catch (NumberFormatException nfe)
{
throw new ParameterException( " The island size value must be an integer" );
}
}
public static double sigmaXY( String SIGMA_XY) throws ParameterException
{
try
{
double sigmaXY = Double.parseDouble( SIGMA_XY );
if ( sigmaXY < 0 )
{
throw new ParameterException( " The value of sigmaXY parameter can not be negative" );
}
if ( sigmaXY > 10 )
{
throw new ParameterException( " The value of sigmaXY parameter must be inferior or equal to 10" );
}
LOGGER.info( "XY smoothing: {}", sigmaXY );
return sigmaXY;
}
catch (NumberFormatException nfe)
{
throw new ParameterException( " The sigmaXY value must be a number" );
}
}
public static double sigmaZ( String SIGMA_Z) throws ParameterException
{
try
{
double sigmaZ = Double.parseDouble( SIGMA_Z );
if ( sigmaZ < 0 )
{
throw new ParameterException( " The value of sigmaZ parameter can not be negative" );
}
if ( sigmaZ > 10 )
{
throw new ParameterException( " The value of sigmaZ parameter must be inferior or equal to 10" );
}
LOGGER.info( "Z smoothing: {}", sigmaZ );
return sigmaZ;
}
catch (NumberFormatException nfe)
{
throw new ParameterException( " The sigmaXY value must be a number" );
}
}
public static double startingOsSize( String OS_SIZE, int round) throws ParameterException
{
String os = (round == 2 ? "First round": "Second round");
try
{
double osSize = Double.parseDouble( OS_SIZE );
if ( osSize < 0 )
{
throw new ParameterException(
String.format( " The value of %s starting OS size (ST%d) parameter can not be negative",
os, round ));
}
if ( osSize > 1 )
{
throw new ParameterException(
String.format(" The value of %s starting OS size (ST%d) parameter must be inferior or equal to 1",
os, round ));
}
LOGGER.info( "{} Starting OS size: {}", os, osSize );
return osSize;
}
catch (NumberFormatException nfe)
{
throw new ParameterException( String.format(" The %s starting OS size (ST%d) parameter must a number comprise between 0 and 1",
os, round ));
}
}
public static double connexity( String CONNEXITY, int ROUND) throws ParameterException
{
String round = (ROUND == 2 ? "First round": "Second round");
try
{
double connexity = Double.parseDouble( CONNEXITY );
if ( connexity < 0 )
{
throw new ParameterException(
String.format( " The value of %s connexity rate (CR%d) parameter can not be negative",
round, ROUND ));
}
if ( connexity > 1 )
{
throw new ParameterException(
String.format(" The value of %s connexity rate (CR%d) parameter must be inferior or equal to 1",
round, ROUND ));
}
LOGGER.info( "{} connexity: {}", round, connexity );
return connexity;
}
catch (NumberFormatException nfe)
{
throw new ParameterException( String.format(" The %s connexity rate (CR%d) parameter must a number comprise between 0 and 1",
round, ROUND ));
}
}
public static int overlap( String OVERLAP, int ROUND) throws ParameterException
{
String round = (ROUND == 2 ? "First round": "Second round");
try
{
int overlap = Integer.parseInt( OVERLAP );
if ( overlap < 0 )
{
throw new ParameterException(
String.format(" The value of the %s overlap parameter (R%d) can not be negative",round, ROUND ));
}
if ( overlap > 50 )
{
throw new ParameterException(
String.format( " The value of the %s overlap parameter (R%d) must be inferior or equal to 50",
round, ROUND ));
}
LOGGER.info( "{} overlap: {}", round, overlap );
return overlap;
}
catch (NumberFormatException nfe)
{
throw new ParameterException( " The %s overlap value (R%d) must be a integer" );
}
}
public static int delta( String DELTA, int channel) throws ParameterException
{
if( DELTA.isEmpty())
{
throw new ParameterException( String.format(" Missing value delta value for channel %d", channel ));
}
try
{
int delta = Integer.parseInt( DELTA );
if ( delta < 0 )
{
throw new ParameterException( " The value of delta parameter can not be negative" );
}
if ( delta > 30 )
{
throw new ParameterException( " The value of delta parameter is to high" );
}
LOGGER.info( "Delta: {}",delta );
return delta;
}
catch (NumberFormatException nfe)
{
throw new ParameterException( " The delta value must be a integer" );
}
}
public static int offset( String OFFSET, int channel) throws ParameterException
{
if( OFFSET.isEmpty())
{
throw new ParameterException( String.format(" Missing value delta value for channel %d", channel ));
}
try
{
int offset = Integer.parseInt( OFFSET );
if ( offset < 0 )
{
throw new ParameterException( " The value of offset parameter can not be negative" );
}
if ( offset > 30 )
{
throw new ParameterException( " The value of offset parameter is to high" );
}
LOGGER.info( "Offset: {}",offset );
return offset;
}
catch (NumberFormatException nfe)
{
throw new ParameterException( " The delta value must be a integer" );
}
}
public static String method( String METHOD, int channel) throws ParameterException
{
if( METHOD.isEmpty())
{
throw new ParameterException( String.format(" Missing value delta value for channel %d", channel ));
}
if ( !METHOD.equals("MIP") && !METHOD.equals("MEAN"))
{
throw new ParameterException( " The method %s ois not implemented in Zellige, try MIP or MEAN" );
}
LOGGER.info( "Method: {}",METHOD );
return METHOD;
}
}
package fr.pasteur.ida.zellige.steps.selection.util;
import io.scif.img.IO;
import net.imagej.ImageJ;
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.util.Util;
import net.imglib2.view.Views;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@SuppressWarnings( "unchecked" )
public class Binning< T extends RealType< T > & NativeType< T > >
{
private final static Logger LOGGER = LoggerFactory.getLogger( Binning.class );
public Img< T > getOutput()
{
return output;
}
private final Img< T > output;
/**
* 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
* @return the binned input image
*/
public static < T extends RealType< T > & NativeType< T > > Img< T >
run( final RandomAccessibleInterval< T > input, int bin )
{
LOGGER.debug( "Staring process...." );
double startTime = System.currentTimeMillis();
final int threads = Runtime.getRuntime().availableProcessors() / 2;
LOGGER.info( "Numbers of processors: {}", threads );
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 ) )
.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 {}.", bin, bin );
LOGGER.debug( "Process completed in {}s", ( endTime - startTime ) / 1000 );
return binning.getOutput();
}
else
{
LOGGER.debug( "The binning has failed." );
return null;
}
}
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( RandomAccessibleInterval< T > input, int 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 ) ), input.getType() );
output = factory.create( x, y, z );
}
/**
* Static class
* Bins a 2D image.
*
* @param <T> the image type
*/
private static class Binning2D< T extends RealType< T > & NativeType< T > > implements Runnable
{
private final RandomAccessibleInterval< T > inputSlice;
private final RandomAccessibleInterval< T > outputSlice;
private final int bin;
/**
* Constructor
*
* @param inputSlice the input image
* @param outputSlice the output binned image
* @param bin the bin size
*/
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()
{
try
{
LOGGER.debug( "Starting to bin a section !" );
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 < inputSlice.dimension( 0 ); x = x + bin )
{
raOut.setPositionAndGet( x / bin, y / bin ).set( ra.setPositionAndGet( x, y ) );
}
}
LOGGER.info( "Section processed" );
}
catch ( Exception e )
{
throw new RuntimeException( e );
}
}
}
public static < T extends RealType< T > & NativeType< T > > void main( String[] args ) throws InterruptedException
{
ImageJ ij = new ImageJ();
ij.launch( args );
// 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, "binned");
}
}
......@@ -43,7 +43,6 @@ import org.slf4j.LoggerFactory;
public class ExtremaDetection< T extends RealType< T > & NativeType< T > >
{
public static final String MAX = "max";
public static final String MIN = "min";
private final static Logger LOGGER = LoggerFactory.getLogger( ExtremaDetection.class );
......@@ -59,7 +58,7 @@ public class ExtremaDetection< T extends RealType< T > & NativeType< T > >
parameterCheck( input, factory, type, method );
this.input = input;
this.factory = factory;
this.extrema = factory.create( input );
this.extrema = factory.create( input.dimensionsAsLongArray() );
this.type = type;
LOGGER.debug( "Partial derivative is : {}", method );
}
......
......@@ -40,7 +40,6 @@ import static fr.pasteur.ida.zellige.steps.selection.util.ExtremaDetection.MAX;
public class ExtremaDetection2D< T extends RealType< T > & NativeType< T > >
{
private final RandomAccessibleInterval< T > inputSection;
private final ImgFactory< T > factory;
private final RandomAccessibleInterval< T > extrema;
......@@ -79,22 +78,20 @@ public class ExtremaDetection2D< T extends RealType< T > & NativeType< T > >
{
{
// Output for partial derivative.
RandomAccessibleInterval< T > sectionDerivative = factory.create( inputSection );
RandomAccessibleInterval< T > sectionDerivative = factory.create( inputSection.dimensionsAsLongArray() );
// Partial derivative computation */
Derivative.run( inputSection, sectionDerivative, method );
computeExtrema( inputSection, sectionDerivative );
}
}
/**
* @param section the section considered
* @param sectionDerivative the corresponding partial derivative section of the input image as a {@link RandomAccessibleInterval}
*/
private void
computeExtrema
( RandomAccessibleInterval< T > section, RandomAccessibleInterval< T > sectionDerivative
)
( RandomAccessibleInterval< T > section, RandomAccessibleInterval< T > sectionDerivative )
{
RandomAccess< T > derivativeAccess = Views.extendMirrorSingle( sectionDerivative ).randomAccess();
RandomAccess< T > extremaAccess = extrema.randomAccess();
......@@ -125,7 +122,7 @@ public class ExtremaDetection2D< T extends RealType< T > & NativeType< T > >
* @param z - the index of the Z dimension
* @return - true if the position (v, z) is a local maximum false otherwise.
*/
private boolean isALocalExtrema( RandomAccess< T > derivative, int z ) //throws Exception
private boolean isALocalExtrema( RandomAccess< T > derivative, int z )
{
derivative.setPosition( z, 1 );
final double tZero = derivative.get().getRealDouble();
......
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.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 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( Img <T> input, int bin)
{
if (bin == 1)
{
return input;
}
Img <T> output = input.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.run( 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, bin);
ImageJFunctions.show( output_unbinned, "unbinned 1" );
}
}
......@@ -28,10 +28,19 @@
*/
package fr.pasteur.ida.zellige.utils;
import net.imagej.Dataset;
import net.imglib2.Dimensions;
import net.imglib2.FinalDimensions;
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.loops.LoopBuilder;
import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.RealType;
import net.imglib2.view.IntervalView;
import net.imglib2.view.Views;
import static fr.pasteur.ida.zellige.steps.Utils.setPositionAndGet;
......@@ -55,4 +64,46 @@ public class Util
}
return array;
}
/**
* Creates a 4D {@link Img<T>} from a 3D {@link Dataset}
* @param dataset a 3D {@link Dataset}
* @return a 4D {@link Img<T>}
* @param <T> the dataset type
* @throws Exception if the input is not valid.
*/
public static < T extends RealType< T > & NativeType< T > > Img<T > create4dimImage( Dataset dataset ) throws Exception
{
int xDim = ( int ) dataset.getWidth();
int yDim = ( int ) dataset.getHeight();
int zDim = ( int ) dataset.getDepth();
return create4dimImage( ( RandomAccessibleInterval< T > ) dataset.getImgPlus().getImg(), xDim, yDim, zDim );
}
/**
* Adds a fourth dimension to a 3D image
* @param input a 3-dimensions {@link Img<T>}
* @param xDim the image's width
* @param yDim the image's height
* @param zDim the image's depth
* @return a 4D {@link Img<T>}
* @throws Exception if the input is not valid.
*/
public static < T extends RealType< T > & NativeType< T > > Img< T > create4dimImage( RandomAccessibleInterval< T > input, int xDim, int yDim, int zDim ) throws Exception
{
if( input.numDimensions() == 3 && input.dimension( 2 ) != 0 ) // if not a 3D stack
{
Dimensions dim = new FinalDimensions( new long[]{ xDim, yDim, 1, zDim } );
T type = input.getType();
ImgFactory< T > newFactory = net.imglib2.util.Util.getArrayOrCellImgFactory( dim, type.createVariable() );
Img< T > fourDimensionsOutput = newFactory.create( dim );
IntervalView< T > view = Views.hyperSlice( fourDimensionsOutput, 2, 0 );
LoopBuilder.setImages( input, view ).forEachPixel(
( a, b ) -> b.setReal( a.getRealDouble() ) );
return fourDimensionsOutput;
}
throw new Exception( "The input is not suitable for this function");
}
}
......@@ -65,10 +65,10 @@ public class All_GT_Display< T extends RealType< T > & NativeType< T > > extends
final String[] refImagePath = new String[]{
// "src/test/resources/Mouche_c01_f0001_p013/Ground truth Height map_1.tif",
"C:\\Users\\ctrebeau\\Desktop\\Zellige analysis\\files\\Mouche_c01_f0001_p013\\GT\\Ground truth Height map_1.tif",
"C:\\Users\\ctrebeau\\Desktop\\Zellige analysis\\files\\Mouche_c01_f0001_p013\\GT\\Ground truth Height map_2.tif",
"C:\\Users\\ctrebeau\\Desktop\\Zellige analysis\\files\\Mouche_c01_f0001_p013\\GT\\Ground truth Height map_3.tif",
"C:\\Users\\ctrebeau\\Desktop\\Zellige analysis\\files\\Mouche_c01_f0001_p013\\GT\\Ground truth Height map_4.tif"
"H:\\Projet\\Zellige\\Zellige analysis\\files\\Mouche_c01_f0001_p013\\GT\\Ground truth Height map_1.tif",
"H:\\Projet\\Zellige\\Zellige analysis\\files\\Mouche_c01_f0001_p013\\GT\\Ground truth Height map_2.tif",
"H:\\Projet\\Zellige\\Zellige analysis\\files\\Mouche_c01_f0001_p013\\GT\\Ground truth Height map_3.tif",
"H:\\Projet\\Zellige\\Zellige analysis\\files\\Mouche_c01_f0001_p013\\GT\\Ground truth Height map_4.tif"
};
......
......@@ -166,8 +166,8 @@ public class HM_black_GT_distanceDisplay_realImages< T extends RealType< T > & N
}
}
}
LOGGER.debug( "GTCount =" + GTCount );
LOGGER.debug( "HMCount =" + HMCount );
LOGGER.debug( "GTCount ={}", GTCount );
LOGGER.debug( "HMCount ={}", HMCount );
}
Scatter scatter = new Scatter( points, colors );
scatter.setWidth( 2 );
......
......@@ -165,8 +165,8 @@ public class HM_black_GT_distanceDisplay_realImages_2D< T extends RealType< T >
}
}
}
LOGGER.debug( "GTCount =" + GTCount );
LOGGER.debug( "HMCount =" + HMCount );
LOGGER.debug( "GTCount ={}", GTCount );
LOGGER.debug( "HMCount ={}", HMCount );
}
Scatter scatter = new Scatter( points, colors );
scatter.setWidth( 2 );
......
......@@ -87,7 +87,7 @@ public class OSEDisplay extends AbstractAnalysis
}
Coord3d[] points = new Coord3d[ count ];
Color[] colors = new Color[ count ];
LOGGER.debug( "count : " + count );
LOGGER.debug( "count : {}", count );
Random r = new Random();
r.setSeed( 50 );
......@@ -108,7 +108,7 @@ public class OSEDisplay extends AbstractAnalysis
int z = coordinate.getZ();
if ( z == 6 || z == 7 )
{
LOGGER.debug( osID + " : " + coordinate );
LOGGER.debug( "{} : {}", osID, coordinate );
}
points[ index ] = new Coord3d( x, y, z );
colors[ index ] = Color.BLACK;
......