From 96e08a1c957e48cca9bfbb028fb1ba519188b11c Mon Sep 17 00:00:00 2001 From: Thomas MUSSET <thomas.musset@pasteur.fr> Date: Thu, 6 Apr 2023 14:34:50 +0200 Subject: [PATCH] update pom parent, add .DS_Store in gitignore, update some classes --- .gitignore | 1 + pom.xml | 62 +- .../adufour/activecontours/ActiveContour.java | 153 ++-- .../activecontours/ActiveContours.java | 741 ++++++------------ .../activecontours/ActiveContoursOverlay.java | 96 +-- .../activecontours/DeformationProfiler.java | 537 ++++++------- .../adufour/activecontours/Mesh3D.java | 324 +++----- .../adufour/activecontours/Polygon2D.java | 653 ++++++--------- .../adufour/activecontours/ReSampler.java | 40 +- .../activecontours/SaveMeshTracksToVTK.java | 52 +- .../adufour/activecontours/SlidingWindow.java | 44 +- .../activecontours/TopologyException.java | 20 +- 12 files changed, 1040 insertions(+), 1683 deletions(-) mode change 100644 => 100755 pom.xml diff --git a/.gitignore b/.gitignore index 8959c97..2d12c4b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ target/ .project .settings/ export.jardesc +**/.DS_Store \ No newline at end of file diff --git a/pom.xml b/pom.xml old mode 100644 new mode 100755 index 27e19be..ebb35b1 --- a/pom.xml +++ b/pom.xml @@ -5,18 +5,13 @@ <modelVersion>4.0.0</modelVersion> <parent> - <artifactId>pom-icy</artifactId> <groupId>org.bioimageanalysis.icy</groupId> - <version>2.1.0</version> + <artifactId>pom-icy</artifactId> + <version>2.2.0</version> </parent> - <!-- <parent> --> - <!-- <groupId>org.bioimageanalysis.icy</groupId> --> - <!-- <artifactId>parent-pom-plugin</artifactId> --> - <!-- <version>1.0.5</version> --> - <!-- </parent> --> <artifactId>active-contours</artifactId> - <version>4.4.12</version> + <version>4.4.13</version> <packaging>jar</packaging> @@ -29,32 +24,71 @@ <dependencies> <dependency> <groupId>org.bioimageanalysis.icy</groupId> - <artifactId>3d-mesh-roi</artifactId> + <artifactId>icy-vtk</artifactId> </dependency> + <dependency> <groupId>org.bioimageanalysis.icy</groupId> - <artifactId>fill-holes-in-roi</artifactId> + <artifactId>ezplug</artifactId> </dependency> <dependency> <groupId>org.bioimageanalysis.icy</groupId> - <artifactId>filter-toolbox</artifactId> + <artifactId>protocols</artifactId> </dependency> + <dependency> <groupId>org.bioimageanalysis.icy</groupId> - <artifactId>hk-means</artifactId> + <artifactId>java3d</artifactId> </dependency> <dependency> <groupId>org.bioimageanalysis.icy</groupId> - <artifactId>track-manager</artifactId> + <artifactId>vecmath</artifactId> </dependency> <dependency> <groupId>org.bioimageanalysis.icy</groupId> - <artifactId>java3d</artifactId> + <artifactId>jama</artifactId> </dependency> <dependency> <groupId>org.bioimageanalysis.icy</groupId> <artifactId>jfreechart</artifactId> </dependency> + <dependency> + <groupId>org.bioimageanalysis.icy</groupId> + <artifactId>quickhull</artifactId> + </dependency> + <dependency> + <groupId>net.sourceforge.jexcelapi</groupId> + <artifactId>jxl</artifactId> + </dependency> + <dependency> + <groupId>org.jogamp.jogl</groupId> + <artifactId>jogl-all</artifactId> + </dependency> + + <dependency> + <groupId>org.bioimageanalysis.icy</groupId> + <artifactId>spot-detection-utilities</artifactId> + </dependency> + <dependency> + <groupId>org.bioimageanalysis.icy</groupId> + <artifactId>track-manager</artifactId> + </dependency> + <dependency> + <groupId>org.bioimageanalysis.icy</groupId> + <artifactId>3d-mesh-roi</artifactId> + </dependency> + <dependency> + <groupId>org.bioimageanalysis.icy</groupId> + <artifactId>fill-holes-in-roi</artifactId> + </dependency> + <dependency> + <groupId>org.bioimageanalysis.icy</groupId> + <artifactId>filter-toolbox</artifactId> + </dependency> + <dependency> + <groupId>org.bioimageanalysis.icy</groupId> + <artifactId>hk-means</artifactId> + </dependency> </dependencies> <repositories> diff --git a/src/main/java/plugins/adufour/activecontours/ActiveContour.java b/src/main/java/plugins/adufour/activecontours/ActiveContour.java index 8f09c0c..ec65d87 100644 --- a/src/main/java/plugins/adufour/activecontours/ActiveContour.java +++ b/src/main/java/plugins/adufour/activecontours/ActiveContour.java @@ -18,11 +18,10 @@ import plugins.nchenouard.spot.Detection; /** * A generic active contour - * + * * @author Alexandre Dufour */ -public abstract class ActiveContour extends Detection implements Iterable<Point3d> -{ +public abstract class ActiveContour extends Detection implements Iterable<Point3d> { protected static final Processor processor = new Processor(SystemUtil.getNumberOfCPUs() * 2); protected String name; @@ -42,8 +41,7 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 /** * Constructor for XML loading purposes only */ - protected ActiveContour() - { + protected ActiveContour() { super(0, 0, 0, 0); name = ""; @@ -52,8 +50,7 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 } @SuppressWarnings("unchecked") - protected ActiveContour(Var<Double> sampling, final SlidingWindow convergenceWindow) - { + protected ActiveContour(Var<Double> sampling, final SlidingWindow convergenceWindow) { super(0, 0, 0, 0); name = ""; @@ -72,13 +69,11 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 setColor(Color.getHSBColor((float) Math.random(), 0.8f, 0.9f)); } - public String getName() - { + public String getName() { return name; } - public void setName(final String name) - { + public void setName(final String name) { this.name = name; } @@ -88,21 +83,19 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 /** * Adds the specified point to the contour. It is up to the implementing classes to determine * whether the points should be added in a specific order or based on geometric rules - * - * @param p - * the point to add + * + * @param p the point to add */ protected abstract void addPoint(Point3d p); /** * Checks whether the contour is self-intersecting. Depending on the given parameters, a * self-intersection can be considered as a loop or as a contour division. - * - * @param minDistance - * the distance threshold between non-neighboring points to detect self-intersection + * + * @param minDistance the distance threshold between non-neighboring points to detect self-intersection * @return null if either no self-intersection is detected or if one of the new contours is too - * small, or an array of contours with 0 elements if both contours are too small, and 2 - * elements if both contours are viable + * small, or an array of contours with 0 elements if both contours are too small, and 2 + * elements if both contours are viable */ protected abstract ActiveContour[] checkSelfIntersection(double minDistance); @@ -111,8 +104,6 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 * to keep the contour shape along its principal axis <br> * WARNING: this method directly update the array of final forces used to displace the contour * points. It should be used among the last to keep it most effective - * - * @param weight */ abstract void computeAxisForces(double weight); @@ -120,30 +111,22 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 /** * Update edge term of the contour evolution according to the image gradient - * - * @param weight - * @param edgeData - * a sequence containing the edge information (one channel per edge direction) + * + * @param edgeData a sequence containing the edge information (one channel per edge direction) */ abstract void computeEdgeForces(Sequence edgeData, int channel, double weight); /** * Update region term of the contour evolution according to the Chan-Vese-Mumford-Shah * functional - * - * @param imageData - * the image data (must a double-type image of range [0-1]) - * @param weight - * the weight of the data attachment term - * @param cin - * the intensity mean inside the contour - * @param cout - * the intensity mean outside the contour - * @param sensitivity - * set 1 for default, greater than 1 for high SNRs and vice-versa + * + * @param imageData the image data (must a double-type image of range [0-1]) + * @param weight the weight of the data attachment term + * @param cin the intensity mean inside the contour + * @param cout the intensity mean outside the contour + * @param sensitivity set 1 for default, greater than 1 for high SNRs and vice-versa */ - abstract void computeRegionForces(Sequence imageData, int channel, double weight, double sensitivity, double cin, - double cout); + abstract void computeRegionForces(Sequence imageData, int channel, double weight, double sensitivity, double cin, double cout); abstract void computeInternalForces(double weight); @@ -152,9 +135,8 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 /** * Computes the feedback forces yielded by the penetration of the current contour into the * target contour - * - * @param target - * the contour that is being penetrated + * + * @param target the contour that is being penetrated * @return the number of actual point-mesh intersection tests */ abstract int computeFeedbackForces(ActiveContour target); @@ -162,17 +144,12 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 /** * Compute the average image intensity inside the contour on the specified image data, and fill * out the mask buffer to allow the global exterior mean to be computed - * - * @param summedImageData - * the summed image data on which the average intensity should be computed - * @param mask - * the boolean mask where this contour should be rasterised + * + * @param summedImageData the summed image data on which the average intensity should be computed + * @param mask the boolean mask where this contour should be rasterised * @return the average intensity inside the contour - * @throws TopologyException - * if the contour becomes extremely thin to the point where it contains no pixel to - * measure intensity - * @throws InterruptedException - * @throws UnsupportedOperationException + * @throws TopologyException if the contour becomes extremely thin to the point where it contains no pixel to + * measure intensity */ public abstract double computeAverageIntensity(Sequence summedImageData, BooleanMask3D mask) throws TopologyException, UnsupportedOperationException, InterruptedException; @@ -181,12 +158,10 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 * Compute the average image intensity locally outside the contour on the specified image data. * When this method is called, the provided mask should already have been filled by *all* * contours, so as to ensure that the measure average is unbiased - * - * @param imageData - * the data on which the average intensity should be computed - * @param mask - * the boolean mask where all contours (including the current one) have already been - * rasterised + * + * @param imageData the data on which the average intensity should be computed + * @param mask the boolean mask where all contours (including the current one) have already been + * rasterised * @return the average intensity outside the contour */ public abstract double computeBackgroundIntensity(Sequence imageData, BooleanMask3D mask); @@ -194,11 +169,9 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 /** * Tests whether the given point is inside the contour, and if so returns * the penetration depth of this point. <br> - * - * @param p - * a point to test - * @return - * <ul> + * + * @param p a point to test + * @return <ul> * <li>if <code>p</code> is outside: <code>0</code> * <li>if <code>p</code> is inside: the distance from <code>p</code> * to the contour edge @@ -207,13 +180,12 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 public abstract double getDistanceToEdge(Point3d p); /** - * @param order - * the dimension (a.k.a. norm) to compute: - * <ul> - * <li>0: number of points,</li> - * <li>1: perimeter (2D) or surface area (3D),</li> - * <li>2: surface (2D) or volume (3D)</li> - * </ul> + * @param order the dimension (a.k.a. norm) to compute: + * <ul> + * <li>0: number of points,</li> + * <li>1: perimeter (2D) or surface area (3D),</li> + * <li>2: surface (2D) or volume (3D)</li> + * </ul> * @return the dimension for the specified order */ public abstract double getDimension(int order); @@ -226,11 +198,9 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 * points is strictly comprised between a minimum value and a maximum value. * In order to avoid oscillatory behavior, 'max' and 'min' should verify the * following relations: min < 1, max > 1, 2*min <= max. - * - * @param minFactor - * the minimum distance between two points. - * @param maxFactor - * the maximum distance between two points. + * + * @param minFactor the minimum distance between two points. + * @param maxFactor the maximum distance between two points. */ public abstract void reSample(double minFactor, double maxFactor) throws TopologyException; @@ -242,23 +212,17 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 public abstract ROI toROI() throws UnsupportedOperationException, InterruptedException; /** - * @param type - * the type of ROI to export - * @param sequence - * a sequence which can be used to retrieve the pixel size (may be needed if the - * contour is defined in real units rather than pixel units) + * @param type the type of ROI to export + * @param sequence a sequence which can be used to retrieve the pixel size (may be needed if the + * contour is defined in real units rather than pixel units) * @return a ROI representing the contour - * @throws UnsupportedOperationException - * if the contour cannot be exported in the requested type + * @throws UnsupportedOperationException if the contour cannot be exported in the requested type */ public abstract ROI toROI(ROIType type, Sequence sequence) throws UnsupportedOperationException, InterruptedException; /** * Paints the contour onto the specified sequence with the specified value - * - * @param output - * @param value */ public abstract void toSequence(Sequence output, double value); @@ -273,8 +237,7 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 * <li>center of mass</li> * </ul> */ - protected void updateMetaData() - { + protected void updateMetaData() { // center of mass final Point3d center = new Point3d(); @@ -291,8 +254,7 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 // center calculation double nbPts = 0; - for (final Point3d p : this) - { + for (final Point3d p : this) { nbPts++; center.add(p); @@ -324,8 +286,7 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 boundingSphere.setCenter(center); // radius calculation - for (final Point3d p : this) - { + for (final Point3d p : this) { final double d = p.distanceSquared(center); if (d > radius) @@ -349,24 +310,20 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 protected abstract void clean(); /** - * @param epsilon - * the convergence threshold + * @param epsilon the convergence threshold * @return <code>true</code> if the contour has converged */ public abstract boolean hasConverged(SlidingWindow.Operation operation, double epsilon); - public int getLastConvergedFrame() - { + public int getLastConvergedFrame() { return lastConvergedFrame; } - public void setLastConvergedFrame(final int frame) - { + public void setLastConvergedFrame(final int frame) { lastConvergedFrame = frame; } - public void setDivisionSensitivity(final Var<Double> divisionSensitivity) - { + public void setDivisionSensitivity(final Var<Double> divisionSensitivity) { this.divisionSensitivity = divisionSensitivity; } } diff --git a/src/main/java/plugins/adufour/activecontours/ActiveContours.java b/src/main/java/plugins/adufour/activecontours/ActiveContours.java index b70063e..660b05d 100644 --- a/src/main/java/plugins/adufour/activecontours/ActiveContours.java +++ b/src/main/java/plugins/adufour/activecontours/ActiveContours.java @@ -1,8 +1,6 @@ package plugins.adufour.activecontours; import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.Arrays; @@ -54,13 +52,11 @@ import plugins.adufour.ezplug.EzException; import plugins.adufour.ezplug.EzGroup; import plugins.adufour.ezplug.EzPlug; import plugins.adufour.ezplug.EzStoppable; -import plugins.adufour.ezplug.EzVar; import plugins.adufour.ezplug.EzVarBoolean; import plugins.adufour.ezplug.EzVarDimensionPicker; import plugins.adufour.ezplug.EzVarDouble; import plugins.adufour.ezplug.EzVarEnum; import plugins.adufour.ezplug.EzVarInteger; -import plugins.adufour.ezplug.EzVarListener; import plugins.adufour.ezplug.EzVarSequence; import plugins.adufour.filtering.Convolution1D; import plugins.adufour.filtering.Kernels1D; @@ -80,39 +76,32 @@ import plugins.kernel.roi.roi3d.ROI3DStack; import plugins.nchenouard.spot.Detection; import vtk.vtkObjectBase; -public class ActiveContours extends EzPlug implements EzStoppable, Block -{ +public class ActiveContours extends EzPlug implements EzStoppable, Block { public static final String CONTOUR_BASE_NAME = "Contour #"; public static final String CONTOUR_ID = "contourId"; - private class LocalRegionStatisticsComputer implements Callable<Object> - { + private class LocalRegionStatisticsComputer implements Callable<Object> { final ActiveContour contour; final boolean maskBased; - public LocalRegionStatisticsComputer(final ActiveContour contour, final boolean maskBased) - { + public LocalRegionStatisticsComputer(final ActiveContour contour, final boolean maskBased) { this.contour = contour; this.maskBased = maskBased; } @Override - public Object call() throws InterruptedException - { - try - { + public Object call() throws InterruptedException { + try { final double cin = contour.computeAverageIntensity(contour instanceof Mesh3D ? regionData : regionDataSummed, maskBased ? contourMask_buffer : null); region_cin.put(trackGroup.getValue().getTrackSegmentWithDetection(contour), cin); } - catch (TopologyException topo) - { + catch (TopologyException topo) { System.err.println("Removing a contour. Reason: " + topo.getMessage()); allContoursAtTimeT.remove(contour); evolvingContoursAtTimeT.remove(contour); } - catch (UnsupportedOperationException ex) - { + catch (UnsupportedOperationException ex) { System.err.println("Error while computing contour statistics: " + ex.getMessage()); } @@ -120,18 +109,15 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } } - private class LocalBackgroundStatisticsComputer implements Callable<Object> - { + private class LocalBackgroundStatisticsComputer implements Callable<Object> { final ActiveContour contour; - public LocalBackgroundStatisticsComputer(final ActiveContour contour) - { + public LocalBackgroundStatisticsComputer(final ActiveContour contour) { this.contour = contour; } @Override - public Object call() - { + public Object call() { final TrackSegment segment = trackGroup.getValue().getTrackSegmentWithDetection(contour); final double cout = contour.computeBackgroundIntensity(regionData, contourMask_buffer); @@ -142,8 +128,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } } - private class ContourInitializer implements Callable<Object> - { + private class ContourInitializer implements Callable<Object> { final ROI roi; final int z; final int t; @@ -153,8 +138,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block final List<TrackSegment> endedTracks; public ContourInitializer(final ROI roi, final int z, final int t, final Tuple3d pixelSize, final int convWinSize, - final List<TrackSegment> activeTracks, final List<TrackSegment> justEndedTracks) - { + final List<TrackSegment> activeTracks, final List<TrackSegment> justEndedTracks) { super(); this.roi = roi; @@ -168,8 +152,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block // test if the object is colliding an existing contour or if we need to discard // it for other reason - private boolean colliding() throws UnsupportedOperationException, InterruptedException - { + private boolean colliding() throws UnsupportedOperationException, InterruptedException { // // image bounds // final Rectangle imageBounds = inputData.getBounds2D(); // // minus one (to detect object on border) @@ -179,8 +162,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block // imageBounds.height -= 2; // test if object is intersecting with current active contours - for (final TrackSegment segment : activeTracks) - { + for (final TrackSegment segment : activeTracks) { // get contour for this active track final ActiveContour contour = (ActiveContour) segment.getLastDetection(); // get ROI from contour @@ -195,8 +177,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } @Override - public Object call() throws InterruptedException - { + public Object call() throws InterruptedException { // object colliding active contours ? --> discard it if (colliding()) return null; @@ -208,15 +189,13 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block return null; // does it overlap with a track that terminates in the previous frame? - for (final TrackSegment track : endedTracks) - { + for (final TrackSegment track : endedTracks) { final ActiveContour previousContour = (ActiveContour) track.getLastDetection(); // get ROI from contour final ROI previousContourROI = previousContour.toROI(ROIType.POLYGON, null); // object is intersecting previous contour ? - if (roi.intersects(previousContourROI)) - { + if (roi.intersects(previousContourROI)) { System.out.println("Found link at time " + t + ", position (" + contour.getX() + ";" + contour.getY() + ")"); // add contour to the track track.addDetection(contour); @@ -235,14 +214,12 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } } - private class ContourDuplicator implements Callable<Object> - { + private static class ContourDuplicator implements Callable<Object> { final TrackSegment segment; final int t; final int convWinSize; - public ContourDuplicator(final TrackSegment segment, final int t, final int convWinSize) - { + public ContourDuplicator(final TrackSegment segment, final int t, final int convWinSize) { super(); this.segment = segment; @@ -251,8 +228,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } @Override - public Object call() - { + public Object call() { Detection detection; detection = segment.getDetectionAtTime(t); @@ -307,30 +283,26 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block public final EzVarDouble contour_resolution = new EzVarDouble("Contour sampling", 2, 0.1, 10000.0, 0.1); public final EzVarDouble contour_timeStep = new EzVarDouble("Evolution time step", 0.1, 0.1, 10, 0.01); public final EzVarInteger convergence_winSize = new EzVarInteger("Convergence window size", 50, 10, 10000, 10); - public final EzVarEnum<Operation> convergence_operation = new EzVarEnum<SlidingWindow.Operation>("Convergence operation", Operation.values(), - Operation.VAR_COEFF); + public final EzVarEnum<Operation> convergence_operation = new EzVarEnum<>("Convergence operation", Operation.values(), Operation.VAR_COEFF); public final EzVarDouble convergence_criterion = new EzVarDouble("Convergence criterion", 0.001, 0, 1, 0.0001); public final EzVarInteger convergence_nbIter = new EzVarInteger("Max. iterations", 100000, 100, 100000, 1000); - public enum ExportROI - { + public enum ExportROI { NO, ON_INPUT, ON_NEW_IMAGE, AS_LABELS } - public enum ROIType - { + public enum ROIType { AREA(ROI2DArea.class), POLYGON(ROI2DPolygon.class); final Class<? extends ROI> clazz; - private ROIType(final Class<? extends ROI> clazz) - { + ROIType(final Class<? extends ROI> clazz) { this.clazz = clazz; } } - public final EzVarEnum<ExportROI> output_rois = new EzVarEnum<ExportROI>("Export ROI", ExportROI.values(), ExportROI.NO); - public final EzVarEnum<ROIType> output_roiType = new EzVarEnum<ROIType>("Type of ROI", ROIType.values(), ROIType.AREA); + public final EzVarEnum<ExportROI> output_rois = new EzVarEnum<>("Export ROI", ExportROI.values(), ExportROI.NO); + public final EzVarEnum<ROIType> output_roiType = new EzVarEnum<>("Type of ROI", ROIType.values(), ROIType.AREA); private final VarSequence output_labels = new VarSequence("Labels", null); public final EzVarBoolean tracking = new EzVarBoolean("Track objects over time", false); @@ -339,7 +311,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block public final EzVarBoolean tracking_newObjects = new EzVarBoolean("Watch entering objects", false); - private final HashMap<TrackSegment, Double> volumes = new HashMap<TrackSegment, Double>(); + private final HashMap<TrackSegment, Double> volumes = new HashMap<>(); public final EzVarBoolean volume_constraint = new EzVarBoolean("Volume constraint", false); public final EzVarDouble volume_weight = new EzVarDouble("Volume weight", 0.01, 0, 1, 0.001); @@ -351,25 +323,25 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block private BooleanMask3D contourMask_buffer; - HashMap<TrackSegment, Double> region_cin = new HashMap<TrackSegment, Double>(0); - HashMap<TrackSegment, Double> region_cout = new HashMap<TrackSegment, Double>(0); + final HashMap<TrackSegment, Double> region_cin = new HashMap<>(0); + final HashMap<TrackSegment, Double> region_cout = new HashMap<>(0); public final VarROIArray roiInput = new VarROIArray("input ROI"); public final VarROIArray roiOutput = new VarROIArray("Regions of interest"); private boolean globalStop; - Var<TrackGroup> trackGroup = new Var<TrackGroup>("Tracks", TrackGroup.class); + Var<TrackGroup> trackGroup = new Var<>("Tracks", TrackGroup.class); /** * All contours present on the current time point */ - private final HashSet<ActiveContour> allContoursAtTimeT = new HashSet<ActiveContour>(); + private final HashSet<ActiveContour> allContoursAtTimeT = new HashSet<>(); /** * Set of contours that have not yet converged on the current time point */ - private final HashSet<ActiveContour> evolvingContoursAtTimeT = new HashSet<ActiveContour>(); + private final HashSet<ActiveContour> evolvingContoursAtTimeT = new HashSet<>(); private ActiveContoursOverlay overlay; @@ -377,45 +349,30 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block private long lastVtkGCTime = 0L; - public ActiveContours() - { + public ActiveContours() { super(); multiThreadService.setThreadName("Active Contours"); - showTrackManager = new EzButton("Send to track manager", new ActionListener() - { - @Override - public void actionPerformed(final ActionEvent e) - { - ThreadUtil.invokeLater(new Runnable() - { - @Override - public void run() - { - if (trackGroup.getValue() == null) - return; - if (trackGroup.getValue().getTrackSegmentList().isEmpty()) - return; - - Icy.getMainInterface().getSwimmingPool().add(new SwimmingObject(trackGroup.getValue())); - final TrackManager tm = new TrackManager(); - tm.reOrganize(); - tm.setDisplaySequence(inputData); - } - }); - } - }); + showTrackManager = new EzButton("Send to track manager", e -> ThreadUtil.invokeLater(() -> { + if (trackGroup.getValue() == null) + return; + if (trackGroup.getValue().getTrackSegmentList().isEmpty()) + return; + + Icy.getMainInterface().getSwimmingPool().add(new SwimmingObject(trackGroup.getValue())); + final TrackManager tm = new TrackManager(); + tm.reOrganize(); + tm.setDisplaySequence(inputData); + })); } - public TrackGroup getTrackGroup() - { + public TrackGroup getTrackGroup() { return trackGroup.getValue(); } @Override - public void initialize() - { + public void initialize() { addEzComponent(showAdvancedOptions); addEzComponent(input); @@ -507,16 +464,14 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } @Override - public void loadParameters(final File file) - { + public void loadParameters(final File file) { super.loadParameters(file); volume_constraint.setValue(Boolean.FALSE); } @Override - public void execute() - { + public void execute() { output_labels.setValue(null); volumes.clear(); roiOutput.setValue(null); @@ -538,7 +493,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block if (tracks != null) tracks.clearAllTrackSegment(); tracks = new TrackGroup(inputData); - tracks.setDescription("Active contours (" + new Date().toString() + ")"); + tracks.setDescription("Active contours (" + new Date() + ")"); trackGroup.setValue(tracks); // initialize the mask buffer once (used to calculate average intensities @@ -552,11 +507,9 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block contourMask_buffer = new BooleanMask3D(bounds3d, maskSlices); - if (!Icy.getMainInterface().isHeadLess()) - { + if (!Icy.getMainInterface().isHeadLess()) { // replace any ActiveContours Painter object on the sequence by ours - for (final Overlay existingOverlay : inputData.getOverlays()) - { + for (final Overlay existingOverlay : inputData.getOverlays()) { if (existingOverlay instanceof ActiveContoursOverlay) existingOverlay.remove(); } @@ -574,37 +527,29 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block ROI field = null; final Sequence boundSource = evolution_bounds.getValue(); - if (boundSource != null) - { + if (boundSource != null) { final List<ROI> rois = boundSource.getROIs(); - if (rois.size() > 0) - { - try - { + if (rois.size() > 0) { + try { field = ROIUtil.merge(rois, BooleanOperator.OR); } - catch (final UnsupportedOperationException e) - { + catch (final UnsupportedOperationException e) { throw new VarException(evolution_bounds.getVariable(), "Cannot compute the evolution bounds: " + e.getMessage() + "\nIf you are not sure how to fix this, change this parameter to \"No Sequence\""); } - catch (InterruptedException e) - { + catch (InterruptedException e) { throw new VarException(evolution_bounds.getVariable(), "Interrupted Active Contours process..."); } } } // no specific field ? limit to sequence bounds - if (field == null) - - { + if (field == null) { if (inputData.getSizeZ() == 1) field = new ROI2DRectangle(0, 0, inputData.getWidth(), inputData.getHeight()); - else - { - final ROI3DStack<ROI2DRectangle> field3D = new ROI3DStack<ROI2DRectangle>(ROI2DRectangle.class); + else { + final ROI3DStack<ROI2DRectangle> field3D = new ROI3DStack<>(ROI2DRectangle.class); for (int z = 0; z < inputData.getSizeZ() - 1; z++) field3D.setSlice(z, new ROI2DRectangle(0, 0, inputData.getWidth(), inputData.getHeight())); @@ -613,8 +558,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } } - for (int t = startT; t <= endT; t++) - { + for (int t = startT; t <= endT; t++) { int iteration; // if sizeT changed during AC processing (i already did it to shorthen @@ -631,8 +575,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block if (isHeadLess()) System.out.println("=> preparing image data..."); - try - { + try { initData(t); if (isHeadLess()) @@ -646,8 +589,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block if (iteration > 0) System.out.println("[Active Contours] converged current contours on frame " + t + " in " + iteration + " iterations"); } - catch (InterruptedException e) - { + catch (InterruptedException e) { // so it will end nicely Thread.currentThread().interrupt(); } @@ -657,12 +599,10 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block if (isHeadLess()) System.out.println("=> adding new contours..."); - try - { + try { addNewContours(t); } - catch (InterruptedException e) - { + catch (InterruptedException e) { // so it will end nicely Thread.currentThread().interrupt(); } @@ -670,22 +610,18 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block if (Thread.currentThread().isInterrupted()) break; - try - { + try { if (isHeadLess()) System.out.println("=> evolving new contours..."); // evolve new contours iteration = evolveContours(t, field); // no more contours for this time point ? - if (iteration == -1) - { + if (iteration == -1) { // detection of new objects disable ? - if (!tracking_newObjects.getValue().booleanValue() || (inputData.getSizeZ() != 1)) - { + if (!tracking_newObjects.getValue().booleanValue() || (inputData.getSizeZ() != 1)) { // no ROIs to work with in future ? --> we can stop process here - if (!hasFutureRois(t)) - { + if (!hasFutureRois(t)) { storeResult(t); break; } @@ -699,8 +635,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block // store detections and results storeResult(t); } - catch (InterruptedException e) - { + catch (InterruptedException e) { // interrupt nicely Thread.currentThread().interrupt(); } @@ -714,27 +649,22 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block int maxId = 0; // get maximum id - for (final ROI roi : roiOutput.getValue()) - { - try - { + for (final ROI roi : roiOutput.getValue()) { + try { // get object id final int contourId = Integer.parseInt(roi.getProperty(CONTOUR_ID)); if (contourId > maxId) maxId = contourId; } - catch (final Exception e) - { + catch (final Exception e) { // ignore } } // then fix ROI names final int nbPaddingDigits = (int) Math.floor(Math.log10(maxId)); - for (final ROI roi : roiOutput.getValue()) - { - try - { + for (final ROI roi : roiOutput.getValue()) { + try { // get object id final int contourId = Integer.parseInt(roi.getProperty(CONTOUR_ID)); final String roiName = roi.getName(); @@ -744,26 +674,21 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block else roi.setName(CONTOUR_BASE_NAME + StringUtil.toString(contourId, nbPaddingDigits) + " (" + roiName + ")"); } - catch (final Exception e) - { + catch (final Exception e) { // ignore } } - if (getUI() != null) - { + if (getUI() != null) { Sequence out = inputData; - switch (output_rois.getValue()) - { + switch (output_rois.getValue()) { case ON_NEW_IMAGE: - try - { + try { out = SequenceUtil.getCopy(inputData); out.setName(inputData.getName() + " + Active contours"); } - catch (InterruptedException e) - { + catch (InterruptedException e) { throw new VarException(output_rois.getVariable(), "Interrupted output sequence creation..."); } //$FALL-THROUGH$ @@ -804,23 +729,19 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block regionDataSummed = null; } - boolean executeMultiThread(final Collection<Callable<Object>> tasks, final String messageOnError) throws Exception - { - try - { + boolean executeMultiThread(final Collection<Callable<Object>> tasks, final String messageOnError) throws Exception { + try { // force wait completion for all tasks for (final Future<Object> res : multiThreadService.invokeAll(tasks)) res.get(); return true; } - catch (final InterruptedException e) - { + catch (final InterruptedException e) { // restore the interrupted flag Thread.currentThread().interrupt(); } - catch (final Exception e) - { + catch (final Exception e) { if (StringUtil.isEmpty(messageOnError)) throw e; @@ -831,8 +752,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block return false; } - private void initData(final int t) throws InterruptedException - { + private void initData(final int t) throws InterruptedException { final int edgeChannel = edge_c.getValue().intValue(); final int regionChannel = region_c.getValue().intValue(); @@ -863,39 +783,34 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block regionData = new Sequence(OMEUtil.createOMEXMLMetadata(inputData.getOMEXMLMetadata()), "region data"); // convert float data rescaled to [0..1] - for (int z = 0; z < bounds.sizeZ; z++) - { + for (int z = 0; z < bounds.sizeZ; z++) { IcyBufferedImage img; img = currentFrame.getImage(0, z, edgeChannel); - img = IcyBufferedImageUtil.convertType(img, DataType.FLOAT, new Scaler[] {edgeScaler}); + img = IcyBufferedImageUtil.convertType(img, DataType.FLOAT, new Scaler[]{edgeScaler}); edgeData.setImage(0, z, img); img = currentFrame.getImage(0, z, regionChannel); - img = IcyBufferedImageUtil.convertType(img, DataType.FLOAT, new Scaler[] {regionScaler}); + img = IcyBufferedImageUtil.convertType(img, DataType.FLOAT, new Scaler[]{regionScaler}); regionData.setImage(0, z, img); } - try - { + try { // smooth the signal final Sequence gaussian = Kernels1D.CUSTOM_GAUSSIAN.createGaussianKernel1D(1).toSequence(); Convolution1D.convolve(edgeData, gaussian, gaussian, null); Convolution1D.convolve(regionData, gaussian, gaussian, null); } - catch (final Exception e) - { + catch (final Exception e) { System.err.println("Warning: error while smoothing the signal: " + e.getMessage()); } // summed region data (use to accelerate intensity calculations) regionDataSummed = SequenceUtil.getCopy(regionData); - for (int z = 0; z < bounds.sizeZ; z++) - { + for (int z = 0; z < bounds.sizeZ; z++) { final float[] regionDataSliceSummed = regionDataSummed.getDataXYAsFloat(0, z, 0); - for (int j = 0; j < bounds.sizeY; j++) - { + for (int j = 0; j < bounds.sizeY; j++) { // start at the second pixel (index 1) of each line int offset = (j * bounds.sizeX) + 1; @@ -909,16 +824,14 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } } - private void initCurrentContours(final int t) - { + private void initCurrentContours(final int t) { // prepare parameters final int convWinSize = convergence_winSize.getValue().intValue() * 2; // use multi threading to initiate current contours (by duplicating ones from // previous frame) - final List<Callable<Object>> tasks = new ArrayList<Callable<Object>>(); + final List<Callable<Object>> tasks = new ArrayList<>(); - try - { + try { // duplicate contours from the previous frame for (final TrackSegment segment : trackGroup.getValue().getTrackSegmentList()) tasks.add(new ContourDuplicator(segment, t, convWinSize)); @@ -926,17 +839,16 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block // execute tasks executeMultiThread(tasks, "couldn't duplicate a contour"); } - catch (final Exception e) - { + catch (final Exception e) { e.printStackTrace(); System.err.println("Warning: (reason: " + e.getMessage() + "). Moving on..."); } } - private void addNewContours(final int t) throws InterruptedException - { + private void addNewContours(final int t) throws InterruptedException { // prepare parameters final TrackGroup tg = trackGroup.getValue(); + final List<TrackSegment> tracks = trackGroup.getValue().getTrackSegmentList(); final int convWinSize = convergence_winSize.getValue().intValue() * 2; final Viewer viewer = inputData.getFirstViewer(); @@ -951,18 +863,16 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block final List<ROI> objects = getNewObjectsFor(t); // use multi threading to initiate contours from these new objects - final List<Callable<Object>> tasks = new ArrayList<Callable<Object>>(); - final List<TrackSegment> newTracks = new ArrayList<TrackSegment>(); + final List<Callable<Object>> tasks = new ArrayList<>(); + final List<TrackSegment> newTracks = new ArrayList<>(); - try - { + try { // initialize new contours for (final ROI roi : objects) tasks.add(new ContourInitializer(roi, currentZ, t, pixelSize, convWinSize, activeTracks, justEndedTracks)); // force wait completion for all tasks - for (final Future<Object> res : multiThreadService.invokeAll(tasks)) - { + for (final Future<Object> res : multiThreadService.invokeAll(tasks)) { final TrackSegment track = (TrackSegment) res.get(); // a new track was created ? --> add it @@ -970,30 +880,25 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block newTracks.add(track); } } - catch (final InterruptedException e) - { + catch (final InterruptedException e) { // restore the interrupted flag Thread.currentThread().interrupt(); } - catch (final Exception e) - { + catch (final Exception e) { e.printStackTrace(); System.err.println("Warning: couldn't initialize a contour (reason: " + e.getMessage() + ")."); } // add new created tracks - synchronized (tg) - { + synchronized (tg) { for (final TrackSegment track : newTracks) tg.addTrackSegment(track); } - synchronized (region_cin) - { + synchronized (region_cin) { for (final TrackSegment track : newTracks) region_cin.put(track, Double.valueOf(0d)); } - synchronized (region_cout) - { + synchronized (region_cout) { for (final TrackSegment track : newTracks) region_cout.put(track, Double.valueOf(0d)); } @@ -1002,14 +907,11 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block /** * Returns all {@link TrackSegment} ending at the specified time point */ - private List<TrackSegment> getTracksEndingAt(final List<TrackSegment> tracks, final int t) - { - final List<TrackSegment> result = new ArrayList<TrackSegment>(); - - if (t >= 0) - { - for (final TrackSegment track : tracks) - { + private List<TrackSegment> getTracksEndingAt(final List<TrackSegment> tracks, final int t) { + final List<TrackSegment> result = new ArrayList<>(); + + if (t >= 0) { + for (final TrackSegment track : tracks) { // get last detection for this track final Detection detection = track.getLastDetection(); @@ -1022,13 +924,11 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block return result; } - private boolean hasFutureRois(final int t) - { + private boolean hasFutureRois(final int t) { List<ROI> rois = CollectionUtil.asArrayList(roiInput.getValue()); // protocol mode, no ROI ? --> no more ROI - if (rois.isEmpty()) - { + if (rois.isEmpty()) { if (isHeadLess()) return false; @@ -1041,16 +941,13 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block return false; // only pick ROI for current frame - for (final ROI roi : rois) - { - if (roi instanceof ROI2D) - { + for (final ROI roi : rois) { + if (roi instanceof ROI2D) { // we have new ROI for this time point or in future if (((ROI2D) roi).getT() >= t) return true; } - else if (roi instanceof ROI3D) - { + else if (roi instanceof ROI3D) { if (((ROI3D) roi).getT() >= t) return true; } @@ -1059,13 +956,11 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block return false; } - private List<ROI> getRoisOf(final int t) - { + private List<ROI> getRoisOf(final int t) { List<ROI> result = CollectionUtil.asArrayList(roiInput.getValue()); // protocol mode, no ROI ? --> cannot continue - if (result.isEmpty()) - { + if (result.isEmpty()) { if (isHeadLess()) throw new VarException(roiInput, "Active contours: no input ROI"); @@ -1077,16 +972,13 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block throw new VarException(input.getVariable(), "Please draw or select a ROI"); // only pick ROI for current frame - for (int i = result.size() - 1; i >= 0; i--) - { + for (int i = result.size() - 1; i >= 0; i--) { final ROI roi = result.get(i); - if (roi instanceof ROI2D) - { + if (roi instanceof ROI2D) { final int rt = ((ROI2D) roi).getT(); - if (rt == -1) - { + if (rt == -1) { // take T = -1 ROI only on first frame if (t > 0) result.remove(i); @@ -1095,12 +987,10 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block else if (rt != t) result.remove(i); } - else if (roi instanceof ROI3D) - { + else if (roi instanceof ROI3D) { final int rt = ((ROI3D) roi).getT(); - if (rt == -1) - { + if (rt == -1) { // take T = -1 ROI only on first frame if (t > 0) result.remove(i); @@ -1119,18 +1009,14 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block /** * Create a copy of input ROI and split multiples components ROI if needed - * - * @throws InterruptedException */ - private List<ROI> getWorkRois(final ROI roi) throws InterruptedException - { + private List<ROI> getWorkRois(final ROI roi) throws InterruptedException { // get minimum allowed size final int minPoints = (int) (contour_resolution.getValue().doubleValue() * 3); - final List<ROI> result = new ArrayList<ROI>(); + final List<ROI> result = new ArrayList<>(); // 2D area ROI (we should also consider 3D area normally) - if (roi instanceof ROI2DArea) - { + if (roi instanceof ROI2DArea) { final ROI2DArea area = (ROI2DArea) roi; // get mask final BooleanMask2D mask = area.getBooleanMask(true); @@ -1138,11 +1024,9 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block final BooleanMask2D[] components = mask.getComponents(); // check if the area has multiple components - if (components.length > 1) - { + if (components.length > 1) { // split multi components ROI - for (final BooleanMask2D comp : components) - { + for (final BooleanMask2D comp : components) { // don't bother initializing contours that are too small (w.r.t. the required // sampling) if (comp.getNumberOfPoints() < minPoints) @@ -1159,8 +1043,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block result.add(newArea); } } - else - { + else { // accept only if above minimal wanted number of point if (mask.getNumberOfPoints() >= minPoints) result.add(roi.getCopy()); @@ -1173,9 +1056,8 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block return result; } - private List<ROI> getNewObjectsFor(final int t) throws InterruptedException - { - final List<ROI> result = new ArrayList<ROI>(); + private List<ROI> getNewObjectsFor(final int t) throws InterruptedException { + final List<ROI> result = new ArrayList<>(); // get ROI located at the given time point for (final ROI roi : getRoisOf(t)) @@ -1183,18 +1065,15 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block result.addAll(getWorkRois(roi)); // watch for entering object (only for 2D) - if (tracking_newObjects.getValue().booleanValue() && (inputData.getSizeZ() == 1)) - { + if (tracking_newObjects.getValue().booleanValue() && (inputData.getSizeZ() == 1)) { final Collection<Double> allVolumes = volumes.values(); double minVol = 0d; double maxVol = 0d; double meanVol = 0d; // compute mean volume for object - if (!allVolumes.isEmpty()) - { - for (final Double volume : allVolumes) - { + if (!allVolumes.isEmpty()) { + for (final Double volume : allVolumes) { final double v = volume.doubleValue(); if ((minVol == 0d) || (v < minVol)) @@ -1218,13 +1097,11 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block maxVol = Math.round(maxVol); // don't try to detect new tiny objects - if (maxVol > 10) - { + if (maxVol > 10) { // we use HK-Means plugin to detect entering objects in region data only // (HK-Mean won't work on edge signal anyway) // Note that it will work only for fluo images here - for (final ROI roi : HKMeans.hKMeans(regionData, (byte) 7, (int) minVol, (int) maxVol, Double.valueOf(0d))) - { + for (final ROI roi : HKMeans.hKMeans(regionData, (byte) 7, (int) minVol, (int) maxVol, Double.valueOf(0d))) { // set correct position for ROI ((ROI2D) roi).setC(-1); ((ROI2D) roi).setZ(-1); @@ -1240,24 +1117,18 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block /** * Return new contour from a given ROI. - * - * @throws InterruptedException */ - ActiveContour getContourOf(final ROI roi, final int z, final int t, final Tuple3d pixelSize, final int convWinSize) throws InterruptedException - { + ActiveContour getContourOf(final ROI roi, final int z, final int t, final Tuple3d pixelSize, final int convWinSize) throws InterruptedException { final int depth = inputData.getSizeZ(); ActiveContour result = null; - try - { + try { // fix Z position for 2D ROI - if (roi instanceof ROI2D) - { + if (roi instanceof ROI2D) { final ROI2D roi2d = (ROI2D) roi; // infinite Z dim ? - if (roi2d.getZ() == -1) - { + if (roi2d.getZ() == -1) { // a 2D contour cannot be created from a "virtually 3D" ROI, merely a slice of // it => which one? if (z == -1) @@ -1274,8 +1145,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block result.setT(t); } - else if (roi instanceof ROI3D) - { + else if (roi instanceof ROI3D) { result = new Mesh3D(contour_resolution.getVariable(), (Tuple3d) pixelSize.clone(), (ROI3D) roi, new SlidingWindow(convWinSize)); // contour.setX(r3.getBounds3D().getCenterX()); // contour.setY(r3.getBounds3D().getCenterY()); @@ -1284,8 +1154,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block else System.err.println("Warning: couldn't create a contour for ROI '" + roi.getName() + "' (ROI not supported)"); } - catch (final TopologyException topo) - { + catch (final TopologyException topo) { System.err.println("Warning: couldn't create a contour for ROI '" + roi.getName() + "'"); } @@ -1345,13 +1214,11 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block // } // } - public int evolveContours(final int t, final ROI boundField) throws InterruptedException - { + public int evolveContours(final int t, final ROI boundField) throws InterruptedException { // retrieve the contours on the current frame and store them in currentContours allContoursAtTimeT.clear(); - for (final TrackSegment segment : trackGroup.getValue().getTrackSegmentList()) - { + for (final TrackSegment segment : trackGroup.getValue().getTrackSegmentList()) { final Detection det = segment.getDetectionAtTime(t); if (det != null) allContoursAtTimeT.add((ActiveContour) det); @@ -1365,16 +1232,13 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block int nbConvergedContours = 0; boolean hasContour3d = false; - while (!globalStop && (nbConvergedContours < allContoursAtTimeT.size())) - { + while (!globalStop && (nbConvergedContours < allContoursAtTimeT.size())) { nbConvergedContours = 0; // prepare the list of current evolving (i.e. non-converged) contours evolvingContoursAtTimeT.clear(); - for (final ActiveContour contour : allContoursAtTimeT) - { - if ((contour.getLastConvergedFrame() == t) || contour.hasConverged(convergence_operation.getValue(), convergence_criterion.getValue())) - { + for (final ActiveContour contour : allContoursAtTimeT) { + if ((contour.getLastConvergedFrame() == t) || contour.hasConverged(convergence_operation.getValue(), convergence_criterion.getValue())) { contour.setLastConvergedFrame(t); nbConvergedContours++; continue; @@ -1392,8 +1256,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block if (evolvingContoursAtTimeT.size() == 0) break; - if (getUI() != null) - { + if (getUI() != null) { if (nbConvergedContours == 0) getUI().setProgressBarValue(Double.NaN); else @@ -1403,18 +1266,17 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } // re-sample the contours to ensure homogeneous resolution - resampleContours(t); + //resampleContours(t); + resampleContours(); // we are based on region ? - if (region_weight.getValue() > EPSILON) - { + if (region_weight.getValue() > EPSILON) { // update region information (if necessary): // - every 10 iterations // if the contour list has changed boolean updateRegionStatistics = iter % (convergence_winSize.getValue() / 3) == 0; - for (final ActiveContour contour : allContoursAtTimeT) - { + for (final ActiveContour contour : allContoursAtTimeT) { // make sure this contour's statistics exist if (region_cout.containsKey(trackGroup.getValue().getTrackSegmentWithDetection(contour))) continue; @@ -1436,8 +1298,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block // if we have 3D contour, force VTK garbage collection from time to time (ugly // method but we always end with unreleased objects with VTK) final long time = System.currentTimeMillis(); - if (hasContour3d && ((iter & 0x1FF) == 0) || ((time - lastVtkGCTime) > 10000L)) - { + if (hasContour3d && ((iter & 0x1FF) == 0) || ((time - lastVtkGCTime) > 10000L)) { vtkObjectBase.JAVA_OBJECT_MANAGER.gc(false); lastVtkGCTime = time; } @@ -1446,8 +1307,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block overlay.painterChanged(); // maximum number of iteration allowed raised ? - if (iter >= convergence_nbIter.getValue()) - { + if (iter >= convergence_nbIter.getValue()) { // consider that all current evolving contours converged here for (final ActiveContour contour : evolvingContoursAtTimeT) contour.setLastConvergedFrame(t); @@ -1467,155 +1327,120 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block /** * Deform contours together - * - * @param evolvingContours - * @param allContours - * @throws InterruptedException + * * @deprecated parameters evolvingContours and allContours are not necessary - * anymore (they are now instance variables) + * anymore (they are now instance variables) */ @Deprecated - public void deformContours(final HashSet<ActiveContour> evolvingContours, final HashSet<ActiveContour> allContours, final ROI field) - throws InterruptedException - { + public void deformContours(final HashSet<ActiveContour> evolvingContours, final HashSet<ActiveContour> allContours, final ROI field) throws InterruptedException { deformContours(field); } /** * Deform contours together - * - * @throws InterruptedException */ - public void deformContours(final ROI boundField) throws InterruptedException - { - if (evolvingContoursAtTimeT.size() == 1 && allContoursAtTimeT.size() == 1) - { + public void deformContours(final ROI boundField) throws InterruptedException { + if (evolvingContoursAtTimeT.size() == 1 && allContoursAtTimeT.size() == 1) { // no multi-threading needed final ActiveContour contour = evolvingContoursAtTimeT.iterator().next(); final TrackSegment segment = trackGroup.getValue().getTrackSegmentWithDetection(contour); - if (Math.abs(edge_weight.getValue()) > EPSILON) - { + if (Math.abs(edge_weight.getValue()) > EPSILON) { contour.computeEdgeForces(edgeData, 0, edge_weight.getValue()); } - if (regul_weight.getValue() > EPSILON) - { + if (regul_weight.getValue() > EPSILON) { contour.computeInternalForces(regul_weight.getValue()); } - if (region_weight.getValue() > EPSILON) - { + if (region_weight.getValue() > EPSILON) { final double cin = region_cin.get(segment); final double cout = region_cout.get(segment); contour.computeRegionForces(regionData, 0, region_weight.getValue(), region_sensitivity.getValue(), cin, cout); } - if (axis_weight.getValue() > EPSILON) - { + if (axis_weight.getValue() > EPSILON) { contour.computeAxisForces(axis_weight.getValue()); } - if (Math.abs(balloon_weight.getValue()) > EPSILON) - { + if (Math.abs(balloon_weight.getValue()) > EPSILON) { contour.computeBalloonForces(balloon_weight.getValue()); } - if (volume_constraint.getValue() && volumes.containsKey(segment)) - { + if (volume_constraint.getValue() && volumes.containsKey(segment)) { contour.computeVolumeConstraint(volumes.get(segment), volume_weight.getValue()); } contour.move(boundField, contour_timeStep.getValue()); } - else - { - final ArrayList<Callable<Object>> tasks = new ArrayList<Callable<Object>>(evolvingContoursAtTimeT.size()); + else { + final ArrayList<Callable<Object>> tasks = new ArrayList<>(evolvingContoursAtTimeT.size()); - for (final ActiveContour contour : evolvingContoursAtTimeT) - { + for (final ActiveContour contour : evolvingContoursAtTimeT) { final TrackSegment segment = trackGroup.getValue().getTrackSegmentWithDetection(contour); if (!region_cin.containsKey(segment) && region_weight.getValue() > EPSILON) updateRegionStatistics(); - tasks.add(new Callable<Object>() - { - @Override - public Object call() - { + tasks.add(() -> { + if (regul_weight.getValue() > EPSILON) { + contour.computeInternalForces(regul_weight.getValue()); + } - if (regul_weight.getValue() > EPSILON) - { - contour.computeInternalForces(regul_weight.getValue()); - } + if (Math.abs(edge_weight.getValue()) > EPSILON) { + contour.computeEdgeForces(edgeData, 0, edge_weight.getValue()); + } - if (Math.abs(edge_weight.getValue()) > EPSILON) - { - contour.computeEdgeForces(edgeData, 0, edge_weight.getValue()); - } + if (region_weight.getValue() > EPSILON) { + final double cin = region_cin.get(segment); + final double cout = region_cout.get(segment); + contour.computeRegionForces(regionData, 0, region_weight.getValue(), region_sensitivity.getValue(), cin, cout); + } - if (region_weight.getValue() > EPSILON) - { - final double cin = region_cin.get(segment); - final double cout = region_cout.get(segment); - contour.computeRegionForces(regionData, 0, region_weight.getValue(), region_sensitivity.getValue(), cin, cout); - } + if (axis_weight.getValue() > EPSILON) { + contour.computeAxisForces(axis_weight.getValue()); + } - if (axis_weight.getValue() > EPSILON) - { - contour.computeAxisForces(axis_weight.getValue()); - } + if (Math.abs(balloon_weight.getValue()) > EPSILON) { + contour.computeBalloonForces(balloon_weight.getValue()); + } - if (Math.abs(balloon_weight.getValue()) > EPSILON) - { - contour.computeBalloonForces(balloon_weight.getValue()); - } + if (coupling_flag.getValue()) { + // Don't move the contours just now: coupling feedback must be computed + // against ALL contours (including those which have already converged) + for (final ActiveContour otherContour : allContoursAtTimeT) { + if (otherContour == null || otherContour == contour) + continue; - if (coupling_flag.getValue()) - { - // Don't move the contours just now: coupling feedback must be computed - // against ALL contours (including those which have already converged) - for (final ActiveContour otherContour : allContoursAtTimeT) - { - if (otherContour == null || otherContour == contour) - continue; - - contour.computeFeedbackForces(otherContour); - } - - // we disabled volume constraint feature as it doesn't work and sometime end to - // crazy contour (Stephane) - // re-enabled volume constraint after taking into account both shrinking and - // growing contours instead of just growing ones(Daniel) - if (volume_constraint.getValue() && volumes.containsKey(segment)) - { - contour.computeVolumeConstraint(volumes.get(segment), volume_weight.getValue()); - } - } - else - { - // move contours asynchronously - contour.move(boundField, contour_timeStep.getValue()); + contour.computeFeedbackForces(otherContour); } - return contour; + // we disabled volume constraint feature as it doesn't work and sometime end to + // crazy contour (Stephane) + // re-enabled volume constraint after taking into account both shrinking and + // growing contours instead of just growing ones(Daniel) + if (volume_constraint.getValue() && volumes.containsKey(segment)) { + contour.computeVolumeConstraint(volumes.get(segment), volume_weight.getValue()); + } + } + else { + // move contours asynchronously + contour.move(boundField, contour_timeStep.getValue()); } + + return contour; }); } - try - { + try { executeMultiThread(tasks, null); } - catch (final Exception e) - { + catch (final Exception e) { throw new RuntimeException(e); } - if (coupling_flag.getValue()) - { + if (coupling_flag.getValue()) { // motion is synchronous, and can be done now for (final ActiveContour contour : evolvingContoursAtTimeT) contour.move(boundField, contour_timeStep.getValue()); @@ -1625,16 +1450,8 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block /** * Resample all contours to maintain a homogeneous resoltution - * - * @param evolvingContours - * @param allContours - * @param t - * @return <code>true</code> if the list of contours has changed (a contour has - * vanished or divided), <code>false</code> otherwise - * @throws InterruptedException */ - private void resampleContours(final int t) throws InterruptedException - { + private void resampleContours(/*final int t*/) throws InterruptedException { // if (isHeadLess()) System.out.println("=> Resampling contours..."); final VarBoolean loop = new VarBoolean("loop", true); @@ -1644,56 +1461,42 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block final int maxIterations = 10000; int itCount = 0; - while (loop.getValue()) - { + while (loop.getValue()) { if (itCount++ > maxIterations || Thread.currentThread().isInterrupted()) break; loop.setValue(false); - if (evolvingContoursAtTimeT.size() == 1) - { + if (evolvingContoursAtTimeT.size() == 1) { // no multi-threading needed - for (final ActiveContour contour : evolvingContoursAtTimeT) - { - if (new ReSampler(trackGroup.getValue(), contour, evolvingContoursAtTimeT, allContoursAtTimeT).call().booleanValue()) - { + for (final ActiveContour contour : evolvingContoursAtTimeT) { + if (new ReSampler(trackGroup.getValue(), contour, evolvingContoursAtTimeT, allContoursAtTimeT).call().booleanValue()) { change.setValue(true); loop.setValue(true); } } } - else - { - final List<ReSampler> tasks = new ArrayList<ReSampler>(evolvingContoursAtTimeT.size()); + else { + final List<ReSampler> tasks = new ArrayList<>(evolvingContoursAtTimeT.size()); for (final ActiveContour contour : evolvingContoursAtTimeT) tasks.add(new ReSampler(trackGroup.getValue(), contour, evolvingContoursAtTimeT, allContoursAtTimeT)); - try - { - for (final Future<Boolean> resampled : multiThreadService.invokeAll(tasks)) - { - if (resampled.get()) - { + try { + for (final Future<Boolean> resampled : multiThreadService.invokeAll(tasks)) { + if (resampled.get()) { change.setValue(true); loop.setValue(true); } } } - catch (final InterruptedException e) - { + catch (final InterruptedException e) { Thread.currentThread().interrupt(); } - catch (final ExecutionException e) - { + catch (final ExecutionException e) { e.printStackTrace(); throw new RuntimeException(e); } - catch (final RuntimeException e) - { - throw e; - } } } @@ -1701,13 +1504,11 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block updateRegionStatistics(); } - private void updateRegionStatistics() throws InterruptedException - { + private void updateRegionStatistics() throws InterruptedException { updateRegionStatistics(region_localise.getValue()); } - private void updateRegionStatistics(final boolean locally) throws InterruptedException - { + private void updateRegionStatistics(final boolean locally) throws InterruptedException { final int nbContours = allContoursAtTimeT.size(); if (nbContours == 0) @@ -1718,27 +1519,22 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block for (final BooleanMask2D slice : contourMask_buffer.mask.values()) Arrays.fill(slice.mask, false); - if (nbContours == 1) - { + if (nbContours == 1) { // use the current thread - for (final ActiveContour contour : allContoursAtTimeT) - { + for (final ActiveContour contour : allContoursAtTimeT) { new LocalRegionStatisticsComputer(contour, !locally).call(); } } - else - { + else { // use multiple threads - final Collection<Callable<Object>> updaters = new ArrayList<Callable<Object>>(allContoursAtTimeT.size()); + final Collection<Callable<Object>> updaters = new ArrayList<>(allContoursAtTimeT.size()); for (final ActiveContour contour : allContoursAtTimeT) updaters.add(new LocalRegionStatisticsComputer(contour, !locally)); - try - { + try { executeMultiThread(updaters, null); } - catch (final Exception e) - { + catch (final Exception e) { e.printStackTrace(); throw new RuntimeException(e); } @@ -1747,52 +1543,42 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block updateBackgroundStatistics(locally); } - private void updateBackgroundStatistics(final boolean locally) - { + private void updateBackgroundStatistics(final boolean locally) { final int nbContours = allContoursAtTimeT.size(); if (nbContours == 0) return; - if (locally) - { - if (nbContours == 1) - { + if (locally) { + if (nbContours == 1) { // use the current thread new LocalBackgroundStatisticsComputer(allContoursAtTimeT.iterator().next()).call(); } - else - { + else { // use multiple threads - final Collection<Callable<Object>> updaters = new ArrayList<Callable<Object>>(allContoursAtTimeT.size()); + final Collection<Callable<Object>> updaters = new ArrayList<>(allContoursAtTimeT.size()); for (final ActiveContour contour : allContoursAtTimeT) updaters.add(new LocalBackgroundStatisticsComputer(contour)); - try - { + try { executeMultiThread(updaters, null); } - catch (final Exception e) - { + catch (final Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } } - else - { + else { final double[] outs = new double[inputData.getSizeZ()]; - for (int z = 0; z < outs.length; z++) - { + for (int z = 0; z < outs.length; z++) { final boolean[] _mask = contourMask_buffer.mask.get(z).mask; final float[] _data = regionData.getDataXYAsFloat(0, z, 0); double outSumSlice = 0, outCptSlice = 0; - for (int i = 0; i < _mask.length; i++) - { - if (!_mask[i]) - { + for (int i = 0; i < _mask.length; i++) { + if (!_mask[i]) { outSumSlice += _data[i]; outCptSlice++; } @@ -1801,17 +1587,14 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block outs[z] = (outCptSlice == 0d) ? 0d : outSumSlice / outCptSlice; } - for (final ActiveContour contour : allContoursAtTimeT) - { + for (final ActiveContour contour : allContoursAtTimeT) { final TrackSegment segment = trackGroup.getValue().getTrackSegmentWithDetection(contour); - if (contour instanceof Polygon2D) - { + if (contour instanceof Polygon2D) { final double cout = outs[(int) Math.round(contour.getZ())]; region_cout.put(segment, cout); // System.out.println(" out: " + cout); } - else - { + else { final double cout = ArrayMath.mean(outs); region_cout.put(segment, cout); // System.out.println(" out: " + cout); @@ -1820,17 +1603,15 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } } - private void storeResult(final int t) throws UnsupportedOperationException, InterruptedException - { + private void storeResult(final int t) throws UnsupportedOperationException, InterruptedException { if (isHeadLess()) System.out.println("=> Storing result..."); final List<TrackSegment> segments = trackGroup.getValue().getTrackSegmentList(); // Append the current list to the existing one - final List<ROI> rois = new ArrayList<ROI>(Arrays.asList(roiOutput.getValue())); + final List<ROI> rois = new ArrayList<>(Arrays.asList(roiOutput.getValue())); - for (int i = 1; i <= segments.size(); i++) - { + for (int i = 1; i <= segments.size(); i++) { final TrackSegment segment = segments.get(i - 1); final ActiveContour contour = (ActiveContour) segment.getDetectionAtTime(t); @@ -1844,8 +1625,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block // output as ROIs final ROI roi = contour.toROI(output_roiType.getValue(), inputData); - if (roi != null) - { + if (roi != null) { // store id into ROI property roi.setProperty(CONTOUR_ID, Integer.toString(i)); // use contour name and color @@ -1861,15 +1641,12 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } // output labels - if (output_labels.isReferenced() || output_rois.getValue() == ExportROI.AS_LABELS) - { + if (output_labels.isReferenced() || output_rois.getValue() == ExportROI.AS_LABELS) { Sequence binSeq = output_labels.getValue(); - if (binSeq == null) - { + if (binSeq == null) { output_labels.setValue(binSeq = new Sequence()); } - if (binSeq.getImage(t, (int) contour.getZ()) == null) - { + if (binSeq.getImage(t, (int) contour.getZ()) == null) { binSeq.setImage(t, (int) contour.getZ(), new IcyBufferedImage(inputData.getWidth(), inputData.getHeight(), 1, DataType.USHORT)); } contour.toSequence(binSeq, i); @@ -1888,8 +1665,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } @Override - public void clean() - { + public void clean() { if (inputData != null) inputData.removeOverlay(overlay); if (trackGroup.getValue() != null) @@ -1919,8 +1695,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } @Override - public void declareInput(final VarList inputMap) - { + public void declareInput(final VarList inputMap) { inputMap.add("input sequence", input.getVariable()); inputMap.add("Input ROI", roiInput); inputMap.add("regularization: weight", regul_weight.getVariable()); @@ -1938,14 +1713,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block coupling_flag.setValue(true); inputMap.add("contour resolution", contour_resolution.getVariable()); - contour_resolution.addVarChangeListener(new EzVarListener<Double>() - { - @Override - public void variableChanged(final EzVar<Double> source, final Double newValue) - { - convergence_winSize.setValue((int) (100.0 / newValue)); - } - }); + contour_resolution.addVarChangeListener((source, newValue) -> convergence_winSize.setValue((int) (100.0 / newValue))); // inputMap.add("minimum object size", contour_minArea.getVariable()); inputMap.add("region bounds", evolution_bounds.getVariable()); @@ -1964,8 +1732,7 @@ public class ActiveContours extends EzPlug implements EzStoppable, Block } @Override - public void declareOutput(final VarList outputMap) - { + public void declareOutput(final VarList outputMap) { outputMap.add("Regions of interest", roiOutput); outputMap.add("Tracks", trackGroup); outputMap.add("Labels", output_labels); diff --git a/src/main/java/plugins/adufour/activecontours/ActiveContoursOverlay.java b/src/main/java/plugins/adufour/activecontours/ActiveContoursOverlay.java index b705653..b03fd03 100644 --- a/src/main/java/plugins/adufour/activecontours/ActiveContoursOverlay.java +++ b/src/main/java/plugins/adufour/activecontours/ActiveContoursOverlay.java @@ -16,105 +16,91 @@ import plugins.fab.trackmanager.TrackGroup; import plugins.fab.trackmanager.TrackSegment; import plugins.nchenouard.spot.Detection; -public class ActiveContoursOverlay extends Overlay implements SequenceListener -{ - private TrackGroup trackGroup; - - public ActiveContoursOverlay(TrackGroup trackGroup) - { +public class ActiveContoursOverlay extends Overlay implements SequenceListener { + private final TrackGroup trackGroup; + + public ActiveContoursOverlay(TrackGroup trackGroup) { super("Active contours"); this.trackGroup = trackGroup; } - + @Override - public void paint(Graphics2D g, Sequence sequence, IcyCanvas canvas) - { + public void paint(Graphics2D g, Sequence sequence, IcyCanvas canvas) { if (!Arrays.asList(sequence.getListeners()).contains(this)) sequence.addListener(this); - + int currentPositionT = canvas.getPositionT(); - - ArrayList<TrackSegment> segments = new ArrayList<TrackSegment>(trackGroup.getTrackSegmentList()); - - for (int i = 1; i <= segments.size(); i++) - { + + ArrayList<TrackSegment> segments = new ArrayList<>(trackGroup.getTrackSegmentList()); + + for (int i = 1; i <= segments.size(); i++) { TrackSegment segment = segments.get(i - 1); - + if (segment == null) continue; - - for (int d = 0; d < segment.getDetectionList().size(); d++) - { + + for (int d = 0; d < segment.getDetectionList().size(); d++) { ActiveContour contour = (ActiveContour) segment.getDetectionList().get(d); - + if (contour == null || contour.getT() != currentPositionT) continue; - + contour.paint(g, sequence, canvas); - + // 2D viewer ? - if (g != null) - { + if (g != null) { // in 2D, draw the contour number in its center (and mind the zoom factor) float f = (float) canvas.canvasToImageLogDeltaX(18); - + float x = (float) contour.getX(); float y = (float) contour.getY(); - + // adjust the text positioning x -= (i < 10 ? f / 2 : f); y += f / 2; - - g.drawString("" + i, x, y); + + g.drawString(String.valueOf(i), x, y); } } } - + } - + @Override - public void remove() - { - ArrayList<TrackSegment> segments = new ArrayList<TrackSegment>(trackGroup.getTrackSegmentList()); - - for (int i = 1; i <= segments.size(); i++) - { + public void remove() { + ArrayList<TrackSegment> segments = new ArrayList<>(trackGroup.getTrackSegmentList()); + + for (int i = 1; i <= segments.size(); i++) { TrackSegment segment = segments.get(i - 1); - + if (segment == null) continue; - - try - { + + try { ArrayList<Detection> detections = segment.getDetectionList(); - - if (detections != null) for (Detection detection : detections) - { + + if (detections != null) for (Detection detection : detections) { ((ActiveContour) detection).clean(); } } - catch (ConcurrentModificationException e) - { + catch (ConcurrentModificationException e) { // segment has probably changed while looking for a detection to paint // => ignore and wait for the next repaint } } - + super.remove(); trackGroup.getSequence().removeOverlay(this); } - + @Override - public void sequenceChanged(SequenceEvent sequenceEvent) - { + public void sequenceChanged(SequenceEvent sequenceEvent) { if (sequenceEvent.getSourceType() != SequenceEventSourceType.SEQUENCE_OVERLAY) return; - - if (sequenceEvent.getSource() == this && sequenceEvent.getType() == SequenceEventType.REMOVED) - { + + if (sequenceEvent.getSource() == this && sequenceEvent.getType() == SequenceEventType.REMOVED) { sequenceEvent.getSequence().removeListener(this); remove(); } } - + @Override - public void sequenceClosed(Sequence sequence) - { + public void sequenceClosed(Sequence sequence) { sequence.removeListener(this); remove(); } diff --git a/src/main/java/plugins/adufour/activecontours/DeformationProfiler.java b/src/main/java/plugins/adufour/activecontours/DeformationProfiler.java index f6c26f6..a20573d 100644 --- a/src/main/java/plugins/adufour/activecontours/DeformationProfiler.java +++ b/src/main/java/plugins/adufour/activecontours/DeformationProfiler.java @@ -1,7 +1,5 @@ package plugins.adufour.activecontours; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -54,47 +52,38 @@ import plugins.nchenouard.spot.Detection; /** * WARNING: this is an experimental class and may change in the future, use at * your own risks! - * + * * @author Alexandre Dufour */ -public class DeformationProfiler extends PluginTrackManagerProcessor implements PluginBundled -{ +public class DeformationProfiler extends PluginTrackManagerProcessor implements PluginBundled { private static XMLPreferences preferences = null; - private enum Descriptors - { + private enum Descriptors { None("None"), Width("Box width"), Height("Box height"), Depth("Box depth"), Norm1("Perimeter (2D) or surface area (3D)"), Norm2("Surface (2D) or Volume (3D)"), Roundness("Roundness (min radius / max radius)"), Convexity("Solidity (area / convex area)"), Smoothness("Contour smoothness"), Sphericity("Sphericity"), Elongation("Elongation factor"), Flatness("Flatness"); - private Descriptors(String name) - { + Descriptors(String name) { this.name = name; } final String name; @Override - public String toString() - { + public String toString() { return name; } } - private JComboBox<Descriptors> jComboDescriptors = new JComboBox<Descriptors>(Descriptors.values()); + private final JComboBox<Descriptors> jComboDescriptors = new JComboBox<>(Descriptors.values()); - private JButton jButtonSaveToVTK = new JButton("Export meshes to VTK files"); - - private JButton jButtonSaveShapeToXLS = new JButton("Export shape measures to XLS"); - - private JPanel chartPanel = new JPanel(); + private final JPanel chartPanel = new JPanel(); private double tScale; - public DeformationProfiler() - { + public DeformationProfiler() { if (preferences == null) preferences = getPreferencesRoot(); @@ -111,8 +100,10 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements JPanel panelExport = new JPanel(); panelExport.setLayout(new BoxLayout(panelExport, BoxLayout.X_AXIS)); + JButton jButtonSaveToVTK = new JButton("Export meshes to VTK files"); panelExport.add(jButtonSaveToVTK); panelExport.add(Box.createHorizontalStrut(5)); + JButton jButtonSaveShapeToXLS = new JButton("Export shape measures to XLS"); panelExport.add(jButtonSaveShapeToXLS); panel.add(panelExport); @@ -121,91 +112,57 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements panel.add(GuiUtil.createLineBoxPanel(Box.createHorizontalStrut(10), new JLabel("Plot descriptor:"), Box.createHorizontalStrut(10), jComboDescriptors, Box.createHorizontalStrut(10))); - jComboDescriptors.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - Compute(); - } - }); - - jButtonSaveToVTK.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - new Thread() - { - public void run() - { - // Restore last used folder - String vtkFolder = preferences.get("vtkFolder", null); - - String path = SaveDialog.chooseFile("Export shape information", vtkFolder, "Mesh"); - - if (path == null) - return; - - // store the folder in the preferences - preferences.put("vtkFolder", FileUtil.getDirectory(path)); - - AnnounceFrame message = new AnnounceFrame("Saving VTK files...", 0); - try - { - exportMeshToVTK(path); - } - finally - { - message.close(); - } - } - }.start(); + jComboDescriptors.addActionListener(e -> Compute()); + + jButtonSaveToVTK.addActionListener(e -> new Thread(() -> { + // Restore last used folder + String vtkFolder = preferences.get("vtkFolder", null); + + String path = SaveDialog.chooseFile("Export shape information", vtkFolder, "Mesh"); + + if (path == null) + return; + + // store the folder in the preferences + preferences.put("vtkFolder", FileUtil.getDirectory(path)); + + AnnounceFrame message = new AnnounceFrame("Saving VTK files...", 0); + try { + exportMeshToVTK(path); + } finally { + message.close(); } - }); - - jButtonSaveShapeToXLS.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - new Thread() - { - public void run() - { - // Restore last used folder - String xlsFolder = preferences.get("xlsFolder", null); - - String path = SaveDialog.chooseFile("Export shape information", xlsFolder, "Shape", ".xls"); - - if (path == null) - return; - - // store the folder in the preferences - preferences.put("xlsFolder", FileUtil.getDirectory(path)); - - AnnounceFrame message = new AnnounceFrame("Saving shape information...", 0); - try - { - exportShapeToXLS(path); - } - finally - { - message.close(); - } - } - }.start(); + }).start()); + + jButtonSaveShapeToXLS.addActionListener(e -> new Thread(() -> { + // Restore last used folder + String xlsFolder = preferences.get("xlsFolder", null); + + String path = SaveDialog.chooseFile("Export shape information", xlsFolder, "Shape", ".xls"); + + if (path == null) + return; + + // store the folder in the preferences + preferences.put("xlsFolder", FileUtil.getDirectory(path)); + + AnnounceFrame message = new AnnounceFrame("Saving shape information...", 0); + try { + exportShapeToXLS(path); + } finally { + message.close(); } - }); + }).start()); panel.add(chartPanel); } @Override - public void Close() - { + public void Close() { } @Override - public synchronized void Compute() - { + public synchronized void Compute() { chartPanel.removeAll(); if (!super.isEnabled()) @@ -216,12 +173,14 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements tScale = trackPool.getDisplaySequence().getTimeInterval(); - ChartPanel chart = null; + ChartPanel chart; Descriptors descriptor = (Descriptors) jComboDescriptors.getSelectedItem(); - switch (descriptor) - { + if (descriptor == null) + return; + + switch (descriptor) { case None: return; @@ -281,30 +240,26 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements break; default: - throw new UnsupportedOperationException( - "\"" + descriptor.toString() + "\" measure is not yet implemented"); + throw new UnsupportedOperationException("\"" + descriptor + "\" measure is not yet implemented"); } jComboDescriptors.setSelectedItem(Descriptors.None); - if (chart != null) - { - // replace default chart colors by detection colors (taken from t=0) - XYItemRenderer renderer = ((XYPlot) chart.getChart().getPlot()).getRenderer(); - for (TrackSegment ts : trackPool.getTrackSegmentList()) - renderer.setSeriesPaint(trackPool.getTrackIndex(ts), ts.getFirstDetection().getColor()); - chartPanel.add(chart); - } + // replace default chart colors by detection colors (taken from t=0) + XYItemRenderer renderer = ((XYPlot) chart.getChart().getPlot()).getRenderer(); + for (TrackSegment ts : trackPool.getTrackSegmentList()) + renderer.setSeriesPaint(trackPool.getTrackIndex(ts), ts.getFirstDetection().getColor()); + + chartPanel.add(chart); super.panel.updateUI(); } - private double[][] computeBoxWidth() - { + private double[][] computeBoxWidth() { final Sequence seq = trackPool.getDisplaySequence(); final int sizeT; - // FIX: better to use last detection time point in this case + // FIXME: better to use last detection time point in this case if (seq == null) sizeT = trackPool.getLastDetectionTimePoint() + 1; else @@ -312,12 +267,10 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements double[][] result = new double[trackPool.getTrackSegmentList().size()][sizeT]; - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { int trackIndex = trackPool.getTrackIndex(ts); - for (Detection det : ts.getDetectionList()) - { + for (Detection det : ts.getDetectionList()) { if (!(det instanceof ActiveContour)) continue; @@ -330,12 +283,11 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements return result; } - private double[][] computeBoxHeight() - { + private double[][] computeBoxHeight() { final Sequence seq = trackPool.getDisplaySequence(); final int sizeT; - // FIX: better to use last detection time point in this case + // FIXME: better to use last detection time point in this case if (seq == null) sizeT = trackPool.getLastDetectionTimePoint() + 1; else @@ -343,12 +295,10 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements double[][] result = new double[trackPool.getTrackSegmentList().size()][sizeT]; - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { int trackIndex = trackPool.getTrackIndex(ts); - for (Detection det : ts.getDetectionList()) - { + for (Detection det : ts.getDetectionList()) { if (!(det instanceof ActiveContour)) continue; @@ -361,12 +311,11 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements return result; } - private double[][] computeBoxDepth() - { + private double[][] computeBoxDepth() { final Sequence seq = trackPool.getDisplaySequence(); final int sizeT; - // FIX: better to use last detection time point in this case + // FIXME: better to use last detection time point in this case if (seq == null) sizeT = trackPool.getLastDetectionTimePoint() + 1; else @@ -374,12 +323,10 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements double[][] result = new double[trackPool.getTrackSegmentList().size()][sizeT]; - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { int trackIndex = trackPool.getTrackIndex(ts); - for (Detection det : ts.getDetectionList()) - { + for (Detection det : ts.getDetectionList()) { if (!(det instanceof ActiveContour)) continue; @@ -392,10 +339,8 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements return result; } - private void exportShapeToXLS(String xlsPath) - { - try - { + private void exportShapeToXLS(String xlsPath) { + try { WritableWorkbook wb = XLSUtil.createWorkbook(xlsPath); saveToXls(wb, "Surface area", computeDimension(1)); @@ -408,27 +353,19 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements wb.write(); wb.close(); } - catch (IOException e) - { - e.printStackTrace(); - } - catch (WriteException e) - { + catch (IOException | WriteException e) { e.printStackTrace(); } } - private void exportMeshToVTK(String vtkPath) - { + private void exportMeshToVTK(String vtkPath) { int cpt = 0; - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { String filePrefix = "_#" + (cpt < 1000 ? "0" : ""); filePrefix += (cpt < 100 ? "0" : ""); filePrefix += (cpt < 10 ? "0" : "") + cpt; - for (Detection det : ts.getDetectionList()) - { + for (Detection det : ts.getDetectionList()) { if (!(det instanceof Mesh3D)) continue; @@ -436,8 +373,7 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements String fileName = filePrefix + "_T" + (t < 10 ? "000" : t < 100 ? "00" : t < 1000 ? "0" : "") + t + ".vtk"; - if (det.getDetectionType() != Detection.DETECTIONTYPE_VIRTUAL_DETECTION) - { + if (det.getDetectionType() != Detection.DETECTIONTYPE_VIRTUAL_DETECTION) { ((Mesh3D) det).mesh.saveToVTK(new File(vtkPath + fileName)); } } @@ -446,18 +382,15 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements } } - private ChartPanel createChartPanel(double[][] array, String title, String xLabel, String yLabel) - { + private ChartPanel createChartPanel(double[][] array, String title, String xLabel, String yLabel) { XYSeriesCollection plot = new XYSeriesCollection(); - for (int track = 0; track < array.length; track++) - { + for (int track = 0; track < array.length; track++) { XYSeries series = new XYSeries(track); double[] row = array[track]; - for (int frame = 0; frame < row.length; frame++) - { + for (int frame = 0; frame < row.length; frame++) { double value = row[frame]; if (value != 0) @@ -467,17 +400,35 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements plot.addSeries(series); } - JFreeChart chart = ChartFactory.createXYLineChart(title, xLabel, yLabel, plot, PlotOrientation.VERTICAL, // orientation + JFreeChart chart = ChartFactory.createXYLineChart( + title, + xLabel, + yLabel, + plot, + PlotOrientation.VERTICAL, // orientation true, // include legend true, // tooltips false // urls ); - return new ChartPanel(chart, 500, 300, 500, 300, 500, 300, false, false, true, true, true, true); + return new ChartPanel( + chart, + 500, + 300, + 500, + 300, + 500, + 300, + false, + false, + true, + true, + true, + true + ); } - private void saveToXls(WritableWorkbook book, String pageTitle, double[][] array) - { + private void saveToXls(WritableWorkbook book, String pageTitle, double[][] array) { WritableSheet sheet = XLSUtil.createNewPage(book, pageTitle); XLSUtil.setCellString(sheet, 0, 0, "Track \\ Time"); @@ -485,19 +436,18 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements final Sequence seq = trackPool.getDisplaySequence(); final int sizeT; - // FIX: better to use last detection time point in this case + // FIXME: better to use last detection time point in this case if (seq == null) sizeT = trackPool.getLastDetectionTimePoint() + 1; else sizeT = seq.getSizeT(); - + // time labels for (int t = 0; t < sizeT; t++) XLSUtil.setCellNumber(sheet, t + 1, 0, t * tScale); // indexes + data - for (int i = 0; i < trackPool.getTrackSegmentList().size(); i++) - { + for (int i = 0; i < trackPool.getTrackSegmentList().size(); i++) { XLSUtil.setCellNumber(sheet, 0, i + 1, i); double[] row = array[i]; for (int j = 0; j < row.length; j++) @@ -511,15 +461,12 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements * the difference between the object and its convex hull, expressed as a * percentage of the convex hull. Hence, the value is 1 if the object is convex, * and lower than 1 otherwise - * - * @return */ - private double[][] computeConvexity() - { + private double[][] computeConvexity() { final Sequence seq = trackPool.getDisplaySequence(); final int sizeT; - // FIX: better to use last detection time point in this case + // FIXME: better to use last detection time point in this case if (seq == null) sizeT = trackPool.getLastDetectionTimePoint() + 1; else @@ -527,12 +474,10 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements double[][] result = new double[trackPool.getTrackSegmentList().size()][sizeT]; - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { int trackIndex = trackPool.getTrackIndex(ts); - for (Detection det : ts.getDetectionList()) - { + for (Detection det : ts.getDetectionList()) { if (!(det instanceof Mesh3D)) continue; @@ -553,8 +498,7 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements Vector3d v13 = new Vector3d(); Vector3d cross = new Vector3d(); - for (int[] face : hullFaces) - { + for (int[] face : hullFaces) { Point3d v1 = hullPoints[face[0]]; Point3d v2 = hullPoints[face[1]]; Point3d v3 = hullPoints[face[2]]; @@ -576,12 +520,11 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements return result; } - private double[][] computeDimension(int order) - { + private double[][] computeDimension(int order) { final Sequence seq = trackPool.getDisplaySequence(); final int sizeT; - // FIX: better to use last detection time point in this case + // FIXME: better to use last detection time point in this case if (seq == null) sizeT = trackPool.getLastDetectionTimePoint() + 1; else @@ -589,19 +532,15 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements double[][] result = new double[trackPool.getTrackSegmentList().size()][sizeT]; - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { int trackIndex = trackPool.getTrackIndex(ts); - if (result.length > trackIndex) - { - for (Detection det : ts.getDetectionList()) - { + if (result.length > trackIndex) { + for (Detection det : ts.getDetectionList()) { if (!(det instanceof ActiveContour)) continue; - if (sizeT > det.getT()) - { + if (sizeT > det.getT()) { double value = ((ActiveContour) det).getDimension(order); result[trackIndex][det.getT()] = value; } @@ -612,12 +551,11 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements return result; } - private double[][] computeElongation() - { + private double[][] computeElongation() { final Sequence seq = trackPool.getDisplaySequence(); final int sizeT; - // FIX: better to use last detection time point in this case + // FIXME: better to use last detection time point in this case if (seq == null) sizeT = trackPool.getLastDetectionTimePoint() + 1; else @@ -625,12 +563,10 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements double[][] result = new double[trackPool.getTrackSegmentList().size()][sizeT]; - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { int trackIndex = trackPool.getTrackIndex(ts); - for (Detection det : ts.getDetectionList()) - { + for (Detection det : ts.getDetectionList()) { if (!(det instanceof Mesh3D)) continue; @@ -645,12 +581,11 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements return result; } - private double[][] computeFlatness() - { + private double[][] computeFlatness() { final Sequence seq = trackPool.getDisplaySequence(); final int sizeT; - // FIX: better to use last detection time point in this case + // FIXME: better to use last detection time point in this case if (seq == null) sizeT = trackPool.getLastDetectionTimePoint() + 1; else @@ -658,12 +593,10 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements double[][] result = new double[trackPool.getTrackSegmentList().size()][sizeT]; - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { int trackIndex = trackPool.getTrackIndex(ts); - for (Detection det : ts.getDetectionList()) - { + for (Detection det : ts.getDetectionList()) { if (!(det instanceof Mesh3D)) continue; @@ -698,17 +631,14 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements * interpret than the raw roughness: its value ranges from 0 to 1, where values * close to 1 indicate a smooth object, while values close to 0 indicate objects * with a rough surface (e.g. spikes) - * - * @return */ - private double[][] computeSmoothness() - { + private double[][] computeSmoothness() { ExecutorService service = Executors.newCachedThreadPool(); final Sequence seq = trackPool.getDisplaySequence(); final int sizeT; - // FIX: better to use last detection time point in this case + // FIXME: better to use last detection time point in this case if (seq == null) sizeT = trackPool.getLastDetectionTimePoint() + 1; else @@ -716,85 +646,71 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements final double[][] result = new double[trackPool.getTrackSegmentList().size()][sizeT]; - ArrayList<Future<?>> results = new ArrayList<Future<?>>(); + ArrayList<Future<?>> results = new ArrayList<>(); - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { final int trackIndex = trackPool.getTrackIndex(ts); - for (Detection det : ts.getDetectionList()) - { + for (Detection det : ts.getDetectionList()) { if (!(det instanceof Mesh3D)) continue; final ROI3DTriangularMesh mesh = ((Mesh3D) det).mesh; // final double samplingDistance = contour.sampling.getValue() * 3; - results.add(service.submit(new Runnable() - { - @Override - public void run() - { - // Point3d center = contour.getMassCenter(); + results.add(service.submit(() -> { + // Point3d center = contour.getMassCenter(); - double[] localRoughness = new double[mesh.getNumberOfVertices(true)]; + double[] localRoughness = new double[mesh.getNumberOfVertices(true)]; - int n = 0; + int n = 0; - // compute local roughness for each mesh point - for (Vertex3D v1 : mesh.getVertices()) - { - if (v1 == null) - continue; + // compute local roughness for each mesh point + for (Vertex3D v1 : mesh.getVertices()) { + if (v1 == null) + continue; - // 1) Build a neighborhood for each vertex w.r.t. the sampling distance - ArrayList<Vertex3D> neighborhood = new ArrayList<Vertex3D>(); - // neighborhood.add(v1); + // 1) Build a neighborhood for each vertex w.r.t. the sampling distance + ArrayList<Vertex3D> neighborhood = new ArrayList<>(); + // neighborhood.add(v1); - // add the first ring of neighbors - for (Integer n1 : v1.neighbors) - { - Vertex3D vn1 = mesh.getVertex(n1); - if (vn1 == v1 || neighborhood.contains(vn1)) - continue; + // add the first ring of neighbors + for (Integer n1 : v1.neighbors) { + Vertex3D vn1 = mesh.getVertex(n1); + if (vn1 == v1 || neighborhood.contains(vn1)) + continue; - neighborhood.add(vn1); + neighborhood.add(vn1); - // add the second ring of neighbors - for (Integer n2 : vn1.neighbors) - { - Vertex3D vn2 = mesh.getVertex(n2); - if (vn2 == v1 || vn2 == vn1 || neighborhood.contains(vn2)) - continue; + // add the second ring of neighbors + for (Integer n2 : vn1.neighbors) { + Vertex3D vn2 = mesh.getVertex(n2); + if (vn2 == v1 || vn2 == vn1 || neighborhood.contains(vn2)) + continue; - neighborhood.add(vn2); - } + neighborhood.add(vn2); } + } - // 2) Compute local roughness for the current neighborhood - - double[] distances = new double[neighborhood.size()]; - for (int i = 0; i < distances.length; i++) - { - distances[i] = neighborhood.get(i).normal.angle(v1.normal); - } + // 2) Compute local roughness for the current neighborhood - localRoughness[n++] = ArrayMath.std(distances, false) / ArrayMath.mean(distances); + double[] distances = new double[neighborhood.size()]; + for (int i = 0; i < distances.length; i++) { + distances[i] = neighborhood.get(i).normal.angle(v1.normal); } - result[trackIndex][mesh.getT()] = 100 / (1 + ArrayMath.mean(localRoughness)); + localRoughness[n++] = ArrayMath.std(distances, false) / ArrayMath.mean(distances); } + + result[trackIndex][mesh.getT()] = 100 / (1 + ArrayMath.mean(localRoughness)); })); } } - for (Future<?> futureResult : results) - { - try - { + for (Future<?> futureResult : results) { + try { futureResult.get(); } - catch (Exception e) - { + catch (Exception e) { e.printStackTrace(); } } @@ -825,15 +741,12 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements * inscribed (resp. bounding) sphere, and may result in both cases to a much * lower roundness than otherwise expected. For a more robust measure, consider * using the sphericity (see {@link #computeSphericity()}). - * - * @return */ - private double[][] computeRoundness() - { + private double[][] computeRoundness() { final Sequence seq = trackPool.getDisplaySequence(); final int sizeT; - // FIX: better to use last detection time point in this case + // FIXME: better to use last detection time point in this case if (seq == null) sizeT = trackPool.getLastDetectionTimePoint() + 1; else @@ -841,12 +754,10 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements double[][] result = new double[trackPool.getTrackSegmentList().size()][sizeT]; - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { int trackIndex = trackPool.getTrackIndex(ts); - for (Detection det : ts.getDetectionList()) - { + for (Detection det : ts.getDetectionList()) { if (!(det instanceof Mesh3D)) continue; @@ -882,15 +793,12 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements * /><br/> * Image modified from "Krumbein, W.C., and Sloss, L.L., Stratigraphy and * Sedimentation, 1956, Freeman and Company, San Francisco CA" - * - * @return */ - private double[][] computeSphericity() - { + private double[][] computeSphericity() { final Sequence seq = trackPool.getDisplaySequence(); final int sizeT; - // FIX: better to use last detection time point in this case + // FIXME: better to use last detection time point in this case if (seq == null) sizeT = trackPool.getLastDetectionTimePoint() + 1; else @@ -898,12 +806,10 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements double[][] result = new double[trackPool.getTrackSegmentList().size()][sizeT]; - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { int trackIndex = trackPool.getTrackIndex(ts); - for (Detection det : ts.getDetectionList()) - { + for (Detection det : ts.getDetectionList()) { if (!(det instanceof Mesh3D)) continue; @@ -994,14 +900,12 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements // } @Override - public void displaySequenceChanged() - { + public void displaySequenceChanged() { } @Override - public String getMainPluginClassName() - { + public String getMainPluginClassName() { return ActiveContours.class.getName(); } @@ -1009,36 +913,37 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements * Compute the best fitting ellipsoid for the given component.<br> * This method is adapted from Yury Petrov's Matlab code and ported to Java by * the BoneJ project - * - * @param in_points - * the points to fit - * @param out_center - * (set to null if not wanted) the calculated ellipsoid - * center - * @param out_radii - * (set to null if not wanted) the calculated ellipsoid - * radius in each eigen-direction - * @param out_eigenVectors - * (set to null if not wanted) the calculated ellipsoid - * eigen-vectors - * @param out_equation - * (set to null if not wanted) an array of size 9 - * containing the calculated ellipsoid equation - * @throws IllegalArgumentException - * if the number of points in the component is - * too low (minimum is 9) - * @throws SingularMatrixException - * if the component is flat (i.e. lies in a 2D - * plane) + * + * @param in_points the points to fit + * @param out_center (set to null if not wanted) the calculated ellipsoid + * center + * @param out_radii (set to null if not wanted) the calculated ellipsoid + * radius in each eigen-direction + * @param out_eigenVectors (set to null if not wanted) the calculated ellipsoid + * eigen-vectors + * @param out_equation (set to null if not wanted) an array of size 9 + * containing the calculated ellipsoid equation + * @throws IllegalArgumentException if the number of points in the component is + * too low (minimum is 9) + * @throws SingularMatrixException if the component is flat (i.e. lies in a 2D + * plane) */ - public static void computeEllipse(Iterable<Point3d> in_points, Point3d out_center, Point3d out_radii, - Vector3d[] out_eigenVectors, double[] out_equation) throws IllegalArgumentException - { - ArrayList<double[]> rawMatrix = new ArrayList<double[]>(); - for (Point3d p : in_points) - { - rawMatrix.add(new double[] {p.x * p.x, p.y * p.y, p.z * p.z, p.x * p.y * 2.0, p.x * p.z * 2.0, - p.y * p.z * 2.0, p.x * 2.0, p.y * 2.0, p.z * 2.0}); + public static void computeEllipse(Iterable<Point3d> in_points, Point3d out_center, Point3d out_radii, Vector3d[] out_eigenVectors, double[] out_equation) throws IllegalArgumentException { + ArrayList<double[]> rawMatrix = new ArrayList<>(); + for (Point3d p : in_points) { + rawMatrix.add( + new double[]{ + p.x * p.x, + p.y * p.y, + p.z * p.z, + p.x * p.y * 2.0, + p.x * p.z * 2.0, + p.y * p.z * 2.0, + p.x * 2.0, + p.y * 2.0, + p.z * 2.0 + } + ); } double[][] _rawMatrix = rawMatrix.toArray(new double[rawMatrix.size()][9]); @@ -1046,19 +951,21 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements Matrix ones = ones(_rawMatrix.length, 1); Matrix V; - try - { + try { V = D.transpose().times(D).inverse().times(D.transpose().times(ones)); } - catch (RuntimeException e) - { + catch (RuntimeException e) { throw new SingularMatrixException("The component is most probably flat (i.e. lies in a 2D plane)"); } double[] v = V.getColumnPackedCopy(); - double[][] a = {{v[0], v[3], v[4], v[6]}, {v[3], v[1], v[5], v[7]}, {v[4], v[5], v[2], v[8]}, - {v[6], v[7], v[8], -1.0D}}; + double[][] a = { + {v[0], v[3], v[4], v[6]}, + {v[3], v[1], v[5], v[7]}, + {v[4], v[5], v[2], v[8]}, + {v[6], v[7], v[8], -1.0D} + }; Matrix A = new Matrix(a); Matrix C = A.getMatrix(0, 2, 0, 2).times(-1.0D).inverse().times(V.getMatrix(6, 8, 0, 0)); Matrix T = Matrix.identity(4, 4); @@ -1078,8 +985,7 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements if (out_center != null) out_center.set(C.get(0, 0), C.get(1, 0), C.get(2, 0)); - if (out_eigenVectors != null && out_eigenVectors.length == 3) - { + if (out_eigenVectors != null && out_eigenVectors.length == 3) { out_eigenVectors[0] = new Vector3d(eVec.get(0, 0), eVec.get(0, 1), eVec.get(0, 2)); out_eigenVectors[1] = new Vector3d(eVec.get(1, 0), eVec.get(1, 1), eVec.get(1, 2)); out_eigenVectors[2] = new Vector3d(eVec.get(2, 0), eVec.get(2, 1), eVec.get(2, 2)); @@ -1088,19 +994,16 @@ public class DeformationProfiler extends PluginTrackManagerProcessor implements System.arraycopy(v, 0, out_equation, 0, v.length); } - private static Matrix diag(Matrix matrix) - { + private static Matrix diag(Matrix matrix) { int min = Math.min(matrix.getRowDimension(), matrix.getColumnDimension()); double[][] diag = new double[min][1]; - for (int i = 0; i < min; i++) - { + for (int i = 0; i < min; i++) { diag[i][0] = matrix.get(i, i); } return new Matrix(diag); } - private static Matrix ones(int m, int n) - { + private static Matrix ones(int m, int n) { double[][] array = new double[m][n]; for (double[] row : array) Arrays.fill(row, 1.0); diff --git a/src/main/java/plugins/adufour/activecontours/Mesh3D.java b/src/main/java/plugins/adufour/activecontours/Mesh3D.java index 485c9d2..8341555 100644 --- a/src/main/java/plugins/adufour/activecontours/Mesh3D.java +++ b/src/main/java/plugins/adufour/activecontours/Mesh3D.java @@ -11,6 +11,7 @@ import javax.vecmath.Point3d; import javax.vecmath.Tuple3d; import javax.vecmath.Vector3d; +import icy.system.IcyExceptionHandler; import org.w3c.dom.Node; import com.jogamp.graph.geom.Triangle; @@ -23,7 +24,6 @@ import icy.roi.ROI; import icy.roi.ROI3D; import icy.roi.ROIUtil; import icy.sequence.Sequence; -import icy.type.DataType; import icy.type.rectangle.Rectangle3D; import plugins.adufour.activecontours.ActiveContours.ROIType; import plugins.adufour.activecontours.SlidingWindow.Operation; @@ -40,38 +40,32 @@ import plugins.kernel.roi.roi3d.ROI3DArea; * accurate active contour computation so pixel size is handled on Mesh3D side and not directly in the ActiveMesh ROI which should be expressed in <i>voxel</i> * as any ROI. */ -public class Mesh3D extends ActiveContour -{ +public class Mesh3D extends ActiveContour { /** * an active vertex is a vertex that carries motion information - * + * * @author Alexandre Dufour */ - private static class ActiveVertex extends Vertex3D - { + private static class ActiveVertex extends Vertex3D { public final Vector3d imageForces = new Vector3d(); public final Vector3d internalForces = new Vector3d(); public final Vector3d feedbackForces = new Vector3d(); public final Vector3d volumeConstraint = new Vector3d(); - public ActiveVertex(ActiveVertex v) - { + public ActiveVertex(ActiveVertex v) { super(v.position, v.neighbors); } - public ActiveVertex(Point3d position) - { + public ActiveVertex(Point3d position) { this(position, 0); } - public ActiveVertex(Point3d position, int nbNeighbors) - { + public ActiveVertex(Point3d position, int nbNeighbors) { super(position, nbNeighbors); } @Override - public Vertex3D clone() - { + public Vertex3D clone() { return new ActiveVertex(this); } } @@ -79,18 +73,15 @@ public class Mesh3D extends ActiveContour /** * An ActiveMesh is defined here as a 3D surface mesh with {@link Triangle} as elementary face * and {@link ActiveVertex} as elementary vertex - * + * * @author Alexandre Dufour */ - public static class ActiveMesh extends ROI3DTriangularMesh - { - public ActiveMesh() - { + public static class ActiveMesh extends ROI3DTriangularMesh { + public ActiveMesh() { } - public ActiveMesh(double sampling, ROI3D roi) - { + public ActiveMesh(double sampling, ROI3D roi) { super(sampling, roi); // setName("Contour (" + roi.getName() + ")"); @@ -99,8 +90,7 @@ public class Mesh3D extends ActiveContour } @Override - public ActiveVertex createVertex(Point3d position) - { + public ActiveVertex createVertex(Point3d position) { return new ActiveVertex(position); } } @@ -116,31 +106,27 @@ public class Mesh3D extends ActiveContour /** * DO NOT USE! This constructor is for XML loading purposes only */ - public Mesh3D() - { + public Mesh3D() { super(); mesh = new ActiveMesh(); pixelSize = new Point3d(); - overlays = new HashMap<IcyCanvas, Overlay>(); + overlays = new HashMap<>(); isRemoving = false; } /** * Creates a clone of the specified contour - * - * @param contour */ - public Mesh3D(Mesh3D contour) - { + public Mesh3D(Mesh3D contour) { super(contour.sampling, new SlidingWindow(contour.convergence.getSize())); mesh = (ActiveMesh) contour.mesh.clone(); pixelSize = new Point3d(); setName(contour.getName()); - overlays = new HashMap<IcyCanvas, Overlay>(); + overlays = new HashMap<>(); isRemoving = false; setColor(contour.getColor()); @@ -148,8 +134,7 @@ public class Mesh3D extends ActiveContour updateMetaData(); } - public Mesh3D(Var<Double> sampling, Tuple3d pixelSize, ROI3D roi, SlidingWindow convergenceWindow) - { + public Mesh3D(Var<Double> sampling, Tuple3d pixelSize, ROI3D roi, SlidingWindow convergenceWindow) { super(sampling, convergenceWindow); mesh = new ActiveMesh(sampling.getValue(), roi); @@ -158,7 +143,7 @@ public class Mesh3D extends ActiveContour this.pixelSize = pixelSize; - overlays = new HashMap<IcyCanvas, Overlay>(); + overlays = new HashMap<>(); isRemoving = false; updateMetaData(); @@ -169,19 +154,15 @@ public class Mesh3D extends ActiveContour * to keep the contour shape along its principal axis <br> * WARNING: this method directly update the array of final forces used to displace the contour * points. It should be used among the last to keep it most effective - * - * @param weight */ @Override - void computeAxisForces(double weight) - { + void computeAxisForces(double weight) { final Vector3d axis = mesh.getMajorAxis(null); // To drive the contour along the main object axis, each displacement // vector is scaled by the scalar product between its normal and the main axis. - for (Vertex3D v : mesh.getVertices()) - { + for (Vertex3D v : mesh.getVertices()) { if (v == null) continue; @@ -202,10 +183,8 @@ public class Mesh3D extends ActiveContour } @Override - void computeBalloonForces(double weight) - { - for (Vertex3D v : mesh.getVertices()) - { + void computeBalloonForces(double weight) { + for (Vertex3D v : mesh.getVertices()) { if (v == null) continue; @@ -222,19 +201,14 @@ public class Mesh3D extends ActiveContour /** * Update edge term of the contour evolution according to the image gradient - * - * @param weight - * @param edgeData */ @Override - void computeEdgeForces(Sequence edgeData, int channel, double weight) - { + void computeEdgeForces(Sequence edgeData, int channel, double weight) { final Vector3d grad = new Vector3d(); final Point3d prev = new Point3d(); final Point3d p = new Point3d(); - for (Vertex3D v : mesh.getVertices()) - { + for (Vertex3D v : mesh.getVertices()) { if (v == null) continue; @@ -264,9 +238,7 @@ public class Mesh3D extends ActiveContour } @Override - void computeRegionForces(Sequence imageData, int channel, double weight, double sensitivity, double cin, - double cout) - { + void computeRegionForces(Sequence imageData, int channel, double weight, double sensitivity, double cin, double cout) { // sensitivity should be high for dim objects, low for bright objects... // ... but none of the following options work properly // sensitivity *= 1/(1+cin); @@ -277,8 +249,7 @@ public class Mesh3D extends ActiveContour final Vector3d regionForce = new Vector3d(); final double adjWeight = weight * sampling.getValue(); - for (Vertex3D v : mesh.getVertices()) - { + for (Vertex3D v : mesh.getVertices()) { if (v == null) continue; @@ -307,13 +278,11 @@ public class Mesh3D extends ActiveContour } @Override - void computeInternalForces(double weight) - { + void computeInternalForces(double weight) { final Vector3d internalForce = new Vector3d(); final double adjWeight = weight / sampling.getValue(); - for (Vertex3D v : mesh.getVertices()) - { + for (Vertex3D v : mesh.getVertices()) { if (v == null) continue; @@ -336,8 +305,8 @@ public class Mesh3D extends ActiveContour } // TODO take into account weight - void computeVolumeConstraint(double targetVolume, double weight) - { + @Override + void computeVolumeConstraint(double targetVolume, double weight) { // 1) compute the difference between target and current volume final double volumeDiff = targetVolume - getDimension(2); // if (volumeDiff > 0): contour too small, should no longer shrink @@ -346,8 +315,7 @@ public class Mesh3D extends ActiveContour final Vector3d avgFeedback = new Vector3d(); int cpt = 0; - for (Vertex3D v : mesh.getVertices()) - { + for (Vertex3D v : mesh.getVertices()) { if (v == null) continue; @@ -366,15 +334,13 @@ public class Mesh3D extends ActiveContour // if forces have opposite direction (forceNorm < 0): contour is shrinking // estimate an average feedback - if ((forceNorm > 0) && (volumeDiff < 0)) - { + if ((forceNorm > 0) && (volumeDiff < 0)) { avgFeedback.add(feedbackForce); cpt++; } } - if (avgFeedback.length() > 0) - { + if (avgFeedback.length() > 0) { avgFeedback.scale(1d / cpt); avgFeedback.scale(Math.abs(volumeDiff / targetVolume) / 1.5); @@ -384,8 +350,7 @@ public class Mesh3D extends ActiveContour // } // move the entire mesh (ugly, but amazingly efficient!!) - for (Vertex3D v : mesh.getVertices()) - { + for (Vertex3D v : mesh.getVertices()) { if (v != null) ((ActiveVertex) v).volumeConstraint.add(avgFeedback); } @@ -395,19 +360,16 @@ public class Mesh3D extends ActiveContour /** * Computes the feedback forces yielded by the penetration of the current contour into the * target contour - * - * @param target - * the contour that is being penetrated + * + * @param target the contour that is being penetrated * @return the number of actual point-mesh intersection tests */ @Override - int computeFeedbackForces(ActiveContour target) - { + int computeFeedbackForces(ActiveContour target) { final Vector3d feedbackForce = new Vector3d(); int tests = 0; - for (Vertex3D v : mesh.getVertices()) - { + for (Vertex3D v : mesh.getVertices()) { if (v == null) continue; @@ -421,8 +383,7 @@ public class Mesh3D extends ActiveContour tests++; final double feedback = target.getDistanceToEdge(v.position); - if (feedback > 0) - { + if (feedback > 0) { feedbackForce.set(v.normal); feedbackForce.scale(-feedback * 10); av.feedbackForces.add(feedbackForce); @@ -437,10 +398,8 @@ public class Mesh3D extends ActiveContour return tests; } - public double getCurvature(Point3d pt) - { - for (Vertex3D v : mesh.getVertices()) - { + public double getCurvature(Point3d pt) { + for (Vertex3D v : mesh.getVertices()) { if (v == null) continue; @@ -449,8 +408,7 @@ public class Mesh3D extends ActiveContour final Vector3d sum = new Vector3d(); final Vector3d diff = new Vector3d(); - for (Integer n : v.neighbors) - { + for (Integer n : v.neighbors) { final Point3d neighbor = mesh.getVertex(n).position; diff.sub(neighbor, pt); @@ -464,16 +422,20 @@ public class Mesh3D extends ActiveContour return 0d; } - public double getDimension(int order) - { - switch (order) - { - case 0: - return mesh.getNumberOfVertices(true); - case 1: - return mesh.getNumberOfContourPoints(); - case 2: - return mesh.getNumberOfPoints(); + @Override + public double getDimension(int order) { + try { + switch (order) { + case 0: + return mesh.getNumberOfVertices(true); + case 1: + return mesh.getNumberOfContourPoints(); + case 2: + return mesh.getNumberOfPoints(); + } + } + catch (InterruptedException e) { + IcyExceptionHandler.showErrorMessage(e, false); } return Double.NaN; } @@ -483,18 +445,16 @@ public class Mesh3D extends ActiveContour // return mesh.getMassCenter(convertToImageSpace); // } - Point3d getMassCenter() - { + Point3d getMassCenter() { // here we always want in metrics unit return mesh.getMassCenter(pixelSize); } /** * @return The major axis of this contour, i.e. an unnormalized vector formed of the two most - * distant contour points + * distant contour points */ - public Vector3d getMajorAxis() - { + public Vector3d getMajorAxis() { // here we always want in metrics unit return mesh.getMajorAxis(pixelSize); } @@ -502,19 +462,14 @@ public class Mesh3D extends ActiveContour /** * Calculates the 3D image value at the given coordinates (in voxel units) by tri-linear * interpolation - * - * @param imageFloat - * the image to sample (must be of type {@link DataType#FLOAT}) - * @param x - * the X-coordinate of the point - * @param y - * the Y-coordinate of the point - * @param z - * the Z-coordinate of the point + * + * @param data the image to sample + * @param x the X-coordinate of the point + * @param y the Y-coordinate of the point + * @param z the Z-coordinate of the point * @return the interpolated image value at the given coordinates */ - private static double getPixelValue(Sequence data, double x, double y, double z) - { + private static double getPixelValue(Sequence data, double x, double y, double z) { return data.getDataInterpolated(0, z, 0, y, x); // // "center" the coordinates to the center of the pixel @@ -568,53 +523,45 @@ public class Mesh3D extends ActiveContour } @Override - public double getX() - { + public double getX() { // get this in pixel units return mesh.getMassCenter(null).x; } @Override - public double getY() - { + public double getY() { // get this in pixel units return mesh.getMassCenter(null).y; } @Override - public double getZ() - { + public double getZ() { // get this in pixel units return mesh.getMassCenter(null).z; } @Override - public void setT(int t) - { + public void setT(int t) { super.setT(t); mesh.setT(t); } @Override - public Iterator<Point3d> iterator() - { + public Iterator<Point3d> iterator() { // return a "tweaked" iterator that will skip null entries automatically - return new Iterator<Point3d>() - { + return new Iterator<Point3d>() { final Iterator<Vertex3D> vertexIterator = mesh.getVertices().iterator(); Vertex3D next = null; boolean nextFetched = false; @Override - public void remove() - { + public void remove() { vertexIterator.remove(); } - private void fetchNext() - { + private void fetchNext() { if (nextFetched) return; @@ -626,8 +573,7 @@ public class Mesh3D extends ActiveContour } @Override - public Point3d next() - { + public Point3d next() { fetchNext(); nextFetched = false; @@ -635,8 +581,7 @@ public class Mesh3D extends ActiveContour } @Override - public boolean hasNext() - { + public boolean hasNext() { if (!vertexIterator.hasNext()) next = null; else @@ -647,14 +592,13 @@ public class Mesh3D extends ActiveContour }; } - void move(ROI boundField, double timeStep) - { + @Override + void move(ROI boundField, double timeStep) { final Vector3d force = new Vector3d(); final double maxDisp = sampling.getValue() * timeStep; final Point3d p = new Point3d(); - for (Vertex3D v : mesh.getVertices()) - { + for (Vertex3D v : mesh.getVertices()) { if (v == null) continue; @@ -668,8 +612,7 @@ public class Mesh3D extends ActiveContour // } // apply model forces if p lies within the area of interest - if ((boundField != null) && (p.z >= 0) && (boundField.contains(p.x, p.y, p.z, 0, 0))) - { + if ((boundField != null) && (p.z >= 0) && (boundField.contains(p.x, p.y, p.z, 0, 0))) { if (av.volumeConstraint.length() > 0) av.position.add(av.volumeConstraint); @@ -687,8 +630,7 @@ public class Mesh3D extends ActiveContour // System.out.println("oups !"); // } } - else - { + else { // FIXME: better to take all force but just reducing them to avoid big oscillation (Stephane) // // force.set(av.imageForces); // force.set(av.internalForces); @@ -730,28 +672,30 @@ public class Mesh3D extends ActiveContour updateMetaData(); // compute some convergence criterion - if (convergence != null) - convergence.push(mesh.getNumberOfPoints()); + try { + if (convergence != null) + convergence.push(mesh.getNumberOfPoints()); + } + catch (InterruptedException e) { + IcyExceptionHandler.showErrorMessage(e, false); + } } @Override - public boolean hasConverged(Operation operation, double epsilon) - { + public boolean hasConverged(Operation operation, double epsilon) { final Double value = convergence.computeCriterion(operation); return (value != null) && (value.doubleValue() <= (epsilon / 10d)); } @Override - protected void updateMetaData() - { + protected void updateMetaData() { super.updateMetaData(); mesh.roiChanged(true); } @Override - public boolean saveToXML(Node node) - { + public boolean saveToXML(Node node) { if (!super.saveToXML(node)) return false; @@ -759,8 +703,7 @@ public class Mesh3D extends ActiveContour } @Override - public boolean loadFromXML(Node node) - { + public boolean loadFromXML(Node node) { if (!super.loadFromXML(node)) return false; @@ -772,14 +715,11 @@ public class Mesh3D extends ActiveContour } @Override - public void reSample(double minFactor, double maxFactor) throws TopologyException - { - try - { + public void reSample(double minFactor, double maxFactor) throws TopologyException { + try { mesh.resample(sampling.getValue(), 0.4); } - catch (MeshTopologyException e) - { + catch (MeshTopologyException e) { if (e.children == null) throw new TopologyException(this, null); @@ -793,36 +733,30 @@ public class Mesh3D extends ActiveContour } @Override - public ActiveContour clone() - { + public ActiveContour clone() { return new Mesh3D(this); } @Override - protected void addPoint(Point3d p) - { + protected void addPoint(Point3d p) { mesh.addVertex(mesh.createVertex(p)); } @Override - protected ActiveContour[] checkSelfIntersection(double minDistance) - { + protected ActiveContour[] checkSelfIntersection(double minDistance) { // TODO return null; } @Override - public double computeAverageIntensity(Sequence regionData, BooleanMask3D mask) throws TopologyException, UnsupportedOperationException, InterruptedException - { - if (mask != null) - { + public double computeAverageIntensity(Sequence regionData, BooleanMask3D mask) throws UnsupportedOperationException, InterruptedException { + if (mask != null) { // get mesh boolean mask final ROI3DArea localROIMask = mesh.getROIMask(); final BooleanMask3D localMask = mesh.getMask(); - final List<Integer> zIndexes = new ArrayList<Integer>(mask.mask.keySet()); + final List<Integer> zIndexes = new ArrayList<>(mask.mask.keySet()); - for (Integer z : zIndexes) - { + for (Integer z : zIndexes) { // build mask from mesh mask final BooleanMask2D localMask2D = localMask.getMask2D(z); if (localMask2D != null) @@ -833,12 +767,9 @@ public class Mesh3D extends ActiveContour // change to channel 0 as regionData is a single channel image localROIMask.setC(0); - try - { + try { return ROIMeanIntensityDescriptor.computeMeanIntensity(localROIMask, regionData); - } - finally - { + } finally { localROIMask.setC(c); } } @@ -846,8 +777,8 @@ public class Mesh3D extends ActiveContour return 0d; } - public double computeBackgroundIntensity(Sequence imageData, BooleanMask3D mask) - { + @Override + public double computeBackgroundIntensity(Sequence imageData, BooleanMask3D mask) { Rectangle3D.Integer b3 = mask.bounds; // attempt to calculate a localized average outside each contour @@ -869,19 +800,15 @@ public class Mesh3D extends ActiveContour int maxX = Math.min(b3.sizeX, (int) Math.round(max.x + xExtent / 2)); double outSum = 0, outCpt = 0; - for (int zSlice = minZ; zSlice < maxZ; zSlice++) - { + for (int zSlice = minZ; zSlice < maxZ; zSlice++) { boolean[] _mask = mask.mask.get(zSlice).mask; float[] _data = imageData.getDataXYAsFloat(0, zSlice, 0); - for (int j = minY; j < maxY; j++) - { + for (int j = minY; j < maxY; j++) { int offset = minX + j * b3.sizeX; - for (int i = minX; i < maxX; i++, offset++) - { - if (!_mask[offset]) - { + for (int i = minX; i < maxX; i++, offset++) { + if (!_mask[offset]) { outSum += _data[i]; outCpt++; } @@ -893,32 +820,27 @@ public class Mesh3D extends ActiveContour } @Override - public double getDistanceToEdge(Point3d p) - { + public double getDistanceToEdge(Point3d p) { return mesh.getPenetrationDepth(p); } @Override - public ROI toROI() - { + @Deprecated + public ROI toROI() { return toROI(ROIType.POLYGON, null); } @Override - public ROI toROI(ROIType type, Sequence sequence) throws UnsupportedOperationException - { + public ROI toROI(ROIType type, Sequence sequence) throws UnsupportedOperationException { ROI3D roi; - switch (type) - { - case POLYGON: - { + switch (type) { + case POLYGON: { roi = mesh.clone(); break; } - case AREA: - { + case AREA: { roi = new ROI3DArea(mesh.getMask()); break; } @@ -935,20 +857,17 @@ public class Mesh3D extends ActiveContour } @Override - public void toSequence(Sequence output, double value) - { + public void toSequence(Sequence output, double value) { // TODO } @Override - protected void updateNormals() - { + protected void updateNormals() { mesh.updateNormals(); } @Override - protected void clean() - { + protected void clean() { isRemoving = true; for (Overlay overlay : overlays.values()) @@ -957,8 +876,7 @@ public class Mesh3D extends ActiveContour } @Override - public void paint(Graphics2D g, final Sequence sequence, IcyCanvas canvas) - { + public void paint(Graphics2D g, final Sequence sequence, IcyCanvas canvas) { if (isRemoving) return; diff --git a/src/main/java/plugins/adufour/activecontours/Polygon2D.java b/src/main/java/plugins/adufour/activecontours/Polygon2D.java index 0ccc31a..d95dbc4 100644 --- a/src/main/java/plugins/adufour/activecontours/Polygon2D.java +++ b/src/main/java/plugins/adufour/activecontours/Polygon2D.java @@ -19,6 +19,7 @@ import java.util.Iterator; import java.util.List; import java.util.TreeSet; +import javax.annotation.Nonnull; import javax.vecmath.Point3d; import javax.vecmath.Vector3d; @@ -51,55 +52,47 @@ import plugins.kernel.roi.roi2d.ROI2DPolygon; import plugins.kernel.roi.roi2d.ROI2DRectangle; import plugins.kernel.roi.roi2d.ROI2DShape; -public class Polygon2D extends ActiveContour -{ - private static final class Segment implements Iterable<Point3d> - { +public class Polygon2D extends ActiveContour { + private static final class Segment implements Iterable<Point3d> { final ArrayList<Point3d> points; - Segment(final Point3d head, final Point3d tail) - { - points = new ArrayList<Point3d>(2); + Segment(final Point3d head, final Point3d tail) { + points = new ArrayList<>(2); points.add(head); points.add(tail); } - final Point3d getHead() - { + Point3d getHead() { return points.get(0); } - final Point3d getTail() - { + Point3d getTail() { return points.get(points.size() - 1); } - final void addHead(final Point3d p) - { + void addHead(final Point3d p) { points.add(0, p); } - final void addHead(final Segment s) - { + void addHead(final Segment s) { for (int i = 0; i < s.points.size(); i++) points.add(i, s.points.get(i)); } - final void addTail(final Point3d p) - { + void addTail(final Point3d p) { points.add(p); } @Override - public Iterator<Point3d> iterator() - { + @Nonnull + public Iterator<Point3d> iterator() { return points.iterator(); } } - private final FillHolesInROI holeFiller = new FillHolesInROI(); + //private final FillHolesInROI holeFiller = new FillHolesInROI(); - final ArrayList<Point3d> points = new ArrayList<Point3d>(); + final ArrayList<Point3d> points = new ArrayList<>(); Path2D.Double path = new Path2D.Double(); @@ -116,13 +109,11 @@ public class Polygon2D extends ActiveContour /** * For XML loading purposes only */ - public Polygon2D() - { + public Polygon2D() { super(); } - protected Polygon2D(final Var<Double> sampling, final SlidingWindow convergenceWindow) - { + protected Polygon2D(final Var<Double> sampling, final SlidingWindow convergenceWindow) { super(sampling, convergenceWindow); setColor(Color.getHSBColor((float) Math.random(), 0.8f, 0.9f)); @@ -130,11 +121,8 @@ public class Polygon2D extends ActiveContour /** * Creates a clone of the specified contour - * - * @param contour */ - public Polygon2D(final Polygon2D contour) - { + public Polygon2D(final Polygon2D contour) { this(contour.sampling, new SlidingWindow(contour.convergence.getSize())); setColor(contour.getColor()); @@ -149,8 +137,7 @@ public class Polygon2D extends ActiveContour feedbackForces = new Vector3d[n]; volumeConstraintForces = new Vector3d[n]; - for (int i = 0; i < n; i++) - { + for (int i = 0; i < n; i++) { contourNormals[i] = new Vector3d(); modelForces[i] = new Vector3d(); feedbackForces[i] = new Vector3d(); @@ -163,21 +150,18 @@ public class Polygon2D extends ActiveContour } /** - * @param sampling - * @param convergenceWindow - * @param roi - * @throws TopologyException - * if the contour cannot created for topological reason (e.g. the roi is too small - * w.r.t. the sampling size) - * @throws InterruptedException + * @throws TopologyException if the contour cannot be created for topological reason (e.g. the roi is too small + * w.r.t. the sampling size) */ - public Polygon2D(final Var<Double> sampling, final SlidingWindow convergenceWindow, ROI2D roi) throws TopologyException, InterruptedException - { + public Polygon2D(final Var<Double> sampling, final SlidingWindow convergenceWindow, ROI2D roi) throws TopologyException, InterruptedException { this(sampling, convergenceWindow); - if (!(roi instanceof ROI2DEllipse) && !(roi instanceof ROI2DRectangle) && !(roi instanceof ROI2DPolygon) - && !(roi instanceof ROI2DArea)) - { + if ( + !(roi instanceof ROI2DEllipse) + && !(roi instanceof ROI2DRectangle) + && !(roi instanceof ROI2DPolygon) + && !(roi instanceof ROI2DArea) + ) { throw new IcyHandledException( "Active contours: invalid ROI. Only Rectangle, Ellipse, Polygon and Area are supported"); } @@ -191,24 +175,21 @@ public class Polygon2D extends ActiveContour if (roi.getNumberOfPoints() < sampling.getValue() * 3) throw new TopologyException(this, null); - if (roi instanceof ROI2DArea) - { + if (roi instanceof ROI2DArea) { // dilate ROI roi = dilateROI(roi, 1, 1); // fill holes first final BooleanMask2D mask = roi.getBooleanMask(true); - if (holeFiller.fillHoles(mask)) + if (FillHolesInROI.fillHoles(mask)) ((ROI2DArea) roi).setAsBooleanMask(mask); - try - { + try { triangulate((ROI2DArea) roi, sampling.getValue()); reSample(0.8, 1.4); return; } - catch (final TopologyException e) - { + catch (final TopologyException e) { final int theZ = roi.getZ(); final int theT = roi.getT(); roi = new ROI2DEllipse(roi.getBounds2D()); @@ -217,8 +198,7 @@ public class Polygon2D extends ActiveContour } } - if (roi instanceof ROI2DShape) - { + if (roi instanceof ROI2DShape) { // convert the ROI into a linked list of points final double[] segment = new double[6]; @@ -230,10 +210,8 @@ public class Polygon2D extends ActiveContour addPoint(new Point3d(segment[0], segment[1], z)); - while (!pathIterator.isDone()) - { - if (pathIterator.currentSegment(segment) == PathIterator.SEG_LINETO) - { + while (!pathIterator.isDone()) { + if (pathIterator.currentSegment(segment) == PathIterator.SEG_LINETO) { addPoint(new Point3d(segment[0], segment[1], z)); } pathIterator.next(); @@ -254,8 +232,7 @@ public class Polygon2D extends ActiveContour // points.clear(); // } - if (getAlgebraicInterior() > 0) - { + if (getAlgebraicInterior() > 0) { // Contour is defined in counter-clockwise order // => inverse it to clockwise ordering Collections.reverse(points); @@ -265,24 +242,21 @@ public class Polygon2D extends ActiveContour } @Override - protected void addPoint(final Point3d p) - { + protected void addPoint(final Point3d p) { points.add(p); } /** * Checks whether the contour is self-intersecting. Depending on the given parameters, a * self-intersection can be considered as a loop or as a contour division. - * - * @param minDistance - * the distance threshold between non-neighboring points to detect self-intersection + * + * @param minDistance the distance threshold between non-neighboring points to detect self-intersection * @return <code>null</code> if either no self-intersection is detected or if one of the new - * contours is too small, or an array of contours with 0 elements if both contours are - * too small, and 2 elements if both contours are viable + * contours is too small, or an array of contours with 0 elements if both contours are + * too small, and 2 elements if both contours are viable */ @Override - protected Polygon2D[] checkSelfIntersection(final double minDistance) - { + protected Polygon2D[] checkSelfIntersection(final double minDistance) { final double divSensitivity = (divisionSensitivity == null) ? 0d : divisionSensitivity.getValue(); double divisionDistQ = boundingSphere.getRadius() * 2 * divSensitivity; divisionDistQ *= divisionDistQ; @@ -294,45 +268,39 @@ public class Polygon2D extends ActiveContour // FIX (Stephane): we sometime need several iterations to remove complex or multiple loops in contour // and we really want to avoid any contour evolution with remaining loop (or it can create chaos !) - while (true) - { + while (true) { int i = 0, j = 0; int n = points.size(); Point3d p_i = null, p_j = null; boolean selfIntersection = false; - loop: for (i = 0; i < n; i++) - { + loop: + for (i = 0; i < n; i++) { p_i = points.get(i); final Vector3d n_i = contourNormalList.get(i); - for (j = i + 2; j < n - 1; j++) - { + for (j = i + 2; j < n - 1; j++) { p_j = points.get(j); final double distQ = p_i.distanceSquared(p_j); - if (distQ < minDistanceQ) - { + if (distQ < minDistanceQ) { // local self-intersection // deal with the special case that i and j are 2 points away - if (i == 0 && j == n - 2) - { + if (i == 0 && j == n - 2) { n--; points.remove(n); contourNormalList.remove(n); continue; } - else if (i == 1 && j == n - 1) - { + else if (i == 1 && j == n - 1) { points.remove(0); contourNormalList.remove(0); n--; continue; } - else if (j == i + 2) - { + else if (j == i + 2) { points.remove(i + 1); contourNormalList.remove(i + 1); n--; @@ -357,13 +325,11 @@ public class Polygon2D extends ActiveContour // are points sufficiently close? // => use the bounding radius / 2 - if (distQ < divisionDistQ) - { + if (distQ < divisionDistQ) { // are points located "in front" of each other? // j - i ~= n/2 ? // take a loose guess (+/- n/7) - if ((j - i) > (2 * n / 5) && (j - i) < (3 * n / 5)) - { + if ((j - i) > (2 * n / 5) && (j - i) < (3 * n / 5)) { // check the local curvature on each side (4 points away) final Vector3d vi1 = new Vector3d(points.get((i + n - 4) % n)); @@ -416,8 +382,7 @@ public class Polygon2D extends ActiveContour int nPoints = j - i; final Polygon2D child1 = new Polygon2D(sampling, new SlidingWindow(this.convergence.getSize())); - for (int p = 0; p < nPoints; p++) - { + for (int p = 0; p < nPoints; p++) { final Point3d pp = points.get((p + i) % n); center.add(pp); child1.addPoint(pp); @@ -433,8 +398,7 @@ public class Polygon2D extends ActiveContour nPoints = i + n - j; final Polygon2D child2 = new Polygon2D(sampling, new SlidingWindow(this.convergence.getSize())); - for (int p = 0, pj = p + j; p < nPoints; p++, pj++) - { + for (int p = 0, pj = p + j; p < nPoints; p++, pj++) { final Point3d pp = points.get(pj % n); center.add(pp); child2.addPoint(pp); @@ -452,16 +416,14 @@ public class Polygon2D extends ActiveContour // if only one of the two children has a size lower than minArea, then the division // should be considered as an artifact loop, the other child thus is the new contour - if (child1.points.size() < 10 || c1area < (c2area / 8)) - { + if (child1.points.size() < 10 || c1area < (c2area / 8)) { // remove c1 (too small) points.clear(); points.addAll(child2.points); continue; } - if (child2.points.size() < 10 || c2area < (c1area / 8)) - { + if (child2.points.size() < 10 || c2area < (c1area / 8)) { // remove c2 (too small) points.clear(); points.addAll(child1.points); @@ -478,7 +440,7 @@ public class Polygon2D extends ActiveContour // division => keep both then... if (n_i.dot(i_j) < 0) - return new Polygon2D[] {child1, child2}; + return new Polygon2D[]{child1, child2}; // loop => keep only the contour with correct orientation // => the contour with a positive algebraic area @@ -487,21 +449,19 @@ public class Polygon2D extends ActiveContour // c1 is the outer loop => keep it if (child1.getAlgebraicInterior() < 0) points.addAll(child1.points); - // c1 is the inner loop => keep c2 + // c1 is the inner loop => keep c2 else if (child2.getAlgebraicInterior() < 0) points.addAll(child2.points); } } @Override - protected void clean() - { + protected void clean() { // nothing to clean (everything should be garbage-collected) } @Override - public Polygon2D clone() - { + public Polygon2D clone() { return new Polygon2D(this); } @@ -510,12 +470,9 @@ public class Polygon2D extends ActiveContour * to keep the contour shape along its principal axis <br> * WARNING: this method directly update the array of final forces used to displace the contour * points. It should be used among the last to keep it most effective - * - * @param weight */ @Override - void computeAxisForces(final double weight) - { + void computeAxisForces(final double weight) { final Vector3d axis = new Vector3d(); final int s = (int) getDimension(0); @@ -526,33 +483,29 @@ public class Polygon2D extends ActiveContour double maxDistSq = 0; final Vector3d vec = new Vector3d(); - for (int i = 0; i < s; i++) - { + for (int i = 0; i < s; i++) { final Point3d vi = points.get(i); - for (int j = i + 1; j < s; j++) - { + for (int j = i + 1; j < s; j++) { final Point3d vj = points.get(j); vec.sub(vi, vj); final double dSq = vec.lengthSquared(); - if (dSq > maxDistSq) - { + if (dSq > maxDistSq) { maxDistSq = dSq; axis.set(vec); } } } - + axis.normalize(); } // To drive the contour along the main object axis, each displacement // vector is scaled by the scalar product between its normal and the main axis. { - for (int i = 0; i < s; i++) - { + for (int i = 0; i < s; i++) { final Vector3d normal = contourNormals[i]; // dot product between normalized vectors ranges from -1 to 1 @@ -568,12 +521,10 @@ public class Polygon2D extends ActiveContour } @Override - void computeBalloonForces(final double weight) - { + void computeBalloonForces(final double weight) { final int n = points.size(); - for (int i = 0; i < n; i++) - { + for (int i = 0; i < n; i++) { final Vector3d force = modelForces[i]; force.x += weight * contourNormals[i].x; @@ -583,21 +534,16 @@ public class Polygon2D extends ActiveContour /** * Update edge term of the contour evolution according to the image gradient - * - * @param weight - * @param edge_data */ @Override - void computeEdgeForces(final Sequence edgeData, final int channel, final double weight) - { + void computeEdgeForces(final Sequence edgeData, final int channel, final double weight) { final IcyBufferedImage image = edgeData.getImage(0, (int) Math.round(getZ())); if (image == null) return; final Vector3d grad = new Vector3d(); - for (int i = 0; i < points.size(); i++) - { + for (int i = 0; i < points.size(); i++) { final Point3d p = points.get(i); final Vector3d force = modelForces[i]; @@ -607,8 +553,7 @@ public class Polygon2D extends ActiveContour final double nextY = getPixelValue(image, p.x, p.y + 0.5d, channel); // getPixelValue(data, width, height, p.x, p.y + 0.5); final double prevY = getPixelValue(image, p.x, p.y - 0.5d, channel); // getPixelValue(data, width, height, p.x, p.y - 0.5); - if ((nextX != 0d) && (prevX != 0d) && (nextY != 0d) && (prevY != 0d)) - { + if ((nextX != 0d) && (prevX != 0d) && (nextY != 0d) && (prevY != 0d)) { grad.set(nextX - prevX, nextY - prevY, 0.0); grad.scale(weight); force.add(grad); @@ -618,8 +563,7 @@ public class Polygon2D extends ActiveContour @Override void computeRegionForces(final Sequence imageData, final int channel, double weight, final double sensitivity, final double inAvg, - final double outAvg) - { + final double outAvg) { // sensitivity should be high for dim objects, low for bright objects... // ... but none of the following options work properly // sensitivity *= 1/(1+cin); @@ -629,7 +573,7 @@ public class Polygon2D extends ActiveContour Point3d p; Vector3d force, norm; - final Vector3d cvms = new Vector3d(); + final Vector3d cvms = new Vector3d(); double val, inDiff, outDiff, forceFactor; final int n = points.size(); @@ -644,8 +588,7 @@ public class Polygon2D extends ActiveContour if (image == null) throw new IllegalArgumentException("Contour.getZ() = " + getZ() + "; Stack size = " + imageData.getSizeZ()); - for (int i = 0; i < n; i++) - { + for (int i = 0; i < n; i++) { p = points.get(i); force = modelForces[i]; norm = contourNormals[i]; @@ -672,8 +615,7 @@ public class Polygon2D extends ActiveContour } @Override - void computeInternalForces(double weight) - { + void computeInternalForces(double weight) { if (feedbackForces == null) return; @@ -693,8 +635,7 @@ public class Polygon2D extends ActiveContour next = points.get(0); // middle points - for (int i = 0; i < n; i++) - { + for (int i = 0; i < n; i++) { prev = curr; curr = next; next = points.get((i + 1) % n); @@ -706,8 +647,7 @@ public class Polygon2D extends ActiveContour } @Override - void computeVolumeConstraint(final double targetVolume, final double weight) - { + void computeVolumeConstraint(final double targetVolume, final double weight) { // 1) compute the difference between target and current volume final double volumeDiff = targetVolume - getDimension(2); // if (volumeDiff > 0): contour too small, should no longer shrink @@ -716,15 +656,13 @@ public class Polygon2D extends ActiveContour final int n = points.size(); final Vector3d totalForce = new Vector3d(); - for (int i = 0; i < n; i++) - { + for (int i = 0; i < n; i++) { totalForce.add(feedbackForces[i], modelForces[i]); // 2) check whether the final force has same direction as the outer normal final double forceNorm = totalForce.dot(contourNormals[i]); - if (forceNorm * volumeDiff < 0) - { + if (forceNorm * volumeDiff < 0) { totalForce.set(contourNormals[i]); totalForce.scale(volumeDiff * weight / targetVolume); volumeConstraintForces[i].set(totalForce); @@ -735,14 +673,12 @@ public class Polygon2D extends ActiveContour /** * Computes the feedback forces yielded by the penetration of the current contour into the * target contour - * - * @param target - * the contour that is being penetrated + * + * @param target the contour that is being penetrated * @return the number of actual point-mesh intersection tests */ @Override - int computeFeedbackForces(final ActiveContour target) - { + int computeFeedbackForces(final ActiveContour target) { final Point3d targetCenter = new Point3d(); target.boundingSphere.getCenter(targetCenter); @@ -752,17 +688,14 @@ public class Polygon2D extends ActiveContour int tests = 0; int index = 0; - for (final Point3d p : points) - { + for (final Point3d p : points) { final double distanceSq = p.distanceSquared(targetCenter); - if (distanceSq < targetRadiusSq) - { + if (distanceSq < targetRadiusSq) { final double penetration = target.getDistanceToEdge(p); // penetration ? - if (penetration > 0d) - { + if (penetration > 0d) { final Vector3d feedbackForce = feedbackForces[index]; feedbackForce.scaleAdd(-penetration * 0.2, contourNormals[index], feedbackForce); @@ -783,67 +716,52 @@ public class Polygon2D extends ActiveContour return tests; } - private static void createEdge(final ArrayList<Segment> segments, final double xStart, final double yStart, final double xEnd, final double yEnd) - { + private static void createEdge(final ArrayList<Segment> segments, final double xStart, final double yStart, final double xEnd, final double yEnd) { final double EPSILON = 0.00001; final Point3d head = new Point3d(xStart, yStart, 0); final Point3d tail = new Point3d(xEnd, yEnd, 0); - if (segments.size() == 0) - { + if (segments.size() == 0) { segments.add(new Segment(head, tail)); return; } int insertAtTailOf = -1, insertAtHeadOf = -1; - for (int i = 0; i < segments.size(); i++) - { + for (int i = 0; i < segments.size(); i++) { if (tail.distance(segments.get(i).getHead()) <= EPSILON) insertAtHeadOf = i; else if (head.distance(segments.get(i).getTail()) <= EPSILON) insertAtTailOf = i; } - if (insertAtTailOf >= 0) - { - if (insertAtHeadOf >= 0) - { + if (insertAtTailOf >= 0) { + if (insertAtHeadOf >= 0) { segments.get(insertAtHeadOf).addHead(segments.get(insertAtTailOf)); segments.remove(insertAtTailOf); } - else - { + else { segments.get(insertAtTailOf).addTail(tail); } } - else if (insertAtHeadOf >= 0) - { + else if (insertAtHeadOf >= 0) { segments.get(insertAtHeadOf).addHead(head); } - else - { + else { segments.add(new Segment(head, tail)); } } /** * Perform a morphological dilation on the specified ROI by the given radius in each dimension - * - * @param roi - * the ROI to dilate - * @param xRadius - * the radius in pixels along X - * @param yRadius - * the radius in pixels along X - * @param zRadius - * the radius in pixels along Z (not used if <code>roi</code> is 2D) + * + * @param roi the ROI to dilate + * @param xRadius the radius in pixels along X + * @param yRadius the radius in pixels along X * @return a new, dilated ROI of type "area" - * @throws InterruptedException */ - private static ROI2D dilateROI(final ROI2D roi, final int xRadius, final int yRadius) throws InterruptedException - { + private static ROI2D dilateROI(final ROI2D roi, final int xRadius, final int yRadius) throws InterruptedException { final int rx = xRadius, rrx = rx * rx; final int ry = yRadius, rry = ry * ry; @@ -856,13 +774,11 @@ public class Polygon2D extends ActiveContour r2.beginUpdate(); - for (final Point p : m2.getContourPoints()) - { + for (final Point p : m2.getContourPoints()) { // Brute force for (int y = -ry; y <= ry; y++) for (int x = -rx; x <= rx; x++) - if (x * x / rrx + y * y / rry <= 1.0) - { + if (x * x / (double) rrx + y * y / (double) rry <= 1.0) { if (!m2.contains(p.x + x, p.y + y)) r2.addPoint(p.x + x, p.y + y); } @@ -872,8 +788,7 @@ public class Polygon2D extends ActiveContour return r2; } - private static double getPixelValue(final IcyBufferedImage image, final double x, final double y, final int c) - { + private static double getPixelValue(final IcyBufferedImage image, final double x, final double y, final int c) { return image.getDataInterpolated(x, y, c); // final int xi = (int) x; @@ -965,17 +880,13 @@ public class Polygon2D extends ActiveContour * Computes the algebraic area of the current contour. The returned value is negative if the * contour points are order clockwise and positive if ordered counter-clockwise. The contour's * surface is just the absolute value of this algebraic surface - * - * @return */ - protected double getAlgebraicInterior() - { + protected double getAlgebraicInterior() { final int nm1 = points.size() - 1; double area = 0; // all points but the last - for (int i = 0; i < nm1; i++) - { + for (int i = 0; i < nm1; i++) { final Point3d p1 = points.get(i); final Point3d p2 = points.get(i + 1); area += (p2.x * p1.y - p1.x * p2.y) * 0.5; @@ -990,13 +901,11 @@ public class Polygon2D extends ActiveContour } @Override - public double getDimension(final int order) - { + public double getDimension(final int order) { if (points.size() <= 1) return 0; - switch (order) - { + switch (order) { case 0: // number of points { @@ -1012,8 +921,7 @@ public class Polygon2D extends ActiveContour double perimeter = p1.distance(p2); - for (int i = 0; i < size - 1; i++) - { + for (int i = 0; i < size - 1; i++) { // shift pair of points by one index p1 = p2; p2 = points.get(i + 1); @@ -1042,19 +950,17 @@ public class Polygon2D extends ActiveContour * semi-infinite line using a big segment. This is done by building a segment originating from * the given point and leaving in the opposite direction of the contour center. The full segment * can be written in algebraic coordinates as - * + * * <pre> * [PQ] where Q = P + n * CP * </pre> - * + * <p> * , where n is chosen arbitrarily large. - * - * @param p - * a point to test + * + * @param p a point to test */ @Override - public double getDistanceToEdge(final Point3d p) - { + public double getDistanceToEdge(final Point3d p) { final Point3d q = new Point3d(p.x + 10000 * (p.x - x), p.y + 10000 * (p.y - y), 0); int nb = 0; @@ -1062,13 +968,11 @@ public class Polygon2D extends ActiveContour double dist = 0, minDist = Double.MAX_VALUE; // all points but the last - for (int i = 0; i < nbPtsM1; i++) - { + for (int i = 0; i < nbPtsM1; i++) { final Point3d p1 = points.get(i); final Point3d p2 = points.get(i + 1); - if (Line2D.linesIntersect(p1.x, p1.y, p2.x, p2.y, p.x, p.y, q.x, q.y)) - { + if (Line2D.linesIntersect(p1.x, p1.y, p2.x, p2.y, p.x, p.y, q.x, q.y)) { nb++; dist = Line2D.ptLineDist(p1.x, p1.y, p2.x, p2.y, p.x, p.y); if (dist < minDist) @@ -1079,8 +983,7 @@ public class Polygon2D extends ActiveContour // last point final Point3d p1 = points.get(nbPtsM1); final Point3d p2 = points.get(0); - if (Line2D.linesIntersect(p1.x, p1.y, p2.x, p2.y, p.x, p.y, q.x, q.y)) - { + if (Line2D.linesIntersect(p1.x, p1.y, p2.x, p2.y, p.x, p.y, q.x, q.y)) { nb++; dist = Line2D.ptLineDist(p1.x, p1.y, p2.x, p2.y, p.x, p.y); if (dist < minDist) @@ -1092,14 +995,12 @@ public class Polygon2D extends ActiveContour } @Override - public Iterator<Point3d> iterator() - { + public Iterator<Point3d> iterator() { return points.iterator(); } @Override - void move(final ROI boundField, final double timeStep) - { + void move(final ROI boundField, final double timeStep) { final int n = points.size(); if ((modelForces == null) || (modelForces.length != n)) @@ -1109,8 +1010,7 @@ public class Polygon2D extends ActiveContour final double maxDisp = sampling.getValue() * timeStep; final Rectangle2D nearBounds; - if (boundField != null) - { + if (boundField != null) { nearBounds = boundField.getBounds5D().toRectangle2D(); nearBounds.setRect(nearBounds.getX() + 2d, nearBounds.getY() + 2d, nearBounds.getWidth() - 4d, nearBounds.getHeight() - 4d); @@ -1118,8 +1018,7 @@ public class Polygon2D extends ActiveContour else nearBounds = null; - for (int index = 0; index < n; index++) - { + for (int index = 0; index < n; index++) { final Point3d p = points.get(index); // apply volume constraint forces to position @@ -1128,10 +1027,8 @@ public class Polygon2D extends ActiveContour // apply model forces if p lies within the area of interest // FIXME: it appears to be better to always apply model force but just reducing it (Stephane) - if ((boundField == null) || boundField.contains(p.x, p.y, 0, 0, 0)) - { - if ((modelForces[index] != null) && (nearBounds != null)) - { + if ((boundField == null) || boundField.contains(p.x, p.y, 0, 0, 0)) { + if ((modelForces[index] != null) && (nearBounds != null)) { // close from border of "bound field" ? --> reduce model forces if ((p.x < nearBounds.getMinX()) || (p.x > nearBounds.getMaxX())) modelForces[index].scale(0.5); @@ -1139,8 +1036,7 @@ public class Polygon2D extends ActiveContour modelForces[index].scale(0.5); } } - else - { + else { // inhibit model force if (modelForces[index] != null) modelForces[index].scale(0); @@ -1185,8 +1081,7 @@ public class Polygon2D extends ActiveContour } @Override - public boolean hasConverged(final Operation operation, final double epsilon) - { + public boolean hasConverged(final Operation operation, final double epsilon) { final Double value = convergence.computeCriterion(operation); return (value != null) && (value.doubleValue() <= (epsilon / 100)); } @@ -1194,14 +1089,12 @@ public class Polygon2D extends ActiveContour AnnounceFrame f = null; // new AnnounceFrame("ready"); @Override - public void paint(final Graphics2D g, final Sequence sequence, final IcyCanvas canvas) - { + public void paint(final Graphics2D g, final Sequence sequence, final IcyCanvas canvas) { // only paint detections on the current frame if (getT() != canvas.getPositionT()) return; - if (g != null) - { + if (g != null) { // 2D viewer final Rectangle2D viewBounds = ((IcyCanvas2D) canvas).canvasToImage(canvas.getBounds()); g.clip(viewBounds); @@ -1217,38 +1110,33 @@ public class Polygon2D extends ActiveContour g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); - synchronized (path) - { + synchronized (path) { g.draw(path); } // this line displays the average intensity inside the object // g.drawString(StringUtil.toString(cin, 2), (float) getX() + 3, (float) getY()); } - else - { + //else { // TODO other viewers - } + //} } int cpt = 0; /** - * Re-samples the Contour according to an 'average distance between points' - * criterion. This method ensures that the distance between two consecutive - * points is strictly comprised between a minimum value and a maximum value. - * In order to avoid oscillatory behavior, 'max' and 'min' should verify the - * following relations: min < 1, max > 1, 2*min <= max. - * - * @param minFactor - * the minimum distance between two points. - * @param maxFactor - * the maximum distance between two points. - */ + * Re-samples the Contour according to an 'average distance between points' + * criterion. This method ensures that the distance between two consecutive + * points is strictly comprised between a minimum value and a maximum value. + * In order to avoid oscillatory behavior, 'max' and 'min' should verify the + * following relations: min < 1, max > 1, 2*min <= max. + * + * @param minFactor the minimum distance between two points. + * @param maxFactor the maximum distance between two points. + */ @Override - public void reSample(final double minFactor, final double maxFactor) throws TopologyException - { + public void reSample(final double minFactor, final double maxFactor) throws TopologyException { if (getDimension(1) < 10) - throw new TopologyException(this, new Polygon2D[] {}); + throw new TopologyException(this, new Polygon2D[]{}); final double minLength = sampling.getValue() * minFactor; final double maxLength = sampling.getValue() * maxFactor; @@ -1257,8 +1145,7 @@ public class Polygon2D extends ActiveContour // be updated manually whenever points is changed) int n = points.size(); - if (contourNormals == null) - { + if (contourNormals == null) { // first pass: update normals once contourNormals = new Vector3d[n]; for (int i = 0; i < n; i++) @@ -1280,11 +1167,9 @@ public class Polygon2D extends ActiveContour int iterCount = 0; final int maxIter = n * 10; - while (noChange == false) - { + while (!noChange) { // Safeguard - if (++iterCount > maxIter) - { + if (++iterCount > maxIter) { System.err.println("[Active Contours] Warning: hitting safeguard (preventing infinite resampling)"); break; } @@ -1292,26 +1177,23 @@ public class Polygon2D extends ActiveContour noChange = true; // all points but the last - for (int i = 0; i < n - 1; i++) - { + for (int i = 0; i < n - 1; i++) { if (n < 4) - throw new TopologyException(this, new Polygon2D[] {}); + throw new TopologyException(this, new Polygon2D[]{}); final Point3d pt1 = points.get(i); final Point3d pt2 = points.get(i + 1); final double distance = pt1.distance(pt2); - if (distance < minLength) - { + if (distance < minLength) { noChange = false; pt2.set((pt1.x + pt2.x) * 0.5, (pt1.y + pt2.y) * 0.5, (pt1.z + pt2.z) * 0.5); points.remove(i); i--; // comes down to i-1+1 when looping n--; } - else if (distance > maxLength) - { + else if (distance > maxLength) { noChange = false; points.add(i + 1, new Point3d((pt1.x + pt2.x) * 0.5, (pt1.y + pt2.y) * 0.5, (pt1.z + pt2.z) * 0.5)); @@ -1324,15 +1206,13 @@ public class Polygon2D extends ActiveContour final Point3d pt1 = points.get(n - 1); final Point3d pt2 = points.get(0); - if (pt1.distance(pt2) < minLength) - { + if (pt1.distance(pt2) < minLength) { noChange = false; pt2.set((pt1.x + pt2.x) * 0.5, (pt1.y + pt2.y) * 0.5, (pt1.z + pt2.z) * 0.5); points.remove(n - 1); n--; } - else if (pt1.distance(pt2) > maxLength) - { + else if (pt1.distance(pt2) > maxLength) { noChange = false; points.add(new Point3d((pt1.x + pt2.x) * 0.5, (pt1.y + pt2.y) * 0.5, (pt1.z + pt2.z) * 0.5)); n++; @@ -1341,15 +1221,13 @@ public class Polygon2D extends ActiveContour // re-sampling is done => update internal structures final int nbPoints = n; - if (modelForces == null || modelForces.length != nbPoints) - { + if (modelForces == null || modelForces.length != nbPoints) { modelForces = new Vector3d[nbPoints]; contourNormals = new Vector3d[nbPoints]; feedbackForces = new Vector3d[nbPoints]; volumeConstraintForces = new Vector3d[nbPoints]; - for (int i = 0; i < nbPoints; i++) - { + for (int i = 0; i < nbPoints; i++) { modelForces[i] = new Vector3d(); contourNormals[i] = new Vector3d(); feedbackForces[i] = new Vector3d(); @@ -1360,9 +1238,8 @@ public class Polygon2D extends ActiveContour updateMetaData(); } - private void triangulate(final ROI2DArea roi, final double resolution) throws TopologyException, InterruptedException - { - final ArrayList<Segment> segments = new ArrayList<Segment>(); + private void triangulate(final ROI2DArea roi, final double resolution) throws TopologyException, InterruptedException { + final ArrayList<Segment> segments = new ArrayList<>(); final Rectangle bounds = roi.getBounds(); @@ -1379,14 +1256,12 @@ public class Polygon2D extends ActiveContour for (int o = 0; o < mask.length; o += bounds.width) mask[o] = false; - for (int j = 0; j < bounds.height; j += grid) - { + for (int j = 0; j < bounds.height; j += grid) { // check for interruption from time to time as this can be a long process if (((j & 0xF) == 0xF) && Thread.interrupted()) throw new InterruptedException("Polygon2D.triangulate() process interrupted."); - for (int i = 0, index = j * bounds.width; i < bounds.width; i += grid, index += grid) - { + for (int i = 0, index = j * bounds.width; i < bounds.width; i += grid, index += grid) { // The image is divided into square cells containing two // triangles each: // @@ -1411,11 +1286,10 @@ public class Polygon2D extends ActiveContour // => there are 6 possible combinations in each triangle, that // is 12 per cube - if (a != b) - { + if (a != b) { if (b == c) // diagonal edge { - if (a == false) // b,c are inside + if (!a) // b,c are inside { createEdge(segments, i, j + 0.5, i + halfgrid, j); @@ -1430,7 +1304,7 @@ public class Polygon2D extends ActiveContour else // a = c -> vertical edge { - if (a == false) // a,c are outside + if (!a) // a,c are outside { createEdge(segments, i + halfgrid, j + halfgrid, i + halfgrid, j); @@ -1444,26 +1318,24 @@ public class Polygon2D extends ActiveContour } } else // a = b -> horizontal edge only if c is different - if (a != c) - { - if (a == false) // a,b are outside - { - createEdge(segments, i, j + halfgrid, i + halfgrid, j + halfgrid); + if (a != c) { + if (!a) // a,b are outside + { + createEdge(segments, i, j + halfgrid, i + halfgrid, j + halfgrid); - } - else - // a,b are inside - { - createEdge(segments, i + halfgrid, j + halfgrid, i, j + halfgrid); + } + else + // a,b are inside + { + createEdge(segments, i + halfgrid, j + halfgrid, i, j + halfgrid); + } } - } - if (c != d) - { + if (c != d) { if (b == c) // diagonal edge { - if (c == false) // b,c are outside + if (!c) // b,c are outside { createEdge(segments, i + halfgrid, j + grid, i + grid, j + halfgrid); @@ -1478,7 +1350,7 @@ public class Polygon2D extends ActiveContour else // b = d -> vertical edge { - if (c == false) // b,d are inside + if (!c) // b,d are inside { createEdge(segments, i + halfgrid, j + grid, i + halfgrid, j + halfgrid); @@ -1492,28 +1364,26 @@ public class Polygon2D extends ActiveContour } } else // c = d -> horizontal edge only if b is different - if (b != c) - { - if (b == false) // c,d are inside - { - createEdge(segments, i + halfgrid, j + halfgrid, i + grid, j + halfgrid); + if (b != c) { + if (!b) // c,d are inside + { + createEdge(segments, i + halfgrid, j + halfgrid, i + grid, j + halfgrid); - } - else - // c,d are outside - { - createEdge(segments, i + grid, j + halfgrid, i + halfgrid, j + halfgrid); + } + else + // c,d are outside + { + createEdge(segments, i + grid, j + halfgrid, i + halfgrid, j + halfgrid); + } } - } } } if (segments.size() == 0) return; - for (final Point3d p : segments.get(0)) - { + for (final Point3d p : segments.get(0)) { p.x += bounds.x; p.y += bounds.y; p.z = roi.getZ(); @@ -1525,24 +1395,22 @@ public class Polygon2D extends ActiveContour // decimate the contour by a factor 2 recursively until 2*resolution >= desired_resolution double current_resolution_doubled = halfgrid * 2; - while (current_resolution_doubled < resolution * 0.7) - { - for (int i = 0; i < points.size(); i++) - points.remove(i); + while (current_resolution_doubled < resolution * 0.7) { + points.clear(); + //for (int i = 0; i < points.size(); i++) + //points.remove(i); current_resolution_doubled *= 2; } } @Override - protected void updateNormals() - { + protected void updateNormals() { final int n = points.size(); Point3d p1 = points.get(n - 2); Point3d p = points.get(n - 1); Point3d p2 = points.get(0); - for (int i = 0; i < n; i++) - { + for (int i = 0; i < n; i++) { p1 = p; p = p2; p2 = points.get((i + 1) % n); @@ -1551,8 +1419,7 @@ public class Polygon2D extends ActiveContour } @Override - protected void updateMetaData() - { + protected void updateMetaData() { // int n = points.size(); // if (modelForces == null || modelForces.length != n) modelForces = new Vector3d[n]; // if (contourNormals == null || contourNormals.length != n) contourNormals = new @@ -1567,19 +1434,16 @@ public class Polygon2D extends ActiveContour updatePath(); } - private void updatePath() - { + private void updatePath() { final Path2D.Double newPath = new Path2D.Double(); final int nbPoints = points.size(); - if (nbPoints > 0) - { + if (nbPoints > 0) { Point3d p = points.get(0); newPath.moveTo(p.x, p.y); - for (int i = 1; i < nbPoints; i++) - { + for (int i = 1; i < nbPoints; i++) { p = points.get(i); newPath.lineTo(p.x, p.y); } @@ -1591,32 +1455,27 @@ public class Polygon2D extends ActiveContour @Deprecated @Override - public ROI2D toROI() throws InterruptedException - { + public ROI2D toROI() throws InterruptedException { return toROI(ROIType.AREA, null); } @Override - public ROI2D toROI(final ROIType type, final Sequence sequence) throws InterruptedException - { + public ROI2D toROI(final ROIType type, final Sequence sequence) throws InterruptedException { ROI2D roi; - switch (type) - { - case AREA: - { + switch (type) { + case AREA: { // roi = new ROI2DArea(); // ((ROI2DArea) roi).addShape(path); - final List<Point2D> p2d = new ArrayList<Point2D>(points.size()); + final List<Point2D> p2d = new ArrayList<>(points.size()); for (final Point3d p : this) p2d.add(new Point2D.Double(p.x, p.y)); roi = (ROI2D) ROIUtil.convertToMask(new ROI2DPolygon(p2d)); break; } - case POLYGON: - { - final List<Point2D> p2d = new ArrayList<Point2D>(points.size()); + case POLYGON: { + final List<Point2D> p2d = new ArrayList<>(points.size()); for (final Point3d p : this) p2d.add(new Point2D.Double(p.x, p.y)); roi = new ROI2DPolygon(p2d); @@ -1634,8 +1493,7 @@ public class Polygon2D extends ActiveContour } @Override - public double computeAverageIntensity(final Sequence summedImageData, final BooleanMask3D mask) - { + public double computeAverageIntensity(final Sequence summedImageData, final BooleanMask3D mask) { int myZ = (int) z; if (myZ == -1 && summedImageData.getSizeZ() == 1) @@ -1666,21 +1524,18 @@ public class Polygon2D extends ActiveContour final int maxY = Math.min((int) maxBounds.y + 1, h); final int n = points.size(); - final ArrayList<Integer> crosses = new ArrayList<Integer>(10); - Point3d p1 = null, p2 = null; + final ArrayList<Integer> crosses = new ArrayList<>(10); + Point3d p1, p2; - for (int j = minY; j < maxY; j++) - { + for (int j = minY; j < maxY; j++) { crosses.clear(); p1 = points.get(n - 1); - for (int p = 0; p < n; p++) - { + for (int p = 0; p < n; p++) { p2 = points.get(p); - if (j > Math.min(p1.y, p2.y) && j < Math.max(p1.y, p2.y)) - { + if (j > Math.min(p1.y, p2.y) && j < Math.max(p1.y, p2.y)) { int cross = (int) Math.round((p1.x + p2.x) * 0.5); if (cross < 0) cross = 0; @@ -1698,8 +1553,7 @@ public class Polygon2D extends ActiveContour Collections.sort(crosses); final int lineOffset = j * w; - for (int c = 0; c < crosses.size(); c += 2) - { + for (int c = 0; c < crosses.size(); c += 2) { final int crossIN = crosses.get(c); final int crossOUT = crosses.get(c + 1); @@ -1707,14 +1561,11 @@ public class Polygon2D extends ActiveContour sum += getPixelValue(image, crossOUT, j, 0); count += crossOUT - crossIN; - if (mask != null) - { - try - { + if (mask != null) { + try { Arrays.fill(_mask, lineOffset + crossIN, lineOffset + crossOUT, true); } - catch (final ArrayIndexOutOfBoundsException e) - { + catch (final ArrayIndexOutOfBoundsException e) { String message = "Image size: " + w + " x " + h + "\n"; message += "Line offset: " + lineOffset + "\n"; message += "Cross IN: " + crossIN + "\n"; @@ -1730,8 +1581,7 @@ public class Polygon2D extends ActiveContour } @Override - public double computeBackgroundIntensity(final Sequence imageData, final BooleanMask3D mask) - { + public double computeBackgroundIntensity(final Sequence imageData, final BooleanMask3D mask) { final Rectangle3D.Integer b3 = mask.bounds; // attempt to calculate a localised average outside each contour @@ -1753,12 +1603,10 @@ public class Polygon2D extends ActiveContour final boolean[] _mask = mask.mask.get((int) z).mask; final float[] _data = imageData.getDataXYAsFloat(0, (int) z, 0); - for (int j = minY; j < maxY; j++) - { + for (int j = minY; j < maxY; j++) { int offset = minX + j * b3.sizeX; for (int i = minX; i < maxX; i++, offset++) - if (!_mask[offset]) - { + if (!_mask[offset]) { outSum += _data[i]; outCpt++; } @@ -1768,10 +1616,10 @@ public class Polygon2D extends ActiveContour } @Override - public void toSequence(final Sequence output, final double value) - { + public void toSequence(final Sequence output, final double value) { final int myZ = (int) Math.round(getZ()); - final int myT = Math.round(getT()); + //final int myT = Math.round(getT()); + final int myT = getT(); final Object _mask = output.getDataXY(myT, myZ, 0); @@ -1790,50 +1638,42 @@ public class Polygon2D extends ActiveContour final int maxY = Math.min((int) maxBounds.y + 1, sizeY); final int n = points.size(); - Point3d p1 = null, p2 = null; - final TreeSet<Integer> crosses = new TreeSet<Integer>(); + Point3d p1, p2 = null; + final TreeSet<Integer> crosses = new TreeSet<>(); - for (int j = minY; j < maxY; j++) - { + for (int j = minY; j < maxY; j++) { final int lineOffset = j * sizeX; - int offset = lineOffset + (minX < 0 ? 0 : minX); + int offset = lineOffset + (Math.max(minX, 0)); crosses.clear(); crosses.add(minX); - for (int p = 0; p < n - 1; p++) - { + for (int p = 0; p < n - 1; p++) { p1 = points.get(p); p2 = points.get(p + 1); - if (j >= Math.min(p1.y, p2.y) && j <= Math.max(p1.y, p2.y)) - { + if (j >= Math.min(p1.y, p2.y) && j <= Math.max(p1.y, p2.y)) { // crosses.add((int) Math.round((p1.x + p2.x) * 0.5)); final int cross = (int) Math.round(p1.x + ((j - p1.y) * (p2.x - p1.x) / (p2.y - p1.y))); - if (crosses.contains(cross)) - { + if (crosses.contains(cross)) { crosses.remove(cross); Array1DUtil.setValue(_mask, lineOffset + cross, value); } - else - { + else { crosses.add(cross); } } } p1 = points.get(0); - if (j >= Math.min(p1.y, p2.y) && j <= Math.max(p1.y, p2.y)) - { + if (j >= Math.min(p1.y, p2.y) && j <= Math.max(p1.y, p2.y)) { // crosses.add((int) Math.round((p1.x + p2.x) * 0.5)); final int cross = (int) Math.round(p1.x + ((j - p1.y) * (p2.x - p1.x) / (p2.y - p1.y))); - if (crosses.contains(cross)) - { + if (crosses.contains(cross)) { crosses.remove(cross); Array1DUtil.setValue(_mask, lineOffset + cross, value); } - else - { + else { crosses.add(cross); } } @@ -1842,8 +1682,7 @@ public class Polygon2D extends ActiveContour final int nC = crosses.size(); - if (nC > 2) - { + if (nC > 2) { boolean in = false; final Iterator<Integer> it = crosses.iterator(); @@ -1851,16 +1690,13 @@ public class Polygon2D extends ActiveContour if (start < 0) start = 0; - while (it.hasNext()) - { + while (it.hasNext()) { int end = it.next(); if (end > sizeX) end = sizeX; - if (in) - { - for (int i = start; i < end; i++, offset++) - { + if (in) { + for (int i = start; i < end; i++, offset++) { // if (start < 0 || end >= sizeY) continue; Array1DUtil.setValue(_mask, offset, value); } @@ -1880,27 +1716,21 @@ public class Polygon2D extends ActiveContour * specified parameters. The raster scan algorithm is a 2D version of the line-scan algorithm * developed in: <i>Dufour et al., 3D active meshes: fast discrete deformable models for cell * tracking in 3D time-lapse microscopy. IEEE Transactions on Image Processing 20, 2011</i> - * - * @param updateLocalMask - * indicates whether the local boolean mask should be updated (this is used to get a - * {@link BooleanMask3D} version of this mesh) - * @param imageData - * (set to <code>null</code> if not needed) a sequence that will be used to compute - * the average intensity inside the mesh (note that the T and C have to be different - * than <code>-1</code> if the sequence has more than 1 time point and 1 channel) - * @param averageIntensity - * (only used if <code>imageData</code> is provided) a variable that will be hold the - * average image intensity inside the contour after the scan is complete + * + * @param updateLocalMask indicates whether the local boolean mask should be updated (this is used to get a + * {@link BooleanMask3D} version of this mesh) + * @param imageData (set to <code>null</code> if not needed) a sequence that will be used to compute + * the average intensity inside the mesh (note that the T and C have to be different + * from <code>-1</code> if the sequence has more than 1 time point and 1 channel) + * @param averageIntensity (only used if <code>imageData</code> is provided) a variable that will be hold the + * average image intensity inside the contour after the scan is complete */ - public void rasterScan(final boolean updateLocalMask, final Sequence imageData, final VarDouble averageIntensity, - final BooleanMask3D imageMask) - { + public void rasterScan(final boolean updateLocalMask, final Sequence imageData, final VarDouble averageIntensity, final BooleanMask3D imageMask) { } @Override - public boolean loadFromXML(final Node node) - { + public boolean loadFromXML(final Node node) { if (!super.loadFromXML(node)) return false; @@ -1909,8 +1739,7 @@ public class Polygon2D extends ActiveContour if (xmlElement == null) return false; - for (final Element ptElem : XMLUtil.getElements(xmlElement)) - { + for (final Element ptElem : XMLUtil.getElements(xmlElement)) { final double xPt = XMLUtil.getAttributeDoubleValue(ptElem, "x", Double.NaN); final double yPt = XMLUtil.getAttributeDoubleValue(ptElem, "y", Double.NaN); if (Double.isNaN(xPt) || Double.isNaN(yPt)) @@ -1924,15 +1753,13 @@ public class Polygon2D extends ActiveContour } @Override - public boolean saveToXML(final Node node) - { + public boolean saveToXML(final Node node) { if (!super.saveToXML(node)) return false; final Element xmlElement = XMLUtil.addElement(node, "Contour"); - for (final Point3d pt : points) - { + for (final Point3d pt : points) { final Element xmlPt = XMLUtil.addElement(xmlElement, "Point"); XMLUtil.setAttributeDoubleValue(xmlPt, "x", pt.x); XMLUtil.setAttributeDoubleValue(xmlPt, "y", pt.y); diff --git a/src/main/java/plugins/adufour/activecontours/ReSampler.java b/src/main/java/plugins/adufour/activecontours/ReSampler.java index 064d0dd..0ef3230 100644 --- a/src/main/java/plugins/adufour/activecontours/ReSampler.java +++ b/src/main/java/plugins/adufour/activecontours/ReSampler.java @@ -7,32 +7,26 @@ import java.util.concurrent.Callable; import plugins.fab.trackmanager.TrackGroup; import plugins.fab.trackmanager.TrackSegment; -public class ReSampler implements Callable<Boolean> -{ +public class ReSampler implements Callable<Boolean> { private final TrackGroup trackGroup; private final ActiveContour contour; private final Set<ActiveContour> allContours; private final Set<ActiveContour> evolvingContours; - ReSampler(TrackGroup trackGroup, ActiveContour contour, HashSet<ActiveContour> evolvingContours, - HashSet<ActiveContour> allContours) - { + ReSampler(TrackGroup trackGroup, ActiveContour contour, HashSet<ActiveContour> evolvingContours, HashSet<ActiveContour> allContours) { this.trackGroup = trackGroup; this.contour = contour; this.allContours = allContours; this.evolvingContours = evolvingContours; } - public Boolean call() - { + public Boolean call() { boolean change = false; - try - { + try { contour.reSample(0.6, 1.4); } - catch (Exception e) - { + catch (Exception e) { change = true; // the contour is either dividing or vanishing @@ -47,26 +41,21 @@ public class ReSampler implements Callable<Boolean> // this is a thread-safe version of TrackGroup.getTrackSegmentWithDetection(Detection) - synchronized (trackGroup) - { - for (TrackSegment track : trackGroup.getTrackSegmentList()) - { + synchronized (trackGroup) { + for (TrackSegment track : trackGroup.getTrackSegmentList()) { if (track == null) continue; // FIXME Fabrice: how could this happen? - if (track.containsDetection(contour)) - { + if (track.containsDetection(contour)) { currentSegment = track; break; } } - if (currentSegment != null) - { + if (currentSegment != null) { currentSegment.removeDetection(contour); - if (currentSegment.getDetectionList().size() == 0) - { + if (currentSegment.getDetectionList().size() == 0) { // the current contour is the only detection in this segment // => remove the whole segment trackGroup.removeTrackSegment(currentSegment); @@ -75,8 +64,7 @@ public class ReSampler implements Callable<Boolean> } // not expected exception ? - if (!(e instanceof TopologyException)) - { + if (!(e instanceof TopologyException)) { // show it in log e.printStackTrace(); return Boolean.valueOf(change); @@ -88,8 +76,7 @@ public class ReSampler implements Callable<Boolean> if (children == null) return Boolean.valueOf(change); - for (ActiveContour child : children) - { + for (ActiveContour child : children) { child.setT(contour.getT()); allContours.add(child); evolvingContours.add(child); @@ -98,8 +85,7 @@ public class ReSampler implements Callable<Boolean> TrackSegment childSegment = new TrackSegment(); childSegment.addDetection(child); - synchronized (trackGroup) - { + synchronized (trackGroup) { trackGroup.addTrackSegment(childSegment); } diff --git a/src/main/java/plugins/adufour/activecontours/SaveMeshTracksToVTK.java b/src/main/java/plugins/adufour/activecontours/SaveMeshTracksToVTK.java index abf739c..eff2351 100644 --- a/src/main/java/plugins/adufour/activecontours/SaveMeshTracksToVTK.java +++ b/src/main/java/plugins/adufour/activecontours/SaveMeshTracksToVTK.java @@ -14,47 +14,41 @@ import plugins.fab.trackmanager.TrackGroup; import plugins.fab.trackmanager.TrackSegment; import plugins.nchenouard.spot.Detection; -public class SaveMeshTracksToVTK extends Plugin implements Block -{ - Var<TrackGroup> meshTracks = new Var<TrackGroup>("Mesh tracks", TrackGroup.class); +public class SaveMeshTracksToVTK extends Plugin implements Block { + Var<TrackGroup> meshTracks = new Var<>("Mesh tracks", TrackGroup.class); VarFile folder = new VarFile("Folder", null); VarString prefix = new VarString("Prefix", "Mesh"); - + @Override - public void declareInput(VarList inputMap) - { + public void declareInput(VarList inputMap) { inputMap.add("ROI", meshTracks); inputMap.add("folder", folder); inputMap.add("prefix", prefix); } - + @Override - public void declareOutput(VarList outputMap) - { + public void declareOutput(VarList outputMap) { } - + @Override - public void run() - { - ArrayList<TrackSegment> segments = new ArrayList<TrackSegment>(meshTracks.getValue(true).getTrackSegmentList()); - - for (int i = 1; i <= segments.size(); i++) - { + public void run() { + ArrayList<TrackSegment> segments = new ArrayList<>(meshTracks.getValue(true).getTrackSegmentList()); + + for (int i = 1; i <= segments.size(); i++) { TrackSegment segment = segments.get(i - 1); - + if (segment == null) continue; - - for(Detection detection : segment.getDetectionList()) - - if (detection instanceof Mesh3D) - { - String meshID = "_#" + StringUtil.toString(i, 3); - String timeID = "_T" + StringUtil.toString(detection.getT(), 3); - String fileName = prefix.getValue() + meshID + timeID + ".vtk"; - File vtkFile = new File(folder.getValue(true).getPath() + File.separator + fileName); - ((Mesh3D) detection).mesh.saveToVTK(vtkFile); - } + + for (Detection detection : segment.getDetectionList()) + + if (detection instanceof Mesh3D) { + String meshID = "_#" + StringUtil.toString(i, 3); + String timeID = "_T" + StringUtil.toString(detection.getT(), 3); + String fileName = prefix.getValue() + meshID + timeID + ".vtk"; + File vtkFile = new File(folder.getValue(true).getPath() + File.separator + fileName); + ((Mesh3D) detection).mesh.saveToVTK(vtkFile); + } } } - + } diff --git a/src/main/java/plugins/adufour/activecontours/SlidingWindow.java b/src/main/java/plugins/adufour/activecontours/SlidingWindow.java index 79bced8..fdf0df6 100644 --- a/src/main/java/plugins/adufour/activecontours/SlidingWindow.java +++ b/src/main/java/plugins/adufour/activecontours/SlidingWindow.java @@ -5,24 +5,24 @@ import icy.math.ArrayMath; /** * Utility class defining a fixed-size window where a user may store values and check convergence * against various criteria - * + * * @author Alexandre Dufour */ -public class SlidingWindow -{ +public class SlidingWindow { /** * The list of operations that can be applied on the window - * + * * @author Alexandre Dufour */ - public enum Operation - { + public enum Operation { NONE, MIN, MAX, MEAN, SUM, VARIANCE, /** * Coefficient of variation (standard deviation over the mean) */ VAR_COEFF - }; + } + + ; private double[] window; @@ -32,22 +32,18 @@ public class SlidingWindow /** * Creates a new convergence window with given size, operation and convergence test sorting * method - * - * @param size - * the window size + * + * @param size the window size */ - public SlidingWindow(int size) - { + public SlidingWindow(int size) { setSize(size); } - public int getSize() - { + public int getSize() { return window.length; } - public void setSize(int size) - { + public void setSize(int size) { window = new double[size]; internalCount = 0; count = 0; @@ -55,11 +51,8 @@ public class SlidingWindow /** * Adds the given value to the queue - * - * @param value */ - public final void push(double value) - { + public final void push(double value) { // skip every other value to prevent oscillation effects if ((internalCount++ & 1) == 1) return; @@ -71,19 +64,16 @@ public class SlidingWindow /** * Erase all values from the convergence window. Makes the window reusable without destruction */ - public void clear() - { + public void clear() { java.util.Arrays.fill(window, 0); count = 0; } - public Double computeCriterion(Operation operation) - { + public Double computeCriterion(Operation operation) { if (count < window.length) return null; - switch (operation) - { + switch (operation) { case NONE: return null; case MIN: @@ -99,7 +89,7 @@ public class SlidingWindow case VAR_COEFF: return ArrayMath.std(window, false) / ArrayMath.mean(window); default: - throw new UnsupportedOperationException("operation " + operation.toString() + " not supported yet"); + throw new UnsupportedOperationException("operation " + operation + " not supported yet"); } } } diff --git a/src/main/java/plugins/adufour/activecontours/TopologyException.java b/src/main/java/plugins/adufour/activecontours/TopologyException.java index 06b411b..091b7bd 100644 --- a/src/main/java/plugins/adufour/activecontours/TopologyException.java +++ b/src/main/java/plugins/adufour/activecontours/TopologyException.java @@ -2,28 +2,22 @@ package plugins.adufour.activecontours; /** * Class defining an exception which occurs when a contour is splitting during its evolution - * + * * @author Alexandre Dufour */ -public class TopologyException extends Exception -{ - private static final long serialVersionUID = 1L; - +public class TopologyException extends Exception { public final ActiveContour source; public final ActiveContour[] children; /** * Creates a new Topology exception for the specified contour - * - * @param contour - * the contour undergoing a topology break - * @param children - * an array containing zero or more contours that should replace the contour - * raising the exception + * + * @param contour the contour undergoing a topology break + * @param children an array containing zero or more contours that should replace the contour + * raising the exception */ - public TopologyException(ActiveContour contour, ActiveContour[] children) - { + public TopologyException(ActiveContour contour, ActiveContour[] children) { super("Topology break detected in contour " + contour.hashCode()); this.source = contour; this.children = children; -- GitLab