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
protected int id;
protected SlidingWindow convergence;
protected int lastConvergedFrame;
protected VarDouble sampling = new VarDouble("sampling", 1.0);
......@@ -47,6 +48,7 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3
name = "";
id = -1;
lastConvergedFrame = -1;
}
@SuppressWarnings("unchecked")
......@@ -56,6 +58,7 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3
name = "";
id = -1;
lastConvergedFrame = -1;
// follow and shortcut references to avoid memory leaks
while (sampling.getReference() != null)
......@@ -350,6 +353,16 @@ public abstract class ActiveContour extends Detection implements Iterable<Point3
*/
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)
{
this.divisionSensitivity = divisionSensitivity;
......
......@@ -80,1611 +80,1874 @@ import plugins.kernel.roi.roi3d.ROI3DStack;
import plugins.nchenouard.spot.Detection;
import vtk.vtkObjectBase;
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> {
final ActiveContour contour;
final boolean maskBased;
public LocalRegionStatisticsComputer(ActiveContour contour, boolean maskBased) {
this.contour = contour;
this.maskBased = maskBased;
}
@Override
public Object call() {
try {
double cin = contour.computeAverageIntensity(contour instanceof Mesh3D ? regionData : regionDataSummed,
maskBased ? contourMask_buffer : null);
region_cin.put(trackGroup.getValue().getTrackSegmentWithDetection(contour), cin);
} catch (TopologyException topo) {
System.err.println("Removing a contour. Reason: " + topo.getMessage());
allContoursAtTimeT.remove(contour);
evolvingContoursAtTimeT.remove(contour);
}
return null;
}
}
private class LocalBackgroundStatisticsComputer implements Callable<Object> {
final ActiveContour contour;
public LocalBackgroundStatisticsComputer(ActiveContour contour) {
this.contour = contour;
}
@Override
public Object call() {
TrackSegment segment = trackGroup.getValue().getTrackSegmentWithDetection(contour);
double cout = contour.computeBackgroundIntensity(regionData, contourMask_buffer);
region_cout.put(segment, cout);
return null;
}
}
private class ContourInitializer implements Callable<Object> {
final ROI roi;
final int z;
final int t;
final Tuple3d pixelSize;
final int convWinSize;
final List<TrackSegment> activeTracks;
final List<TrackSegment> endedTracks;
public ContourInitializer(ROI roi, int z, int t, Tuple3d pixelSize, int convWinSize,
List<TrackSegment> activeTracks, List<TrackSegment> justEndedTracks) {
super();
this.roi = roi;
this.z = z;
this.t = t;
this.pixelSize = pixelSize;
this.convWinSize = convWinSize;
this.activeTracks = activeTracks;
this.endedTracks = justEndedTracks;
}
// test if the object is colliding an existing contour or if we need to discard
// it for other reason
private boolean colliding() {
// // image bounds
// final Rectangle imageBounds = inputData.getBounds2D();
// // minus one (to detect object on border)
// imageBounds.x++;
// imageBounds.y++;
// imageBounds.width -= 2;
// imageBounds.height -= 2;
// test if object is intersecting with current active contours
for (TrackSegment segment : activeTracks) {
// get contour for this active track
final ActiveContour contour = (ActiveContour) segment.getLastDetection();
// get ROI from contour
final ROI contourROI = contour.toROI(ROIType.POLYGON, null);
// object is intersecting contour ? --> discard
if (roi.intersects(contourROI))
return true;
}
return false;
}
@Override
public Object call() {
// object colliding active contours ? --> discard it
if (colliding())
return null;
// get contour for the new object
final ActiveContour contour = getContourOf(roi, z, t, pixelSize, convWinSize);
// error creating contour
if (contour == null)
return null;
// does it overlap with a track that terminates in the previous frame?
for (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)) {
System.out.println(
"Found link at time " + t + ", position (" + contour.getX() + ";" + contour.getY() + ")");
// add contour to the track
track.addDetection(contour);
// done (no new track)
return null;
}
}
// need to create a new track
final TrackSegment result = new TrackSegment();
// add contour to it
result.addDetection(contour);
// and return the new created track
return result;
}
}
private class ContourDuplicator implements Callable<Object> {
final TrackSegment segment;
final int t;
final int convWinSize;
public ContourDuplicator(TrackSegment segment, int t, int convWinSize) {
super();
this.segment = segment;
this.t = t;
this.convWinSize = convWinSize;
}
@Override
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);
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>
{
final ActiveContour contour;
final boolean maskBased;
public LocalRegionStatisticsComputer(ActiveContour contour, boolean maskBased)
{
this.contour = contour;
this.maskBased = maskBased;
}
@Override
public Object call()
{
try
{
double cin = contour.computeAverageIntensity(contour instanceof Mesh3D ? regionData : regionDataSummed,
maskBased ? contourMask_buffer : null);
region_cin.put(trackGroup.getValue().getTrackSegmentWithDetection(contour), cin);
}
catch (TopologyException topo)
{
System.err.println("Removing a contour. Reason: " + topo.getMessage());
allContoursAtTimeT.remove(contour);
evolvingContoursAtTimeT.remove(contour);
}
return null;
}
}
private class LocalBackgroundStatisticsComputer implements Callable<Object>
{
final ActiveContour contour;
public LocalBackgroundStatisticsComputer(ActiveContour contour)
{
this.contour = contour;
}
@Override
public Object call()
{
TrackSegment segment = trackGroup.getValue().getTrackSegmentWithDetection(contour);
double cout = contour.computeBackgroundIntensity(regionData, contourMask_buffer);
region_cout.put(segment, cout);
return null;
}
}
private class ContourInitializer implements Callable<Object>
{
final ROI roi;
final int z;
final int t;
final Tuple3d pixelSize;
final int convWinSize;
final List<TrackSegment> activeTracks;
final List<TrackSegment> endedTracks;
public ContourInitializer(ROI roi, int z, int t, Tuple3d pixelSize, int convWinSize,
List<TrackSegment> activeTracks, List<TrackSegment> justEndedTracks)
{
super();
this.roi = roi;
this.z = z;
this.t = t;
this.pixelSize = pixelSize;
this.convWinSize = convWinSize;
this.activeTracks = activeTracks;
this.endedTracks = justEndedTracks;
}
// test if the object is colliding an existing contour or if we need to discard
// it for other reason
private boolean colliding()
{
// // image bounds
// final Rectangle imageBounds = inputData.getBounds2D();
// // minus one (to detect object on border)
// imageBounds.x++;
// imageBounds.y++;
// imageBounds.width -= 2;
// imageBounds.height -= 2;
// test if object is intersecting with current active contours
for (TrackSegment segment : activeTracks)
{
// get contour for this active track
final ActiveContour contour = (ActiveContour) segment.getLastDetection();
// get ROI from contour
final ROI contourROI = contour.toROI(ROIType.POLYGON, null);
// object is intersecting contour ? --> discard
if (roi.intersects(contourROI))
return true;
}
return false;
}
@Override
public Object call()
{
// object colliding active contours ? --> discard it
if (colliding())
return null;
// get contour for the new object
final ActiveContour contour = getContourOf(roi, z, t, pixelSize, convWinSize);
// error creating contour
if (contour == null)
return null;
// does it overlap with a track that terminates in the previous frame?
for (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))
{
System.out.println(
"Found link at time " + t + ", position (" + contour.getX() + ";" + contour.getY() + ")");
// add contour to the track
track.addDetection(contour);
// done (no new track)
return null;
}
}
// need to create a new track
final TrackSegment result = new TrackSegment();
// add contour to it
result.addDetection(contour);
// and return the new created track
return result;
}
}
private class ContourDuplicator implements Callable<Object>
{
final TrackSegment segment;
final int t;
final int convWinSize;
public ContourDuplicator(TrackSegment segment, int t, int convWinSize)
{
super();
this.segment = segment;
this.t = t;
this.convWinSize = convWinSize;
}
@Override
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");
private Sequence inputData;
public final EzGroup region = new EzGroup("Find homogeneous intensity areas");
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");
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);
private ROIType(Class<? extends ROI> clazz)
{
this.clazz = clazz;
}
}
public final EzGroup region = new EzGroup("Find homogeneous intensity areas");
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);
final Class<? extends ROI> clazz;
private ROIType(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);
private VarSequence output_labels = new VarSequence("Labels", null);
public final EzVarBoolean tracking = new EzVarBoolean("Track objects over time", false);
public final EzVarDouble division_sensitivity = new EzVarDouble("Division sensitivity", 0, 0, 2, 0.1);
public final EzVarBoolean tracking_newObjects = new EzVarBoolean("Watch entering objects", false);
private final HashMap<TrackSegment, Double> volumes = new HashMap<TrackSegment, Double>();
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);
public final EzButton showTrackManager;
private Sequence edgeData;
private Sequence regionData;
private Sequence regionDataSummed;
private BooleanMask3D contourMask_buffer;
HashMap<TrackSegment, Double> region_cin = new HashMap<TrackSegment, Double>(0);
HashMap<TrackSegment, Double> region_cout = new HashMap<TrackSegment, Double>(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);
/**
* All contours present on the current time point
*/
private final HashSet<ActiveContour> allContoursAtTimeT = new HashSet<ActiveContour>();
/**
* Set of contours that have not yet converged on the current time point
*/
private final HashSet<ActiveContour> evolvingContoursAtTimeT = new HashSet<ActiveContour>();
private ActiveContoursOverlay overlay;
private Processor multiThreadService = new Processor(SystemUtil.getNumberOfCPUs());
private long lastVtkGCTime = 0L;
public ActiveContours() {
super();
multiThreadService.setThreadName("Active Contours");
showTrackManager = new EzButton("Send to track manager", new ActionListener() {
@Override
public void actionPerformed(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()));
TrackManager tm = new TrackManager();
tm.reOrganize();
tm.setDisplaySequence(inputData);
}
});
}
});
}
public TrackGroup getTrackGroup() {
return trackGroup.getValue();