Commit f5df793f authored by Daniel Felipe  GONZALEZ OBANDO's avatar Daniel Felipe GONZALEZ OBANDO
Browse files

enabled volume constraint in Plugin GUI

parent 4be794ba
bin
pluginfile-active-contours*.jar
/ActiveContours.jar
......@@ -80,1797 +80,1610 @@ 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);
return currentContour;
}
}
private final double EPSILON = 0.0000001;
private final EzVarBoolean showAdvancedOptions = new EzVarBoolean("Show advanced options", false);
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 final EzVarSequence input = new EzVarSequence("Input");
private Sequence inputData;
return currentContour;
}
}
public final EzVarDouble regul_weight = new EzVarDouble("Contour smoothness", 0.05, 0, 1.0, 0.01);
private final double EPSILON = 0.0000001;
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 final EzVarBoolean showAdvancedOptions = new EzVarBoolean("Show advanced options", false);
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 EzVarSequence input = new EzVarSequence("Input");
private Sequence inputData;
final Class<? extends ROI> clazz;
public final EzVarDouble regul_weight = new EzVarDouble("Contour smoothness", 0.05, 0, 1.0, 0.01);
private ROIType(Class<? extends ROI> clazz)
{
this.clazz = 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);
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.01);
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();
}
@Override
public void initialize()
{
addEzComponent(showAdvancedOptions);
addEzComponent(input);
// edge
edge.setToolTipText("Sets the contour(s) to follow image intensity gradients");
edge_weight.setToolTipText(
"Negative (resp. positive) weight pushes contours toward decreasing (resp. increasing) intensities");
edge.add(edge_c, edge_weight);
addEzComponent(edge);
// region
region.setToolTipText("Sets the contour(s) to isolate homogeneous intensity regions");
region_weight.setToolTipText("Set to 0 to deactivate this parameter");
region_sensitivity.setToolTipText("Increase this value to be more sensitive to dim objects (default: 1)");
region_localise.setToolTipText("Check this box if the image background is noisy or non-homogeneous");
showAdvancedOptions.addVisibilityTriggerTo(region_sensitivity, true);
// don't show local means (for now)
showAdvancedOptions.addVisibilityTriggerTo(region_localise, true);
region.add(region_c, region_weight, region_sensitivity);// , region_localise);
addEzComponent(region);
// coupling
coupling_flag.setToolTipText("Prevents multiple contours from overlapping");
showAdvancedOptions.addVisibilityTriggerTo(coupling_flag, true);
addEzComponent(coupling_flag);
// regul
regul_weight.setToolTipText("Higher values result in a smoother contour, but may also slow its growth");
addEzComponent(regul_weight);
// balloon force
balloon_weight.setToolTipText("Positive (resp. negative) values will inflate (resp. deflate) the contour");
addEzComponent(balloon_weight);
// axis contraint
axis_weight.setToolTipText("Higher values restrict the evolution along the principal axis");
addEzComponent(axis_weight);
// sensitivity to detect division ahead of time
division_sensitivity.setToolTipText("Increase the sensitivity to cell division");
showAdvancedOptions.addVisibilityTriggerTo(division_sensitivity, true);
addEzComponent(division_sensitivity);
// contour
contour_resolution
.setToolTipText("Sets the contour(s) precision as the distance (in pixels) between control points");
contour_timeStep
.setToolTipText("Defines the evolution speed (warning: keep a low value to avoid vibration effects)");
convergence_winSize
.setToolTipText("Defines over how many iterations the algorithm should check for convergence");
showAdvancedOptions.addVisibilityTriggerTo(convergence_winSize, true);
convergence_operation.setToolTipText("Defines the operation used to detect convergence");
showAdvancedOptions.addVisibilityTriggerTo(convergence_operation, true);
convergence_criterion.setToolTipText("Defines the value of the criterion used to detect convergence");
convergence_nbIter.setToolTipText(
"Defines the absolute number of iterations to use in case the contour does not converge automatically");
showAdvancedOptions.addVisibilityTriggerTo(convergence_nbIter, true);
evolution_bounds.setNoSequenceSelection();
evolution_bounds.setToolTipText(
"Bounds the evolution of the contour to all ROI of the given sequence (select \"No sequence\" to deactivate)");
showAdvancedOptions.addVisibilityTriggerTo(evolution_bounds, true);