Commit 0e5a4626 authored by Stephane Dallongeville's avatar Stephane Dallongeville
Browse files

Tweak and minor fix on maximum iteration

- added detection of early complete operation when doing tracking and there is no more object to track.
- fixed an issue which was causing the double of maximum allowed number of iteration to be processed on contours (not really hurting but it was slower because of that).
parent e8206e4b
...@@ -29,6 +29,7 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 ...@@ -29,6 +29,7 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3
protected int id; protected int id;
protected SlidingWindow convergence; protected SlidingWindow convergence;
protected int lastConvergedFrame;
protected VarDouble sampling = new VarDouble("sampling", 1.0); protected VarDouble sampling = new VarDouble("sampling", 1.0);
...@@ -47,6 +48,7 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 ...@@ -47,6 +48,7 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3
name = ""; name = "";
id = -1; id = -1;
lastConvergedFrame = -1;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
...@@ -56,6 +58,7 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 ...@@ -56,6 +58,7 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3
name = ""; name = "";
id = -1; id = -1;
lastConvergedFrame = -1;
// follow and shortcut references to avoid memory leaks // follow and shortcut references to avoid memory leaks
while (sampling.getReference() != null) while (sampling.getReference() != null)
...@@ -350,6 +353,16 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3 ...@@ -350,6 +353,16 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3
*/ */
public abstract boolean hasConverged(SlidingWindow.Operation operation, double epsilon); public abstract boolean hasConverged(SlidingWindow.Operation operation, double epsilon);
public int getLastConvergedFrame()
{
return lastConvergedFrame;
}
public void setLastConvergedFrame(int frame)
{
lastConvergedFrame = frame;
}
public void setDivisionSensitivity(Var<Double> divisionSensitivity) public void setDivisionSensitivity(Var<Double> divisionSensitivity)
{ {
this.divisionSensitivity = divisionSensitivity; this.divisionSensitivity = divisionSensitivity;
......
...@@ -80,1611 +80,1874 @@ import plugins.kernel.roi.roi3d.ROI3DStack; ...@@ -80,1611 +80,1874 @@ import plugins.kernel.roi.roi3d.ROI3DStack;
import plugins.nchenouard.spot.Detection; import plugins.nchenouard.spot.Detection;
import vtk.vtkObjectBase; 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"; public static final String CONTOUR_BASE_NAME = "Contour #";
public static final String CONTOUR_ID = "contourId";
private class LocalRegionStatisticsComputer implements Callable<Object> {
final ActiveContour contour; private class LocalRegionStatisticsComputer implements Callable<Object>
final boolean maskBased; {
final ActiveContour contour;
public LocalRegionStatisticsComputer(ActiveContour contour, boolean maskBased) { final boolean maskBased;
this.contour = contour;
this.maskBased = maskBased; public LocalRegionStatisticsComputer(ActiveContour contour, boolean maskBased)
} {
this.contour = contour;
@Override this.maskBased = maskBased;
public Object call() { }
try {
double cin = contour.computeAverageIntensity(contour instanceof Mesh3D ? regionData : regionDataSummed, @Override
maskBased ? contourMask_buffer : null); public Object call()
region_cin.put(trackGroup.getValue().getTrackSegmentWithDetection(contour), cin); {
} catch (TopologyException topo) { try
System.err.println("Removing a contour. Reason: " + topo.getMessage()); {
allContoursAtTimeT.remove(contour); double cin = contour.computeAverageIntensity(contour instanceof Mesh3D ? regionData : regionDataSummed,
evolvingContoursAtTimeT.remove(contour); maskBased ? contourMask_buffer : null);
} region_cin.put(trackGroup.getValue().getTrackSegmentWithDetection(contour), cin);
return null; }
} catch (TopologyException topo)
} {
System.err.println("Removing a contour. Reason: " + topo.getMessage());
private class LocalBackgroundStatisticsComputer implements Callable<Object> { allContoursAtTimeT.remove(contour);
final ActiveContour contour; evolvingContoursAtTimeT.remove(contour);
}
public LocalBackgroundStatisticsComputer(ActiveContour contour) { return null;
this.contour = contour; }
} }
@Override private class LocalBackgroundStatisticsComputer implements Callable<Object>
public Object call() { {
TrackSegment segment = trackGroup.getValue().getTrackSegmentWithDetection(contour); final ActiveContour contour;
double cout = contour.computeBackgroundIntensity(regionData, contourMask_buffer); public LocalBackgroundStatisticsComputer(ActiveContour contour)
{
region_cout.put(segment, cout); this.contour = contour;
}
return null;
} @Override
} public Object call()
{
private class ContourInitializer implements Callable<Object> { TrackSegment segment = trackGroup.getValue().getTrackSegmentWithDetection(contour);
final ROI roi;
final int z; double cout = contour.computeBackgroundIntensity(regionData, contourMask_buffer);
final int t;
final Tuple3d pixelSize; region_cout.put(segment, cout);
final int convWinSize;
final List<TrackSegment> activeTracks; return null;
final List<TrackSegment> endedTracks; }
}
public ContourInitializer(ROI roi, int z, int t, Tuple3d pixelSize, int convWinSize,
List<TrackSegment> activeTracks, List<TrackSegment> justEndedTracks) { private class ContourInitializer implements Callable<Object>
super(); {
final ROI roi;
this.roi = roi; final int z;
this.z = z; final int t;
this.t = t; final Tuple3d pixelSize;
this.pixelSize = pixelSize; final int convWinSize;
this.convWinSize = convWinSize; final List<TrackSegment> activeTracks;
this.activeTracks = activeTracks; final List<TrackSegment> endedTracks;
this.endedTracks = justEndedTracks;
} public ContourInitializer(ROI roi, int z, int t, Tuple3d pixelSize, int convWinSize,
List<TrackSegment> activeTracks, List<TrackSegment> justEndedTracks)
// test if the object is colliding an existing contour or if we need to discard {
// it for other reason super();
private boolean colliding() {
// // image bounds this.roi = roi;
// final Rectangle imageBounds = inputData.getBounds2D(); this.z = z;
// // minus one (to detect object on border) this.t = t;
// imageBounds.x++; this.pixelSize = pixelSize;
// imageBounds.y++; this.convWinSize = convWinSize;
// imageBounds.width -= 2; this.activeTracks = activeTracks;
// imageBounds.height -= 2; this.endedTracks = justEndedTracks;
}
// test if object is intersecting with current active contours
for (TrackSegment segment : activeTracks) { // test if the object is colliding an existing contour or if we need to discard
// get contour for this active track // it for other reason
final ActiveContour contour = (ActiveContour) segment.getLastDetection(); private boolean colliding()
// get ROI from contour {
final ROI contourROI = contour.toROI(ROIType.POLYGON, null); // // image bounds
// final Rectangle imageBounds = inputData.getBounds2D();
// object is intersecting contour ? --> discard // // minus one (to detect object on border)
if (roi.intersects(contourROI)) // imageBounds.x++;
return true; // imageBounds.y++;
} // imageBounds.width -= 2;
// imageBounds.height -= 2;
return false;
} // test if object is intersecting with current active contours
for (TrackSegment segment : activeTracks)
@Override {
public Object call() { // get contour for this active track
// object colliding active contours ? --> discard it final ActiveContour contour = (ActiveContour) segment.getLastDetection();
if (colliding()) // get ROI from contour
return null; final ROI contourROI = contour.toROI(ROIType.POLYGON, null);
// get contour for the new object // object is intersecting contour ? --> discard
final ActiveContour contour = getContourOf(roi, z, t, pixelSize, convWinSize); if (roi.intersects(contourROI))
// error creating contour return true;
if (contour == null) }
return null;
return false;
// does it overlap with a track that terminates in the previous frame? }
for (TrackSegment track : endedTracks) {
final ActiveContour previousContour = (ActiveContour) track.getLastDetection(); @Override
// get ROI from contour public Object call()
final ROI previousContourROI = previousContour.toROI(ROIType.POLYGON, null); {
// object colliding active contours ? --> discard it
// object is intersecting previous contour ? if (colliding())
if (roi.intersects(previousContourROI)) { return null;
System.out.println(
"Found link at time " + t + ", position (" + contour.getX() + ";" + contour.getY() + ")"); // get contour for the new object
// add contour to the track final ActiveContour contour = getContourOf(roi, z, t, pixelSize, convWinSize);
track.addDetection(contour); // error creating contour
// done (no new track) if (contour == null)
return null; return null;
}
} // does it overlap with a track that terminates in the previous frame?
for (TrackSegment track : endedTracks)
// need to create a new track {
final TrackSegment result = new TrackSegment(); final ActiveContour previousContour = (ActiveContour) track.getLastDetection();
// add contour to it // get ROI from contour
result.addDetection(contour); final ROI previousContourROI = previousContour.toROI(ROIType.POLYGON, null);
// and return the new created track // object is intersecting previous contour ?
return result; if (roi.intersects(previousContourROI))
} {
} System.out.println(
"Found link at time " + t + ", position (" + contour.getX() + ";" + contour.getY() + ")");
private class ContourDuplicator implements Callable<Object> { // add contour to the track
final TrackSegment segment; track.addDetection(contour);
final int t; // done (no new track)
final int convWinSize; return null;
}
public ContourDuplicator(TrackSegment segment, int t, int convWinSize) { }
super();
// need to create a new track
this.segment = segment; final TrackSegment result = new TrackSegment();
this.t = t; // add contour to it
this.convWinSize = convWinSize; result.addDetection(contour);
}
// and return the new created track
@Override return result;
public Object call() { }
Detection detection; }
detection = segment.getDetectionAtTime(t); private class ContourDuplicator implements Callable<Object>
// already have detection for that time point (shouldn't be the case) ? --> exit {
if (detection != null) final TrackSegment segment;
return detection; final int t;
final int convWinSize;
detection = segment.getDetectionAtTime(t - 1);
// no detection for previous time point ? nothing to do public ContourDuplicator(TrackSegment segment, int t, int convWinSize)
if (detection == null) {
return null; super();
final ActiveContour previousContour = (ActiveContour) detection; this.segment = segment;
final ActiveContour currentContour = previousContour.clone(); this.t = t;
this.convWinSize = convWinSize;
currentContour.convergence.setSize(convWinSize); }
currentContour.setT(t);
@Override
segment.addDetection(currentContour); public Object call()
{
Detection detection;
detection = segment.getDetectionAtTime(t);
// already have detection for that time point (shouldn't be the case) ? --> exit
if (detection != null)
return detection;
detection = segment.getDetectionAtTime(t - 1);
// no detection for previous time point ? nothing to do
if (detection == null)
return null;
final ActiveContour previousContour = (ActiveContour) detection;
final ActiveContour currentContour = previousContour.clone();
currentContour.convergence.setSize(convWinSize);
currentContour.setT(t);
segment.addDetection(currentContour);
return currentContour;
}
}
private final double EPSILON = 0.0000001;
private final EzVarBoolean showAdvancedOptions = new EzVarBoolean("Show advanced options", false);
return currentContour; public final EzVarSequence input = new EzVarSequence("Input");
} private Sequence inputData;
}
private final double EPSILON = 0.0000001; public final EzVarDouble regul_weight = new EzVarDouble("Contour smoothness", 0.05, 0, 1.0, 0.01);
private final EzVarBoolean showAdvancedOptions = new EzVarBoolean("Show advanced options", false); public final EzGroup edge = new EzGroup("Find bright/dark edges");
public final EzVarDimensionPicker edge_c = new EzVarDimensionPicker("Find edges in channel", DimensionId.C, input);
public final EzVarDouble edge_weight = new EzVarDouble("Edge weight", 0, -1, 1, 0.1);
public final EzVarSequence input = new EzVarSequence("Input"); public final EzGroup region = new EzGroup("Find homogeneous intensity areas");
private Sequence inputData; public final EzVarDimensionPicker region_c = new EzVarDimensionPicker("Find regions in channel", DimensionId.C,
input);
public final EzVarDouble region_weight = new EzVarDouble("Region weight", 1.0, 0.0, 1.0, 0.1);
public final EzVarDouble region_sensitivity = new EzVarDouble("Region sensitivity", 1.0, 0.2, 5.0, 0.1);
public final EzVarBoolean region_localise = new EzVarBoolean("Variable background", false);
public final EzVarDouble balloon_weight = new EzVarDouble("Contour inflation", 0, -0.5, 0.5, 0.001);
public final EzVarDouble axis_weight = new EzVarDouble("Axis constraint", 0, 0.0, 1, 0.1);
public final EzVarBoolean coupling_flag = new EzVarBoolean("Multi-contour coupling", true);
public final EzGroup evolution = new EzGroup("Evolution parameters");
public final EzVarSequence evolution_bounds = new EzVarSequence("Bound field to ROI of");
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 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
{
NO, ON_INPUT, ON_NEW_IMAGE, AS_LABELS
}
public enum ROIType
{
AREA(ROI2DArea.class), POLYGON(ROI2DPolygon.class);
public final EzVarDouble regul_weight = new EzVarDouble("Contour smoothness", 0.05, 0, 1.0, 0.01); final Class<? extends ROI> clazz;
public final EzGroup edge = new EzGroup("Find bright/dark edges"); private ROIType(Class<? extends ROI> clazz)
public final EzVarDimensionPicker edge_c = new EzVarDimensionPicker("Find edges in channel", DimensionId.C, input); {
public final EzVarDouble edge_weight = new EzVarDouble("Edge weight", 0, -1, 1, 0.1); this.clazz = clazz;
}
}
public final EzGroup region = new EzGroup("Find homogeneous intensity areas"); public final EzVarEnum<ExportROI> output_rois = new EzVarEnum<ExportROI>("Export ROI", ExportROI.values(),
public final EzVarDimensionPicker region_c = new EzVarDimensionPicker("Find regions in channel", DimensionId.C, ExportROI.NO);
input); public final EzVarEnum<ROIType> output_roiType = new EzVarEnum<ROIType>("Type of ROI", ROIType.values(),
public final EzVarDouble region_weight = new EzVarDouble("Region weight", 1.0, 0.0, 1.0, 0.1); ROIType.AREA);
public final EzVarDouble region_sensitivity = new EzVarDouble("Region sensitivity", 1.0, 0.2, 5.0, 0.1); private VarSequence output_labels = new VarSequence("Labels", null);
public final EzVarBoolean region_localise = new EzVarBoolean("Variable background", false);
public final EzVarBoolean tracking = new EzVarBoolean("Track objects over time", false);
public final EzVarDouble balloon_weight = new EzVarDouble("Contour inflation", 0, -0.5, 0.5, 0.001);
public final EzVarDouble division_sensitivity = new EzVarDouble("Division sensitivity", 0, 0, 2, 0.1);
public final EzVarDouble axis_weight = new EzVarDouble("Axis constraint", 0, 0.0, 1, 0.1);
public final EzVarBoolean tracking_newObjects = new EzVarBoolean("Watch entering objects", false);
public final EzVarBoolean coupling_flag = new EzVarBoolean("Multi-contour coupling", true);
private final HashMap<TrackSegment, Double> volumes = new HashMap<TrackSegment, Double>();
public final EzGroup evolution = new EzGroup("Evolution parameters"); public final EzVarBoolean volume_constraint = new EzVarBoolean("Volume constraint", false);
public final EzVarSequence evolution_bounds = new EzVarSequence("Bound field to ROI of"); public final EzVarDouble volume_weight = new EzVarDouble("Volume weight", 0.01, 0, 1, 0.001);
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 EzButton showTrackManager;
public final EzVarInteger convergence_winSize = new EzVarInteger("Convergence window size", 50, 10, 10000, 10);
public final EzVarEnum<Operation> convergence_operation = new EzVarEnum<SlidingWindow.Operation>( private Sequence edgeData;
"Convergence operation", Operation.values(), Operation.VAR_COEFF); private Sequence regionData;
public final EzVarDouble convergence_criterion = new EzVarDouble("Convergence criterion", 0.001, 0, 1, 0.0001); private Sequence regionDataSummed;
public final EzVarInteger convergence_nbIter = new EzVarInteger("Max. iterations", 100000, 100, 100000, 1000);
private BooleanMask3D contourMask_buffer;
public enum ExportROI {
NO, ON_INPUT, ON_NEW_IMAGE, AS_LABELS HashMap<TrackSegment, Double> region_cin = new HashMap<TrackSegment, Double>(0);
} HashMap<TrackSegment, Double> region_cout = new HashMap<TrackSegment, Double>(0);
public enum ROIType { public final VarROIArray roiInput = new VarROIArray("input ROI");
AREA(ROI2DArea.class), POLYGON(ROI2DPolygon.class); public final VarROIArray roiOutput = new VarROIArray("Regions of interest");
final Class<? extends ROI> clazz; private boolean globalStop;
private ROIType(Class<? extends ROI> clazz) { Var<TrackGroup> trackGroup = new Var<TrackGroup>("Tracks", TrackGroup.class);
this.clazz = clazz;
} /**
} * All contours present on the current time point
*/
public final EzVarEnum<ExportROI> output_rois = new EzVarEnum<ExportROI>("Export ROI", ExportROI.values(), private final HashSet<ActiveContour> allContoursAtTimeT = new HashSet<ActiveContour>();
ExportROI.NO);
public final EzVarEnum<ROIType> output_roiType = new EzVarEnum<ROIType>("Type of ROI", ROIType.values(), /**
ROIType.AREA); * Set of contours that have not yet converged on the current time point
private VarSequence output_labels = new VarSequence("Labels", null); */
private final HashSet<ActiveContour> evolvingContoursAtTimeT = new HashSet<ActiveContour>();
public final EzVarBoolean tracking = new EzVarBoolean("Track objects over time", false);
private ActiveContoursOverlay overlay;
public final EzVarDouble division_sensitivity = new EzVarDouble("Division sensitivity", 0, 0, 2, 0.1);
private Processor multiThreadService = new Processor(SystemUtil.getNumberOfCPUs());
public final EzVarBoolean tracking_newObjects = new EzVarBoolean("Watch entering objects", false);
private long lastVtkGCTime = 0L;
private final HashMap<TrackSegment, Double> volumes = new HashMap<TrackSegment, Double>();
public final EzVarBoolean volume_constraint = new EzVarBoolean("Volume constraint", false); public ActiveContours()
public final EzVarDouble volume_weight = new EzVarDouble("Volume weight", 0.01, 0, 1, 0.001); {
super();
public final EzButton showTrackManager;
multiThreadService.setThreadName("Active Contours");
private Sequence edgeData;
private Sequence regionData; showTrackManager = new EzButton("Send to track manager", new ActionListener()
private Sequence regionDataSummed; {
@Override
private BooleanMask3D contourMask_buffer; public void actionPerformed(ActionEvent e)
{
HashMap<TrackSegment, Double> region_cin = new HashMap<TrackSegment, Double>(0); ThreadUtil.invokeLater(new Runnable()
HashMap<TrackSegment, Double> region_cout = new HashMap<TrackSegment, Double>(0); {
@Override
public final VarROIArray roiInput = new VarROIArray("input ROI"); public void run()
public final VarROIArray roiOutput = new VarROIArray("Regions of interest"); {