From 8ee828ba20fc3000d7908b5564c48e6a672a4bcf Mon Sep 17 00:00:00 2001 From: Stephan Preibisch Date: Mon, 5 Apr 2021 15:18:03 -0400 Subject: [PATCH 01/12] changed code to take a RandomAccessible and an Interval to be able to compute it on large images in true blocks --- .../batch/processing/BatchProcessing.java | 6 ++- src/main/java/cmd/RadialSymmetry.java | 7 ++- src/main/java/compute/RadialSymmetry.java | 49 +++++++++++-------- src/main/java/gui/Radial_Symmetry.java | 29 ++++++----- .../java/gui/interactive/HelperFunctions.java | 12 +++-- src/main/java/intensity/Intensity.java | 7 +-- .../SparseObservationGatherer.java | 8 +-- .../radialsymmetry/cluster/BatchProcess.java | 6 ++- 8 files changed, 78 insertions(+), 46 deletions(-) diff --git a/src/main/java/batch/processing/BatchProcessing.java b/src/main/java/batch/processing/BatchProcessing.java index 4955bf4e..2a41448a 100644 --- a/src/main/java/batch/processing/BatchProcessing.java +++ b/src/main/java/batch/processing/BatchProcessing.java @@ -22,6 +22,7 @@ import milkyklim.algorithm.localization.LevenbergMarquardtSolver; import milkyklim.algorithm.localization.MLEllipticGaussianEstimator; import milkyklim.algorithm.localization.PeakFitter; +import net.imglib2.FinalInterval; import net.imglib2.Localizable; import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealRandomAccess; @@ -90,7 +91,10 @@ public static ArrayList processImage(ImagePlus imp, RandomAccessibleInterv int numDimensions = dim.length; - RadialSymmetry rs = new RadialSymmetry(rai, rsm); + RadialSymmetry rs = new RadialSymmetry( + Views.extendMirrorSingle( rai ), + new FinalInterval( rai ), + rsm); rs.compute(); // TODO: Check if this part is redundant diff --git a/src/main/java/cmd/RadialSymmetry.java b/src/main/java/cmd/RadialSymmetry.java index fd9bab75..0cd12600 100644 --- a/src/main/java/cmd/RadialSymmetry.java +++ b/src/main/java/cmd/RadialSymmetry.java @@ -12,9 +12,11 @@ import gui.interactive.HelperFunctions; import ij.ImageJ; import ij.ImagePlus; +import net.imglib2.FinalInterval; import net.imglib2.RandomAccessibleInterval; import net.imglib2.img.display.imagej.ImageJFunctions; import net.imglib2.img.imageplus.ImagePlusImgs; +import net.imglib2.view.Views; import parameters.RadialSymParams; import picocli.CommandLine; import picocli.CommandLine.Option; @@ -164,7 +166,10 @@ public Void call() throws Exception { img = ImagePlusImgs.from( new ImagePlus( image ) ); HelperFunctions.headless = true; - Radial_Symmetry.runRSFISH(img, params ); + Radial_Symmetry.runRSFISH( + Views.extendMirrorSingle( img ), + new FinalInterval( img ), + params ); System.out.println( "done."); } diff --git a/src/main/java/compute/RadialSymmetry.java b/src/main/java/compute/RadialSymmetry.java index fde7c437..1506b291 100644 --- a/src/main/java/compute/RadialSymmetry.java +++ b/src/main/java/compute/RadialSymmetry.java @@ -10,12 +10,15 @@ import fitting.Center.CenterMethod; import fitting.Spot; import gradient.Gradient; +import gradient.GradientOnDemand; import gradient.GradientPreCompute; import gui.interactive.HelperFunctions; import ij.IJ; import intensity.Intensity; +import net.imglib2.Interval; import net.imglib2.KDTree; import net.imglib2.Point; +import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; import net.imglib2.algorithm.dog.DogDetection; import net.imglib2.neighborsearch.RadiusNeighborSearch; @@ -37,34 +40,37 @@ public enum Ransac { NONE, SIMPLE, MULTICONSENSU }; Gradient derivative; NormalizedGradient ng; - RandomAccessibleInterval img; - RadialSymParams params; + final RandomAccessible img; + final RadialSymParams params; + final Interval interval; // set all parameters in the constructor - public RadialSymmetry(final RandomAccessibleInterval img, final RadialSymParams params) { + public RadialSymmetry(final RandomAccessible img, final Interval interval, final RadialSymParams params) { this.img = img; this.params = params; + this.interval = interval; } public void compute() { - compute(this,img, params); + compute(this,img, interval, params); } public static void compute( final RadialSymmetry rs, - final RandomAccessibleInterval pImg, + final RandomAccessible pImg, + final Interval interval, final RadialSymParams p ) { // perform DOG HelperFunctions.log( "Computing DoG..." ); - rs.peaks = computeDog(pImg, p.sigma, p.threshold, p.anisotropyCoefficient, p.useAnisotropyForDoG ); + rs.peaks = computeDog(pImg, interval, p.sigma, p.threshold, p.anisotropyCoefficient, p.useAnisotropyForDoG ); HelperFunctions.log("DoG pre-detected spots: " + rs.peaks.size() );//+ ", " + numIterations + ", " + pMaxError ); // calculate (normalized) derivatives - rs.derivative = new GradientPreCompute(pImg); + rs.derivative = new GradientOnDemand(pImg); rs.ng = calculateNormalizedGradient(rs.derivative, RadialSymParams.bsMethods[ p.bsMethod ], p.bsMaxError, p.bsInlierRatio); // CODE FOR DEBUGGING DoG OUTPUT @@ -84,7 +90,7 @@ public static void compute( HelperFunctions.log( "Computing Radial Symmetry..." ); rs.spots = computeRadialSymmetry( - pImg, + interval, rs.ng, rs.derivative, rs.peaks, @@ -187,7 +193,7 @@ public static void filterDoubleDetections( final ArrayList< Spot > spots, final System.out.println( "Removed " + countRemoved + " points." ); } - public static ArrayList computeDog(final RandomAccessibleInterval pImg, float pSigma, + public static ArrayList computeDog(final RandomAccessible pImg, final Interval interval, float pSigma, float pThreshold, final double anisotropy, final boolean useAnisotropy ) { float pSigma2 = HelperFunctions.computeSigma2(pSigma, RadialSymParams.defaultSensitivity); @@ -198,23 +204,23 @@ public static ArrayList computeDog(final RandomAccessibleInterval dog2 = new DogDetection<>(pImg, calibration, pSigma, pSigma2, + final DogDetection dog2 = new DogDetection<>(pImg, interval, calibration, pSigma, pSigma2, DogDetection.ExtremaType.MINIMA, pThreshold, false); return dog2.getPeaks(); } - public static ArrayList computeRadialSymmetry(final RandomAccessibleInterval pImg, NormalizedGradient pNg, + public static ArrayList computeRadialSymmetry(final Interval interval, NormalizedGradient pNg, Gradient pDerivative, ArrayList peaks, int[] pSupportRadius, float pInlierRatio, float pMaxError, float pAnisotropy, Ransac ransac, final int minNumInliers, final double nTimesStDev1, final double nTimesStDev2 ) { - int numDimensions = pImg.numDimensions(); + int numDimensions = interval.numDimensions(); // the size of the RANSAC area final long[] range = new long[numDimensions]; for (int d = 0; d < numDimensions; ++d) range[d] = pSupportRadius[d]*2; - ArrayList pSpots = Spot.extractSpotsPoints(pImg, peaks, pDerivative, pNg, range); + ArrayList pSpots = Spot.extractSpotsPoints(interval, peaks, pDerivative, pNg, range); // scale the z-component according to the anisotropy coefficient if (numDimensions == 3) @@ -232,7 +238,7 @@ public static ArrayList computeRadialSymmetry(final RandomAccessibleInterv ransac == Ransac.MULTICONSENSU, nTimesStDev1, nTimesStDev2, - pImg, + interval, pDerivative, pNg, range ); @@ -278,25 +284,26 @@ else if (pBsMethod.equals("RANSAC on Median")) // process each 2D/3D slice of the image to search for the spots public static void process( - RandomAccessibleInterval img, - RandomAccessibleInterval rai, + RandomAccessible img, + RandomAccessible rai, + final Interval interval, RadialSymParams rsm, int[] impDim, ArrayList allSpots, ArrayList timePoint, ArrayList channelPoint) { - RandomAccessibleInterval timeFrameNormalized; - RandomAccessibleInterval timeFrame; + RandomAccessible timeFrameNormalized; + RandomAccessible timeFrame; // impDim <- x y c z t for (int c = 0; c < impDim[2]; c++) { for (int t = 0; t < impDim[4]; t++) { // grab xy(z) part of the image - timeFrameNormalized = HelperFunctions.copyImg(rai, c, t, impDim); - timeFrame = HelperFunctions.copyImg(img, c, t, impDim); + timeFrameNormalized = HelperFunctions.reduceImg(rai, c, t, impDim); + timeFrame = HelperFunctions.reduceImg(img, c, t, impDim); // TODO: finish double-points - RadialSymmetry rs = new RadialSymmetry(timeFrameNormalized, rsm); + RadialSymmetry rs = new RadialSymmetry(timeFrameNormalized, interval, rsm); rs.compute(); int minNumInliers = 1; diff --git a/src/main/java/gui/Radial_Symmetry.java b/src/main/java/gui/Radial_Symmetry.java index f126284c..1bfac7ca 100644 --- a/src/main/java/gui/Radial_Symmetry.java +++ b/src/main/java/gui/Radial_Symmetry.java @@ -22,6 +22,9 @@ import ij.plugin.frame.RoiManager; import imglib2.RealTypeNormalization; import imglib2.TypeTransformingRandomAccessibleInterval; +import net.imglib2.FinalInterval; +import net.imglib2.Interval; +import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; import net.imglib2.converter.Converters; import net.imglib2.img.Img; @@ -30,6 +33,7 @@ import net.imglib2.multithreading.SimpleMultiThreading; import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.real.FloatType; +import net.imglib2.view.Views; import parameters.RadialSymParams; import result.output.ShowResult; @@ -203,7 +207,8 @@ public void run(String arg) { int[] impDim = imp.getDimensions(); // x y c z t ResultsTable rt = runRSFISH( - img, + Views.extendMirrorSingle( img ), + new FinalInterval( img ), params, mode, imp, @@ -213,7 +218,8 @@ public void run(String arg) { } public static < T extends RealType< T > > ResultsTable runRSFISH( - final RandomAccessibleInterval< T > img, + final RandomAccessible< T > img, + final Interval interval, final RadialSymParams params ) { if ( img.numDimensions() < 2 || img.numDimensions() > 3 ) @@ -221,17 +227,18 @@ public static < T extends RealType< T > > ResultsTable runRSFISH( final int[] impDim = new int[ 5 ]; // x y c z t - impDim[ 0 ] = (int)img.dimension( 0 ); - impDim[ 1 ] = (int)img.dimension( 1 ); + impDim[ 0 ] = (int)interval.dimension( 0 ); + impDim[ 1 ] = (int)interval.dimension( 1 ); impDim[ 2 ] = 1; - impDim[ 3 ] = img.numDimensions() > 2 ? (int)img.dimension( 2 ) : 1; + impDim[ 3 ] = interval.numDimensions() > 2 ? (int)interval.dimension( 2 ) : 1; impDim[ 4 ] = 1; - return runRSFISH( img, params, 1, null, impDim); + return runRSFISH( img, interval, params, 1, null, impDim); } public static < T extends RealType< T > > ResultsTable runRSFISH( - final RandomAccessibleInterval< T > img, + final RandomAccessible< T > img, + final Interval interval, final RadialSymParams params, final int mode, final ImagePlus imp, @@ -239,7 +246,7 @@ public static < T extends RealType< T > > ResultsTable runRSFISH( { if ( params.autoMinMax ) { - double[] minmax = HelperFunctions.computeMinMax(img); + double[] minmax = HelperFunctions.computeMinMax( Views.interval( img, interval ) ); if (Double.isNaN( params.min ) ) params.min = (float) minmax[0]; @@ -257,7 +264,7 @@ public static < T extends RealType< T > > ResultsTable runRSFISH( ArrayList channelPoint = new ArrayList<>(0); // un-normalized image for intensity measurement - final RandomAccessibleInterval input = Converters.convert( + final RandomAccessible input = Converters.convert( img, (a, b) -> b.setReal(a.getRealFloat()), new FloatType()); @@ -265,12 +272,12 @@ public static < T extends RealType< T > > ResultsTable runRSFISH( // normalized image for detection final double range = params.max - params.min; - final RandomAccessibleInterval rai = Converters.convert( + final RandomAccessible rai = Converters.convert( img, (a, b) -> b.setReal( ( a.getRealFloat() - params.min ) / range ), new FloatType()); - RadialSymmetry.process(input, rai, params, impDim, allSpots, timePoint, channelPoint); + RadialSymmetry.process(input, rai, interval, params, impDim, allSpots, timePoint, channelPoint); ResultsTable rt = null; diff --git a/src/main/java/gui/interactive/HelperFunctions.java b/src/main/java/gui/interactive/HelperFunctions.java index e260425b..39060089 100644 --- a/src/main/java/gui/interactive/HelperFunctions.java +++ b/src/main/java/gui/interactive/HelperFunctions.java @@ -20,6 +20,7 @@ import net.imglib2.Localizable; import net.imglib2.Point; import net.imglib2.RandomAccess; +import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealLocalizable; import net.imglib2.algorithm.localextrema.RefinedPeak; @@ -47,10 +48,13 @@ public static void log( String s ) IJ.log( s ); } - public static RandomAccessibleInterval copyImg(RandomAccessibleInterval rai, long channel, - long time, int[] impDim) { + public static RandomAccessible reduceImg( + final RandomAccessible rai, + final long channel, + final long time, + final int[] impDim) { - RandomAccessibleInterval img = rai; + RandomAccessible img = rai; // this one is always the loop over 5-dims // cut 5-th, and 3-d and drop them after that int [] mapping = new int[5]; // mapping for all dimensions @@ -67,7 +71,7 @@ public static RandomAccessibleInterval copyImg(RandomAccessibleInterv if (mapping[4] != -1) // if there are timepoints img = Views.hyperSlice(img, mapping[4], time); - return Views.dropSingletonDimensions(img); + return img; } public static double[] calculateMinMax(ImagePlus imp){ diff --git a/src/main/java/intensity/Intensity.java b/src/main/java/intensity/Intensity.java index 1f20a23f..ddb135a7 100644 --- a/src/main/java/intensity/Intensity.java +++ b/src/main/java/intensity/Intensity.java @@ -13,6 +13,7 @@ import milkyklim.algorithm.localization.MLEllipticGaussianEstimator; import milkyklim.algorithm.localization.SparseObservationGatherer; import net.imglib2.Localizable; +import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealRandomAccess; import net.imglib2.RealRandomAccessible; @@ -52,7 +53,7 @@ public int hashCode() { } } - public static void calulateIntesitiesGF(RandomAccessibleInterval xyz, int numDimensions, + public static void calulateIntesitiesGF(RandomAccessible xyz, int numDimensions, double anisotropy, double sigma, ArrayList filteredSpots) { double[] typicalSigmas = new double[numDimensions]; for (int d = 0; d < numDimensions; d++) @@ -85,14 +86,14 @@ public static void calulateIntesitiesGF(RandomAccessibleInterval xyz, } public static void calculateIntensitiesLinear( - RandomAccessibleInterval xyz, + RandomAccessible xyz, ArrayList filteredSpots) { // iterate over all points and perform the linear interpolation for each // of the spots // FIXME: the factory should depend on the imp > floatType, ByteType, // etc. NLinearInterpolatorFactory factory = new NLinearInterpolatorFactory<>(); - RealRandomAccessible interpolant = Views.interpolate(Views.extendBorder(xyz), factory); + RealRandomAccessible interpolant = Views.interpolate(xyz, factory); RealRandomAccess rra = interpolant.realRandomAccess(); for (Spot fSpot : filteredSpots) { rra.setPosition(fSpot); diff --git a/src/main/java/milkyklim/algorithm/localization/SparseObservationGatherer.java b/src/main/java/milkyklim/algorithm/localization/SparseObservationGatherer.java index c6c274c7..6fa5d3ce 100644 --- a/src/main/java/milkyklim/algorithm/localization/SparseObservationGatherer.java +++ b/src/main/java/milkyklim/algorithm/localization/SparseObservationGatherer.java @@ -2,7 +2,7 @@ import fit.PointFunctionMatch; import intensity.Intensity.WrappedSpot; -import net.imglib2.RandomAccessibleInterval; +import net.imglib2.RandomAccessible; import net.imglib2.RealRandomAccess; import net.imglib2.RealRandomAccessible; import net.imglib2.algorithm.localization.Observation; @@ -12,10 +12,10 @@ public class SparseObservationGatherer < T extends RealType< T > > implements ObservationGatherer< WrappedSpot > { - RandomAccessibleInterval img; // initial image + RandomAccessible img; // initial image RealRandomAccessible interpolant; // interpolated image for non-integer intensities - public SparseObservationGatherer(RandomAccessibleInterval< T > img) + public SparseObservationGatherer(RandomAccessible< T > img) { // set the lookup image; necessary to get the intensities // TODO: we need a lookup from peak >> which pixels to use (inliers) @@ -23,7 +23,7 @@ public SparseObservationGatherer(RandomAccessibleInterval< T > img) this.img = img; NLinearInterpolatorFactory factory = new NLinearInterpolatorFactory<>(); - interpolant = Views.interpolate(Views.extendBorder(img), factory); + interpolant = Views.interpolate(img, factory); } @Override diff --git a/src/main/java/process/radialsymmetry/cluster/BatchProcess.java b/src/main/java/process/radialsymmetry/cluster/BatchProcess.java index f020ad71..eb2ac6b2 100644 --- a/src/main/java/process/radialsymmetry/cluster/BatchProcess.java +++ b/src/main/java/process/radialsymmetry/cluster/BatchProcess.java @@ -16,6 +16,7 @@ import ij.gui.Roi; import imglib2.RealTypeNormalization; import imglib2.TypeTransformingRandomAccessibleInterval; +import net.imglib2.FinalInterval; import net.imglib2.RandomAccessibleInterval; import net.imglib2.RealRandomAccess; import net.imglib2.RealRandomAccessible; @@ -338,7 +339,10 @@ public static void process(String imgPath, RadialSymParams params, File outputPa * */ public static ArrayList processImage(Img img, RandomAccessibleInterval rai, RadialSymParams rsm, long[] dims, double sigma, ArrayList intensity) { - RadialSymmetry rs = new RadialSymmetry(rai, rsm); + RadialSymmetry rs = new RadialSymmetry( + Views.extendMirrorSingle( rai ), + new FinalInterval( rai ), + rsm); rs.compute(); // TODO: Check if this part is redundant From 8764e7a8b01a45c143747fdec46d0aeba5226a42 Mon Sep 17 00:00:00 2001 From: Stephan Preibisch Date: Tue, 6 Apr 2021 05:14:44 -0400 Subject: [PATCH 02/12] made parameters serializable --- src/main/java/parameters/RadialSymParams.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/parameters/RadialSymParams.java b/src/main/java/parameters/RadialSymParams.java index ee8eaa35..9ed112ac 100644 --- a/src/main/java/parameters/RadialSymParams.java +++ b/src/main/java/parameters/RadialSymParams.java @@ -1,8 +1,15 @@ package parameters; +import java.io.Serializable; + import compute.RadialSymmetry.Ransac; -public class RadialSymParams { +public class RadialSymParams implements Serializable { + + /** + * + */ + private static final long serialVersionUID = -9045686244206165151L; public static String[] modeChoice = new String[] { "Interactive", "Advanced" }; public static String[] ransacChoice = new String[] { "No RANSAC", "RANSAC", "Multiconsensus RANSAC" }; From 965ea2165aecff988308a555dbe631a2d2299abb Mon Sep 17 00:00:00 2001 From: Stephan Preibisch Date: Tue, 6 Apr 2021 05:15:08 -0400 Subject: [PATCH 03/12] add method that just returns all points (ignores timepoints for now) --- src/main/java/result/output/ShowResult.java | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/main/java/result/output/ShowResult.java b/src/main/java/result/output/ShowResult.java index 5241e41e..09b3d295 100644 --- a/src/main/java/result/output/ShowResult.java +++ b/src/main/java/result/output/ShowResult.java @@ -66,6 +66,37 @@ public static void ransacResultCsv( out.close(); } + public static ArrayList points( final ArrayList spots, double histThreshold) + { + if ( spots == null || spots.size() == 0 ) + { + HelperFunctions.log( "No spots found, nothing to write."); + return null; + } + + ArrayList points = new ArrayList<>(); + + int idx = 0; + for (Spot spot : spots) { + // if spot was not discarded + if (spot.inliers.size() != 0) { // TODO: filtered already? + if (spot.getIntensity() >= histThreshold) { + + idx++; + + final double[] l = new double[ spot.numDimensions() + 1 ]; + for (int d = 0; d < spot.numDimensions(); ++d) + l[ d ] = spot.getDoublePosition(d); + l[ spot.numDimensions() ] = spot.getIntensity(); + + } + } + } + HelperFunctions.log("Spots found = " + idx); + + return points; + } + // ineractive mode // this function will show the result of RANSAC // proper window -> dialog view with the columns From d558c1be50c8d2fd0f2d7932351cd868faa5910f Mon Sep 17 00:00:00 2001 From: Stephan Preibisch Date: Tue, 6 Apr 2021 05:15:37 -0400 Subject: [PATCH 04/12] fix return type --- src/main/java/gui/Radial_Symmetry.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/gui/Radial_Symmetry.java b/src/main/java/gui/Radial_Symmetry.java index 1bfac7ca..8a043019 100644 --- a/src/main/java/gui/Radial_Symmetry.java +++ b/src/main/java/gui/Radial_Symmetry.java @@ -206,18 +206,16 @@ public void run(String arg) { int[] impDim = imp.getDimensions(); // x y c z t - ResultsTable rt = runRSFISH( + runRSFISH( Views.extendMirrorSingle( img ), new FinalInterval( img ), params, mode, imp, impDim ); - - rt.show( "smFISH localizations"); } - public static < T extends RealType< T > > ResultsTable runRSFISH( + public static < T extends RealType< T > > ArrayList runRSFISH( final RandomAccessible< T > img, final Interval interval, final RadialSymParams params ) @@ -236,7 +234,7 @@ public static < T extends RealType< T > > ResultsTable runRSFISH( return runRSFISH( img, interval, params, 1, null, impDim); } - public static < T extends RealType< T > > ResultsTable runRSFISH( + public static < T extends RealType< T > > ArrayList runRSFISH( final RandomAccessible< T > img, final Interval interval, final RadialSymParams params, @@ -295,11 +293,11 @@ public static < T extends RealType< T > > ResultsTable runRSFISH( else if ( mode == 1 ) { // advanced // write the result to the csv file HelperFunctions.log( "Intensity threshold = " + params.intensityThreshold ); - if ( HelperFunctions.headless ) + if ( HelperFunctions.headless && params.resultsFilePath.length() > 0 ) ShowResult.ransacResultCsv(allSpots, timePoint, channelPoint, params.intensityThreshold, params.resultsFilePath ); - else - rt = ShowResult.ransacResultTable(allSpots, timePoint, channelPoint, params.intensityThreshold ); + if ( !HelperFunctions.headless ) + rt = ShowResult.ransacResultTable(allSpots, timePoint, channelPoint, params.intensityThreshold ); } else { @@ -308,6 +306,8 @@ else if ( mode == 1 ) { // advanced if ( !HelperFunctions.headless ) { + rt.show( "smFISH localizations"); + if ( params.resultsFilePath.length() > 0 ) { System.out.println("Writing CSV: " + params.resultsFilePath); @@ -334,7 +334,7 @@ else if ( mode == 1 ) { // advanced } } - return rt; + return ShowResult.points(allSpots, params.intensityThreshold ); } public static void main(String[] args) { From f710d26cd27c0e131c7d7484e067834e39e6a24f Mon Sep 17 00:00:00 2001 From: Stephan Preibisch Date: Tue, 6 Apr 2021 05:44:06 -0400 Subject: [PATCH 05/12] remove ImageJ2 dependency as it messes with Spark --- pom.xml | 4 -- src/main/java/cmd/Anisotropy.java | 16 +++-- src/main/java/gui/Anisotropy_Plugin.java | 64 +++++++++++++------ .../gui/anisotropy/AnisotropyCoefficient.java | 11 ++-- src/main/resources/plugins.config | 3 +- 5 files changed, 62 insertions(+), 36 deletions(-) diff --git a/pom.xml b/pom.xml index 6371e332..619f0533 100644 --- a/pom.xml +++ b/pom.xml @@ -114,10 +114,6 @@ org.apache.commons commons-math3 - - net.imagej - imagej - net.imagej ij diff --git a/src/main/java/cmd/Anisotropy.java b/src/main/java/cmd/Anisotropy.java index eda20ea5..139c3051 100644 --- a/src/main/java/cmd/Anisotropy.java +++ b/src/main/java/cmd/Anisotropy.java @@ -3,6 +3,7 @@ import java.util.concurrent.Callable; import gui.Anisotropy_Plugin; +import ij.ImageJ; import ij.ImagePlus; import net.imagej.patcher.LegacyInjector; import picocli.CommandLine; @@ -10,8 +11,6 @@ public class Anisotropy implements Callable { - static { LegacyInjector.preinit(); } - // input file @Option(names = {"-i", "--image"}, required = true, description = "input image or N5 container path (requires additional -d for N5), e.g. -i /home/smFish.tif or /home/smFish.n5") private String image = null; @@ -30,10 +29,15 @@ public Void call() throws Exception return null; } - final net.imagej.ImageJ ij = new net.imagej.ImageJ(); - ij.ui().showUI(); - ij.ui().show(imp); - ij.command().run(Anisotropy_Plugin.class, true); + new ImageJ(); + + if ( imp.getStackSize() > 1 ) + imp.setSlice( imp.getStackSize() / 2 ); + + imp.resetDisplayRange(); + imp.show(); + + new Anisotropy_Plugin().run( null ); return null; } diff --git a/src/main/java/gui/Anisotropy_Plugin.java b/src/main/java/gui/Anisotropy_Plugin.java index c06caf49..66c1b01a 100644 --- a/src/main/java/gui/Anisotropy_Plugin.java +++ b/src/main/java/gui/Anisotropy_Plugin.java @@ -1,35 +1,59 @@ package gui; -import org.scijava.ItemVisibility; -import org.scijava.command.Command; -import org.scijava.log.LogService; -import org.scijava.plugin.Parameter; -import org.scijava.plugin.Plugin; +import java.util.Arrays; import anisotropy.parameters.AParams; import gui.anisotropy.AnisotropyCoefficient; import gui.interactive.HelperFunctions; +import ij.IJ; +import ij.ImageJ; import ij.ImagePlus; +import ij.WindowManager; +import ij.gui.GenericDialog; +import ij.plugin.PlugIn; import parameters.RadialSymParams; -@Plugin(type = Command.class, menuPath = "Plugins>RS-FISH>Tools>Calculate Anisotropy Coefficient") -public class Anisotropy_Plugin implements Command { +public class Anisotropy_Plugin implements PlugIn { public static String[] paramChoice = new String[] { "Gauss Fit", "Radial Symmetry" }; public static int defaultParam = 0; public static int defaultImg = 0; - @Parameter(autoFill=false, label="Image") - ImagePlus imagePlus; + @Override + public void run( String arg ) { - @Parameter(choices={ "Gauss Fit", "Radial Symmetry" }, label="Detection method") - String paramType = paramChoice[defaultParam]; - - @Parameter(visibility=ItemVisibility.INVISIBLE) - LogService logService; - @Override - public void run() { + // get list of open image stacks + final int[] idList = WindowManager.getIDList(); + + if ( idList == null || idList.length == 0 ) + { + IJ.error( "You need at least one open image." ); + return; + } + + // map all id's to image title for those who are 3d stacks + final String[] imgList = + Arrays.stream( idList ). + mapToObj( id -> WindowManager.getImage( id ).getTitle() ). + toArray( String[]::new ); + + if ( RadialSymParams.defaultImg >= imgList.length ) + RadialSymParams.defaultImg = 0; + + GenericDialog gd = new GenericDialog("Anisotropy"); + + gd.addChoice( "Image", imgList, imgList[ RadialSymParams.defaultImg ] ); + gd.addChoice( "Detection Mode", paramChoice, paramChoice[ defaultParam ] ); + + gd.showDialog(); + + if ( gd.wasCanceled() ) + return; + + // don't do it by name as often multiple images have the same name + ImagePlus imagePlus = WindowManager.getImage( idList[ RadialSymParams.defaultImg = gd.getNextChoiceIndex() ] ); + int mode = RadialSymParams.defaultMode = gd.getNextChoiceIndex(); if ( imagePlus.getNFrames() > 1 ) { @@ -52,7 +76,7 @@ public void run() { float bestScale = 1.0f; AParams ap = new AParams(); double [] minmax = HelperFunctions.calculateMinMax(imagePlus); - AnisotropyCoefficient ac = new AnisotropyCoefficient(imagePlus, ap, paramType, minmax[0], minmax[1]); + AnisotropyCoefficient ac = new AnisotropyCoefficient(imagePlus, ap, mode, minmax[0], minmax[1]); if ( ac.wasCanceled() ) return; bestScale = (float) ac.calculateAnisotropyCoefficient(); @@ -67,11 +91,13 @@ public void run() { public static void main(String[] args) { - net.imagej.ImageJ ij = new net.imagej.ImageJ(); + new ImageJ(); //ij.launch( "/Users/spreibi/Documents/BIMSB/Publications/radialsymmetry/Poiss_300spots_bg_200_0_I_10000_0_img0.tif" ); //ij.launch( "/Users/spreibi/Documents/BIMSB/Publications/radialsymmetry/N2_702_cropped_1620 (high SNR)_ch0.tif" ); //ij.launch( "/Users/spreibi/Downloads/in_situ_HCR_tekt2_514_otogl_488_itln_546_spdf_647_zoom_2_no_DAPI_stage_13_embryo_1_cell_1.tif" ); - ij.command().run(Anisotropy_Plugin.class, true); + + new ImagePlus( "/Users/spreibi/Documents/BIMSB/Publications/radialsymmetry/N2_702_cropped_1620 (high SNR)_ch0.tif" ).show(); + new Anisotropy_Plugin().run( null ); // for the historical reasons System.out.println("DOGE!"); diff --git a/src/main/java/gui/anisotropy/AnisotropyCoefficient.java b/src/main/java/gui/anisotropy/AnisotropyCoefficient.java index f83f136f..18d77329 100644 --- a/src/main/java/gui/anisotropy/AnisotropyCoefficient.java +++ b/src/main/java/gui/anisotropy/AnisotropyCoefficient.java @@ -18,7 +18,6 @@ import gradient.GradientPreCompute; import gui.interactive.HelperFunctions; import gui.interactive.InteractiveRadialSymmetry; -import ij.IJ; import ij.ImageJ; import ij.ImagePlus; import ij.gui.Roi; @@ -70,7 +69,7 @@ public class AnisotropyCoefficient { final int type; Rectangle rectangle; - final String paramType; // defines which method will be used: gaussfit or radial symmetry + final int mode; // defines which method will be used: gaussfit or radial symmetry ArrayList> peaks; @@ -108,9 +107,9 @@ public boolean wasCanceled() { } // paramType defines if we use RS or Gaussian Fit - public AnisotropyCoefficient(ImagePlus imp, final AParams params, final String paramType, final double min, final double max){ + public AnisotropyCoefficient(ImagePlus imp, final AParams params, final int mode, final double min, final double max){ this.imagePlus = imp; - this.paramType = paramType; + this.mode = mode; dim = new long[] { imp.getWidth(), imp.getHeight() }; @@ -240,7 +239,7 @@ public double calculateAnisotropyCoefficient(){ HelperFunctions.log("Found " + peaks.size() + " peaks in the 3D substack defined by the ROI." ); - if (paramType.equals("Gauss Fit")) // gauss fit + if ( mode == 0 ) // gauss fit bestScale = calculateAnisotropyCoefficientGF(img, threshold, sigma); else bestScale = calculateAnisotropyCoefficientRS(img, threshold, sigma); @@ -613,7 +612,7 @@ public static void main(String[] args) // imp.setRoi(imp.getWidth() / 4, imp.getHeight() / 4, imp.getWidth() / 2, imp.getHeight() / 2); - new AnisotropyCoefficient( imp, new AParams(), "Gauss fit", min, max ); + new AnisotropyCoefficient( imp, new AParams(), 0, min, max ); System.out.println("DOGE!"); } diff --git a/src/main/resources/plugins.config b/src/main/resources/plugins.config index 463fc769..617a8097 100755 --- a/src/main/resources/plugins.config +++ b/src/main/resources/plugins.config @@ -1 +1,2 @@ -Plugins>RS-FISH, "RS-FISH", gui.Radial_Symmetry \ No newline at end of file +Plugins>RS-FISH, "RS-FISH", gui.Radial_Symmetry +Plugins>RS-FISH>Tools, "Calculate Anisotropy Coefficient", gui.Anisotropy_Plugin \ No newline at end of file From 2fb56f3cea899f061d749f214fc77e11974bcf14 Mon Sep 17 00:00:00 2001 From: Stephan Preibisch Date: Tue, 6 Apr 2021 05:49:19 -0400 Subject: [PATCH 06/12] fix java compiler issue --- src/main/java/cmd/RadialSymmetry.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/cmd/RadialSymmetry.java b/src/main/java/cmd/RadialSymmetry.java index 0cd12600..d5097756 100644 --- a/src/main/java/cmd/RadialSymmetry.java +++ b/src/main/java/cmd/RadialSymmetry.java @@ -13,6 +13,7 @@ import ij.ImageJ; import ij.ImagePlus; import net.imglib2.FinalInterval; +import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; import net.imglib2.img.display.imagej.ImageJFunctions; import net.imglib2.img.imageplus.ImagePlusImgs; @@ -167,7 +168,7 @@ public Void call() throws Exception { HelperFunctions.headless = true; Radial_Symmetry.runRSFISH( - Views.extendMirrorSingle( img ), + (RandomAccessible)(Object)Views.extendMirrorSingle( img ), new FinalInterval( img ), params ); From 44628d30f0e55fcdee5bc2d0f6ba185279343821 Mon Sep 17 00:00:00 2001 From: Stephan Preibisch Date: Tue, 6 Apr 2021 05:50:38 -0400 Subject: [PATCH 07/12] remove imagej-legacy dependency --- pom.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pom.xml b/pom.xml index 619f0533..80653201 100644 --- a/pom.xml +++ b/pom.xml @@ -118,10 +118,6 @@ net.imagej ij - - net.imagej - imagej-legacy - From f0e29d028bf567d8f75b13f81ee7c9c15401adfe Mon Sep 17 00:00:00 2001 From: Stephan Preibisch Date: Tue, 6 Apr 2021 06:22:37 -0400 Subject: [PATCH 08/12] remove RANSAC enum from parameter choice --- .../java/batch/processing/BatchProcessing.java | 2 +- src/main/java/cmd/RadialSymmetry.java | 2 +- src/main/java/compute/RadialSymmetry.java | 4 ++-- src/main/java/gui/Radial_Symmetry.java | 4 ++-- src/main/java/parameters/RadialSymParams.java | 18 +++++++----------- .../radialsymmetry/cluster/BatchProcess.java | 6 +++--- 6 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/main/java/batch/processing/BatchProcessing.java b/src/main/java/batch/processing/BatchProcessing.java index 2a41448a..2269be5a 100644 --- a/src/main/java/batch/processing/BatchProcessing.java +++ b/src/main/java/batch/processing/BatchProcessing.java @@ -183,7 +183,7 @@ public static void main(String[] args) { final RadialSymParams params = new RadialSymParams(); // apparently the best value for now params.setAnisotropyCoefficient(1.09f); - params.setRANSAC(Ransac.SIMPLE); + params.setRANSAC(Ransac.SIMPLE.ordinal()); // pre-detection params.setSigmaDog(1.50f); params.setThresholdDog(0.0083f); diff --git a/src/main/java/cmd/RadialSymmetry.java b/src/main/java/cmd/RadialSymmetry.java index d5097756..c66da542 100644 --- a/src/main/java/cmd/RadialSymmetry.java +++ b/src/main/java/cmd/RadialSymmetry.java @@ -100,7 +100,7 @@ public Void call() throws Exception { RadialSymParams.defaultAnisotropy = params.anisotropyCoefficient = anisotropy; RadialSymParams.defaultUseAnisotropyForDoG = params.useAnisotropyForDoG = true; RadialSymParams.defaultRANSACChoice = ransac; - params.RANSAC = Ransac.values()[ ransac ]; //"No RANSAC", "RANSAC", "Multiconsensus RANSAC" + params.ransacSelection = ransac; //"No RANSAC", "RANSAC", "Multiconsensus RANSAC" params.min = minIntensity; params.max = maxIntensity; diff --git a/src/main/java/compute/RadialSymmetry.java b/src/main/java/compute/RadialSymmetry.java index 1506b291..6b6b5a1a 100644 --- a/src/main/java/compute/RadialSymmetry.java +++ b/src/main/java/compute/RadialSymmetry.java @@ -98,7 +98,7 @@ public static void compute( p.inlierRatio, p.maxError, (float)p.anisotropyCoefficient, - p.RANSAC, + p.RANSAC(), p.minNumInliers, p.nTimesStDev1, p.nTimesStDev2 ); @@ -134,7 +134,7 @@ public static void compute( SimpleMultiThreading.threadHaltUnClean(); */ - if ( p.RANSAC.ordinal() > 0 ) + if ( p.RANSAC().ordinal() > 0 ) { for ( int i = rs.spots.size() - 1; i >= 0; --i ) if ( rs.spots.get( i ).inliers.size() == 0 ) diff --git a/src/main/java/gui/Radial_Symmetry.java b/src/main/java/gui/Radial_Symmetry.java index 8a043019..f3e33db5 100644 --- a/src/main/java/gui/Radial_Symmetry.java +++ b/src/main/java/gui/Radial_Symmetry.java @@ -88,7 +88,7 @@ public void run(String arg) { ImagePlus imp = WindowManager.getImage( idList[ RadialSymParams.defaultImg = gd1.getNextChoiceIndex() ] ); int mode = RadialSymParams.defaultMode = gd1.getNextChoiceIndex(); params.anisotropyCoefficient = RadialSymParams.defaultAnisotropy = gd1.getNextNumber(); - params.RANSAC = Ransac.values()[ RadialSymParams.defaultRANSACChoice = gd1.getNextChoiceIndex() ]; + params.ransacSelection = RadialSymParams.defaultRANSACChoice = gd1.getNextChoiceIndex(); params.autoMinMax = RadialSymParams.defaultAutoMinMax = gd1.getNextBoolean(); params.useAnisotropyForDoG = RadialSymParams.defaultUseAnisotropyForDoG = gd1.getNextBoolean(); @@ -102,7 +102,7 @@ public void run(String arg) { return; } - if ( params.RANSAC.ordinal() == 2 ) // Multiconsensus RANSAC + if ( params.RANSAC().ordinal() == 2 ) // Multiconsensus RANSAC { GenericDialogPlus gd2 = new GenericDialogPlus( "Multiconsensus RANSAC Options" ); gd2.addNumericField( "Min_number_of_inliers", RadialSymParams.defaultMinNumInliers, 0 ); diff --git a/src/main/java/parameters/RadialSymParams.java b/src/main/java/parameters/RadialSymParams.java index 9ed112ac..21a3112b 100644 --- a/src/main/java/parameters/RadialSymParams.java +++ b/src/main/java/parameters/RadialSymParams.java @@ -59,7 +59,8 @@ public class RadialSymParams implements Serializable { // RANSAC parameters // current value - public Ransac RANSAC = Ransac.values()[ defaultRANSACChoice ]; + public Ransac RANSAC() { return Ransac.values()[ ransacSelection ]; } + public int ransacSelection = defaultRANSACChoice; public float maxError = defaultMaxError, inlierRatio = defaultInlierRatio; public int supportRadius = defaultSupportRadius; @@ -95,7 +96,7 @@ public class RadialSymParams implements Serializable { public void printParams() { System.out.println("SigmaDoG : " + sigma); System.out.println("ThresholdDoG : " + threshold); - System.out.println("RANSAC : " + RANSAC ); + System.out.println("RANSAC : " + RANSAC() ); System.out.println("MaxError : " + maxError); System.out.println("InlierRatio : " + inlierRatio); System.out.println("supportRadius : " + supportRadius); @@ -124,11 +125,11 @@ public float getThresholdDoG() { // RANSAC public Ransac getRANSAC() { - return RANSAC; + return RANSAC(); } public int getRANSACIndex() { - return RANSAC.ordinal(); + return RANSAC().ordinal(); } public float getMaxError() { @@ -173,7 +174,7 @@ public void setDefaultValuesFromInteractive() { defaultSigma = sigma; defaultThreshold = threshold; - defaultRANSACChoice = RANSAC.ordinal(); + defaultRANSACChoice = RANSAC().ordinal(); defaultMaxError = maxError; defaultInlierRatio = inlierRatio; defaultSupportRadius = supportRadius; @@ -194,13 +195,8 @@ public void setThresholdDog(float threshold) { this.threshold = threshold; } - // RANSAC - public void setRANSAC(Ransac ransac) { - this.RANSAC = ransac; - } - public void setRANSAC(int ransacChoice) { - this.RANSAC = Ransac.values()[ ransacChoice ]; + this.ransacSelection = ransacChoice; } public void setMaxError(float maxError) { diff --git a/src/main/java/process/radialsymmetry/cluster/BatchProcess.java b/src/main/java/process/radialsymmetry/cluster/BatchProcess.java index eb2ac6b2..c76b3517 100644 --- a/src/main/java/process/radialsymmetry/cluster/BatchProcess.java +++ b/src/main/java/process/radialsymmetry/cluster/BatchProcess.java @@ -37,7 +37,7 @@ public static RadialSymParams setParametersN2Second(int lambda) { // same for all lambda values params.setAnisotropyCoefficient(1.08f); - params.setRANSAC(Ransac.SIMPLE); + params.setRANSAC(Ransac.SIMPLE.ordinal()); // FIXME: Check that the values for the params are correct // Larger support radius smaller number of inliers @@ -91,7 +91,7 @@ public static RadialSymParams setParameters(int lambda) { // same for all lambda values params.setAnisotropyCoefficient(1.08f); - params.setRANSAC(Ransac.SIMPLE); + params.setRANSAC(Ransac.SIMPLE.ordinal()); // FIXME: Check that the values for the params are correct // Larger support radius smaller number of inliers @@ -145,7 +145,7 @@ public static RadialSymParams setParameters2(int lambda) { // same for all lambda values params.setAnisotropyCoefficient(1.08f); - params.setRANSAC(Ransac.SIMPLE); + params.setRANSAC(Ransac.SIMPLE.ordinal()); // FIXME: Check that the values for the params are correct // Larger support radius smaller number of inliers From b6de8e177c3a5c2ed4b59964accdb69361a5da7c Mon Sep 17 00:00:00 2001 From: Stephan Preibisch Date: Tue, 6 Apr 2021 09:16:02 -0400 Subject: [PATCH 09/12] fixed import bug --- src/main/java/radial/symmetry/utils/IOUtils.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/radial/symmetry/utils/IOUtils.java b/src/main/java/radial/symmetry/utils/IOUtils.java index a60f76b1..5da107a3 100644 --- a/src/main/java/radial/symmetry/utils/IOUtils.java +++ b/src/main/java/radial/symmetry/utils/IOUtils.java @@ -38,15 +38,17 @@ public static ArrayList readPositionsFromCSV(File filepath){ while ((nextLine = reader.readNext()) != null) { ++i; double [] pos = new double[numDimensions]; + boolean failed = false; for (int d = 0; d < numDimensions; d++) { try { pos[d] = Double.parseDouble(nextLine[d]); } - catch (Exception e ) { HelperFunctions.log( "no entries in line: " + i ); break; } + catch (Exception e ) { failed = true; HelperFunctions.log( "no entries in line: " + i ); break; } } - peaks.add(new RealPoint(pos)); + if ( !failed ) + peaks.add(new RealPoint(pos)); } reader.close(); HelperFunctions.log( "read " + peaks.size() + " spots." ); From 360f04b0431ba17bdd2a3b70d28089dc9076353c Mon Sep 17 00:00:00 2001 From: Stephan Preibisch Date: Tue, 6 Apr 2021 09:16:58 -0400 Subject: [PATCH 10/12] fix double-filtering --- src/main/java/result/output/ShowResult.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/main/java/result/output/ShowResult.java b/src/main/java/result/output/ShowResult.java index 09b3d295..abbf4b71 100644 --- a/src/main/java/result/output/ShowResult.java +++ b/src/main/java/result/output/ShowResult.java @@ -35,7 +35,6 @@ public static void ransacResultCsv( int idx = 0; for (Spot spot : spots) { // if spot was not discarded - if (spot.inliers.size() != 0) { // TODO: filtered already? if (spot.getIntensity() >= histThreshold) { idx++; @@ -60,7 +59,6 @@ public static void ransacResultCsv( out.println(String.format(java.util.Locale.US, "%.4f", spot.getIntensity())); } - } } HelperFunctions.log("Spots found = " + idx); out.close(); @@ -71,28 +69,24 @@ public static ArrayList points( final ArrayList spots, double hi if ( spots == null || spots.size() == 0 ) { HelperFunctions.log( "No spots found, nothing to write."); - return null; + return new ArrayList<>(); } ArrayList points = new ArrayList<>(); - int idx = 0; for (Spot spot : spots) { // if spot was not discarded - if (spot.inliers.size() != 0) { // TODO: filtered already? if (spot.getIntensity() >= histThreshold) { - idx++; - final double[] l = new double[ spot.numDimensions() + 1 ]; for (int d = 0; d < spot.numDimensions(); ++d) l[ d ] = spot.getDoublePosition(d); l[ spot.numDimensions() ] = spot.getIntensity(); + points.add( l ); } - } } - HelperFunctions.log("Spots found = " + idx); + HelperFunctions.log("Spots found = " + points.size()); return points; } @@ -114,7 +108,6 @@ public static ResultsTable ransacResultTable(final ArrayList spots, final int idx = 0; for (Spot spot : spots) { // if spot was not discarded - if (spot.inliers.size() != 0) { // TODO: filtered already? if (spot.getIntensity() >= histThreshold) { rt.incrementCounter(); for (int d = 0; d < spot.numDimensions(); ++d) { @@ -138,7 +131,6 @@ public static ResultsTable ransacResultTable(final ArrayList spots, final rt.addValue("intensity", String.format(java.util.Locale.US, "%.4f", spot.getIntensity())); } - } idx++; } HelperFunctions.log("Spots found = " + rt.getCounter()); From 73bcfaf5bb9dcc0ae1efd10f08e9adb0c02e7c47 Mon Sep 17 00:00:00 2001 From: Stephan Preibisch Date: Tue, 6 Apr 2021 09:28:39 -0400 Subject: [PATCH 11/12] added globalInterval and computeInterval as we might process in blocks, but only want to cut off gradients at the actual edge of the full input image added numThreads parameter --- .../batch/processing/BatchProcessing.java | 1 + src/main/java/cmd/RadialSymmetry.java | 2 +- src/main/java/compute/RadialSymmetry.java | 83 ++++++++++++++++--- src/main/java/gui/Radial_Symmetry.java | 27 ++++-- src/main/java/parameters/RadialSymParams.java | 3 + .../radialsymmetry/cluster/BatchProcess.java | 1 + 6 files changed, 96 insertions(+), 21 deletions(-) diff --git a/src/main/java/batch/processing/BatchProcessing.java b/src/main/java/batch/processing/BatchProcessing.java index 2269be5a..62c98c7b 100644 --- a/src/main/java/batch/processing/BatchProcessing.java +++ b/src/main/java/batch/processing/BatchProcessing.java @@ -94,6 +94,7 @@ public static ArrayList processImage(ImagePlus imp, RandomAccessibleInterv RadialSymmetry rs = new RadialSymmetry( Views.extendMirrorSingle( rai ), new FinalInterval( rai ), + new FinalInterval( rai ), rsm); rs.compute(); diff --git a/src/main/java/cmd/RadialSymmetry.java b/src/main/java/cmd/RadialSymmetry.java index c66da542..00cb2931 100644 --- a/src/main/java/cmd/RadialSymmetry.java +++ b/src/main/java/cmd/RadialSymmetry.java @@ -7,7 +7,6 @@ import org.janelia.saalfeldlab.n5.N5Reader; import org.janelia.saalfeldlab.n5.imglib2.N5Utils; -import compute.RadialSymmetry.Ransac; import gui.Radial_Symmetry; import gui.interactive.HelperFunctions; import ij.ImageJ; @@ -170,6 +169,7 @@ public Void call() throws Exception { Radial_Symmetry.runRSFISH( (RandomAccessible)(Object)Views.extendMirrorSingle( img ), new FinalInterval( img ), + new FinalInterval( img ), params ); System.out.println( "done."); diff --git a/src/main/java/compute/RadialSymmetry.java b/src/main/java/compute/RadialSymmetry.java index 6b6b5a1a..1ec0c072 100644 --- a/src/main/java/compute/RadialSymmetry.java +++ b/src/main/java/compute/RadialSymmetry.java @@ -9,6 +9,7 @@ import background.NormalizedGradientRANSAC; import fitting.Center.CenterMethod; import fitting.Spot; +import fitting.SymmetryCenter3d; import gradient.Gradient; import gradient.GradientOnDemand; import gradient.GradientPreCompute; @@ -32,7 +33,7 @@ public enum Ransac { NONE, SIMPLE, MULTICONSENSU }; public static int bsNumIterations = 500; // not a parameter, can be changed // through Beanshell - public static int numIterations = 250; // not a parameter, can be changed + public static int numIterations = 500; // not a parameter, can be changed // through Beanshell ArrayList peaks; @@ -42,30 +43,36 @@ public enum Ransac { NONE, SIMPLE, MULTICONSENSU }; final RandomAccessible img; final RadialSymParams params; - final Interval interval; + final Interval globalInterval, computeInterval; // set all parameters in the constructor - public RadialSymmetry(final RandomAccessible img, final Interval interval, final RadialSymParams params) { + public RadialSymmetry( + final RandomAccessible img, + final Interval globalInterval, // we need to know where to cut off gradients at image borders + final Interval computeInterval, + final RadialSymParams params) { this.img = img; this.params = params; - this.interval = interval; + this.globalInterval = globalInterval; + this.computeInterval = computeInterval; } public void compute() { - compute(this,img, interval, params); + compute(this,img, globalInterval, computeInterval, params); } public static void compute( final RadialSymmetry rs, final RandomAccessible pImg, - final Interval interval, + final Interval globalInterval, // we need to know where to cut off gradients at image borders + final Interval computeInterval, final RadialSymParams p ) { // perform DOG HelperFunctions.log( "Computing DoG..." ); - rs.peaks = computeDog(pImg, interval, p.sigma, p.threshold, p.anisotropyCoefficient, p.useAnisotropyForDoG ); + rs.peaks = computeDog(pImg, computeInterval, p.sigma, p.threshold, p.anisotropyCoefficient, p.useAnisotropyForDoG, p.numThreads ); HelperFunctions.log("DoG pre-detected spots: " + rs.peaks.size() );//+ ", " + numIterations + ", " + pMaxError ); @@ -90,7 +97,7 @@ public static void compute( HelperFunctions.log( "Computing Radial Symmetry..." ); rs.spots = computeRadialSymmetry( - interval, + globalInterval, rs.ng, rs.derivative, rs.peaks, @@ -194,7 +201,7 @@ public static void filterDoubleDetections( final ArrayList< Spot > spots, final } public static ArrayList computeDog(final RandomAccessible pImg, final Interval interval, float pSigma, - float pThreshold, final double anisotropy, final boolean useAnisotropy ) { + float pThreshold, final double anisotropy, final boolean useAnisotropy, final int numThreads ) { float pSigma2 = HelperFunctions.computeSigma2(pSigma, RadialSymParams.defaultSensitivity); @@ -207,6 +214,8 @@ public static ArrayList computeDog(final RandomAccessible pImg final DogDetection dog2 = new DogDetection<>(pImg, interval, calibration, pSigma, pSigma2, DogDetection.ExtremaType.MINIMA, pThreshold, false); + dog2.setNumThreads(numThreads); + return dog2.getPeaks(); } @@ -247,13 +256,60 @@ public static ArrayList computeRadialSymmetry(final Interval interval, Nor pSpots.addAll( additionalSpots ); } else + { + /* + for ( final Spot s : pSpots ) + { + final SymmetryCenter3d c = new SymmetryCenter3d(); + c.xc = s.getOriginalLocation()[ 0 ]; + c.yc = s.getOriginalLocation()[ 1 ]; + c.zc = s.getOriginalLocation()[ 2 ]; + + ((SymmetryCenter3d)s.center).set(c); + } + */ + try { Spot.fitCandidates(pSpots); + /* + for ( final Spot spot : pSpots ) + { + //boolean lookAt = false; + //if ( spot.getOriginalLocation()[ 0 ] == 230 && spot.getOriginalLocation()[ 1 ] == 229 && spot.getOriginalLocation()[ 2 ] == 55 ) + // lookAt = true; + + //if ( spot.getOriginalLocation()[ 0 ] == 219 && spot.getOriginalLocation()[ 1 ] == 213 && spot.getOriginalLocation()[ 2 ] == 59 ) + // lookAt = true; + + spot.center.fit( spot.candidates ); + + if ( lookAt ) + { + // SINGLE: original location: (219, 213, 59) localized as (219.09322, 212.95442, 58.740772) + // SPARK: original location: (219, 213, 59) localized as (219.17636, 212.91121, 58.17321) + // spark: when using different block boundaries it localizes right (50, 50, 50) instead of (32, 32, 32) + System.out.println( "original location: " + Util.printCoordinates( spot.getOriginalLocation() ) + " localized as " + Util.printCoordinates( spot )); + //System.exit( 0 ); + } + + // original location: (230, 229, 55) for (229.86337, 228.90987, 54.77498) + // no match for: (229.8634, 228.9099, 54.775), d=0.27821317366364656 + + // original location: (219, 213, 59) for (219.09322, 212.95442, 58.740772) + // no match for: (219.0932, 212.9544, 58.7408), d=0.5752897009333628 + if ( Math.abs( spot.getDoublePosition(2) - 58.7408 ) < 0.0001 ) + { + System.out.println( "original location: " + Util.printCoordinates( spot.getOriginalLocation() ) + " for " + Util.printCoordinates( spot )); + } + }*/ + } catch (Exception e) { e.printStackTrace(); System.out.println("Something went wrong, please report the bug."); } + } + return pSpots; } @@ -286,7 +342,8 @@ else if (pBsMethod.equals("RANSAC on Median")) public static void process( RandomAccessible img, RandomAccessible rai, - final Interval interval, + final Interval globalInterval, // we need to know where to cut off gradients at image borders + final Interval computeInterval, RadialSymParams rsm, int[] impDim, ArrayList allSpots, @@ -303,11 +360,12 @@ public static void process( timeFrame = HelperFunctions.reduceImg(img, c, t, impDim); // TODO: finish double-points - RadialSymmetry rs = new RadialSymmetry(timeFrameNormalized, interval, rsm); + RadialSymmetry rs = new RadialSymmetry(timeFrameNormalized, globalInterval, computeInterval, rsm); rs.compute(); - int minNumInliers = 1; + int minNumInliers = rsm.ransacSelection == 0 ? 0 : 1; // TODO: horrible! ArrayList filteredSpots = HelperFunctions.filterSpots(rs.getSpots(), minNumInliers); + allSpots.addAll(filteredSpots); timePoint.add(new Long(filteredSpots.size())); @@ -328,7 +386,6 @@ public static void process( // FIXME: make this a parameter, not doing this by default, will crash on 2d if ( false ) Intensity.fixIntensities(filteredSpots); - } if (c != 0) // FIXME: formula is wrong channelPoint.add(new Long(allSpots.size() - channelPoint.get(c - 1))); diff --git a/src/main/java/gui/Radial_Symmetry.java b/src/main/java/gui/Radial_Symmetry.java index f3e33db5..be4c364d 100644 --- a/src/main/java/gui/Radial_Symmetry.java +++ b/src/main/java/gui/Radial_Symmetry.java @@ -217,7 +217,8 @@ public void run(String arg) { public static < T extends RealType< T > > ArrayList runRSFISH( final RandomAccessible< T > img, - final Interval interval, + final Interval globalInterval, // we need to know where to cut off gradients at image borders + final Interval computeInterval, final RadialSymParams params ) { if ( img.numDimensions() < 2 || img.numDimensions() > 3 ) @@ -225,13 +226,13 @@ public static < T extends RealType< T > > ArrayList runRSFISH( final int[] impDim = new int[ 5 ]; // x y c z t - impDim[ 0 ] = (int)interval.dimension( 0 ); - impDim[ 1 ] = (int)interval.dimension( 1 ); + impDim[ 0 ] = (int)computeInterval.dimension( 0 ); + impDim[ 1 ] = (int)computeInterval.dimension( 1 ); impDim[ 2 ] = 1; - impDim[ 3 ] = interval.numDimensions() > 2 ? (int)interval.dimension( 2 ) : 1; + impDim[ 3 ] = computeInterval.numDimensions() > 2 ? (int)computeInterval.dimension( 2 ) : 1; impDim[ 4 ] = 1; - return runRSFISH( img, interval, params, 1, null, impDim); + return runRSFISH( img, globalInterval, computeInterval, params, 1, null, impDim); } public static < T extends RealType< T > > ArrayList runRSFISH( @@ -241,10 +242,22 @@ public static < T extends RealType< T > > ArrayList runRSFISH( final int mode, final ImagePlus imp, final int[] impDim ) + { + return runRSFISH(img, interval, interval, params, mode, imp, impDim); + } + + public static < T extends RealType< T > > ArrayList runRSFISH( + final RandomAccessible< T > img, + final Interval globalInterval, // we need to know where to cut off gradients at image borders + final Interval computeInterval, + final RadialSymParams params, + final int mode, + final ImagePlus imp, + final int[] impDim ) { if ( params.autoMinMax ) { - double[] minmax = HelperFunctions.computeMinMax( Views.interval( img, interval ) ); + double[] minmax = HelperFunctions.computeMinMax( Views.interval( img, computeInterval ) ); if (Double.isNaN( params.min ) ) params.min = (float) minmax[0]; @@ -275,7 +288,7 @@ public static < T extends RealType< T > > ArrayList runRSFISH( (a, b) -> b.setReal( ( a.getRealFloat() - params.min ) / range ), new FloatType()); - RadialSymmetry.process(input, rai, interval, params, impDim, allSpots, timePoint, channelPoint); + RadialSymmetry.process(input, rai, globalInterval, computeInterval, params, impDim, allSpots, timePoint, channelPoint); ResultsTable rt = null; diff --git a/src/main/java/parameters/RadialSymParams.java b/src/main/java/parameters/RadialSymParams.java index 21a3112b..6cae6d05 100644 --- a/src/main/java/parameters/RadialSymParams.java +++ b/src/main/java/parameters/RadialSymParams.java @@ -44,6 +44,9 @@ public class RadialSymParams implements Serializable { public static String defaultResultsFilePath = ""; + // only used for DoG + public int numThreads = Runtime.getRuntime().availableProcessors(); + // steps per octave for DoG public static int defaultSensitivity = 4; diff --git a/src/main/java/process/radialsymmetry/cluster/BatchProcess.java b/src/main/java/process/radialsymmetry/cluster/BatchProcess.java index c76b3517..00b61e1e 100644 --- a/src/main/java/process/radialsymmetry/cluster/BatchProcess.java +++ b/src/main/java/process/radialsymmetry/cluster/BatchProcess.java @@ -342,6 +342,7 @@ public static ArrayList processImage(Img img, RandomAccessibleI RadialSymmetry rs = new RadialSymmetry( Views.extendMirrorSingle( rai ), new FinalInterval( rai ), + new FinalInterval( rai ), rsm); rs.compute(); From b29936b94337b5ed4cf7dcdffb6f8b679b02c110 Mon Sep 17 00:00:00 2001 From: Stephan Preibisch Date: Tue, 6 Apr 2021 09:43:11 -0400 Subject: [PATCH 12/12] use filterRANSAC instead of RANSAC --- src/main/java/compute/RadialSymmetry.java | 2 +- src/main/java/fitting/Spot.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/compute/RadialSymmetry.java b/src/main/java/compute/RadialSymmetry.java index 1ec0c072..40a7ffff 100644 --- a/src/main/java/compute/RadialSymmetry.java +++ b/src/main/java/compute/RadialSymmetry.java @@ -33,7 +33,7 @@ public enum Ransac { NONE, SIMPLE, MULTICONSENSU }; public static int bsNumIterations = 500; // not a parameter, can be changed // through Beanshell - public static int numIterations = 500; // not a parameter, can be changed + public static int numIterations = 250; // not a parameter, can be changed // through Beanshell ArrayList peaks; diff --git a/src/main/java/fitting/Spot.java b/src/main/java/fitting/Spot.java index 11c7fe27..556379c6 100644 --- a/src/main/java/fitting/Spot.java +++ b/src/main/java/fitting/Spot.java @@ -554,7 +554,7 @@ public static void ransac( final Spot spot, final int iterations, final double m } else { - spot.center.ransac( spot.candidates, spot.inliers, iterations, maxError, inlierRatio, minNumInliers ); + spot.center.filterRansac( spot.candidates, spot.inliers, iterations, maxError, inlierRatio, minNumInliers ); spot.numRemoved = spot.candidates.size() - spot.inliers.size(); //System.out.println( Util.printCoordinates( spot.getOriginalLocation() ));