Skip to content

Commit

Permalink
annotation of main algorithms
Browse files Browse the repository at this point in the history
  • Loading branch information
jollion committed Feb 22, 2018
1 parent 61d9563 commit 8078e8e
Show file tree
Hide file tree
Showing 16 changed files with 228 additions and 270 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
import boa.plugins.plugins.segmenters.BacteriaIntensity;
import boa.plugins.plugins.segmenters.MicroChannelFluo2D;
import boa.plugins.plugins.segmenters.MutationSegmenter;
import boa.plugins.plugins.trackers.LAPTracker;
import boa.plugins.plugins.trackers.MutationTracker;
import boa.plugins.plugins.trackers.MicrochannelTracker;
import boa.plugins.plugins.trackers.bacteria_in_microchannel_tracker.BacteriaClosedMicrochannelTrackerLocalCorrections;
import boa.plugins.plugins.transformations.AutoRotationXY;
Expand Down Expand Up @@ -176,9 +176,9 @@ public static Experiment generateXPFluo(String name, String outputDir, boolean s
//bacteria.setProcessingScheme(new SegmentAndTrack(new BacteriaClosedMicrochannelTrackerLocalCorrections(new BacteriaFluo()).setCostParameters(0.1, 0.5)));
bacteria.setProcessingScheme(new SegmentThenTrack(new BacteriaIntensity(), new BacteriaClosedMicrochannelTrackerLocalCorrections().setCostParameters(0.1, 0.5)));
mutation.setProcessingScheme(new SegmentAndTrack(
new LAPTracker().setCompartimentStructure(1).setSegmenter(
new MutationTracker().setCompartimentStructure(1).setSegmenter(
new MutationSegmenter(0.65, 0.5, 0.55).setScale(2.5)
).setSpotQualityThreshold(1).setLinkingMaxDistance(0.4, 0.41).setGapParameters(0.4, 0.1, 3).setTrackLength(10, 0)
).setSpotQualityThreshold(1).setLinkingMaxDistance(0.4, 0.41).setGapParameters(0.4, 0.1, 3)
).addPreFilters(new BandPass(0, 8, 0, 5) // was 10
).addPostFilters(new FeatureFilter(new Quality(), 0.6, true, true)));

Expand Down
7 changes: 3 additions & 4 deletions src/main/java/boa/core/generateXP/GenerateXP.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
import boa.plugins.plugins.track_post_filter.RemoveTracksStartingAfterFrame;
import boa.plugins.plugins.track_post_filter.TrackLengthFilter;
import boa.plugins.plugins.trackers.bacteria_in_microchannel_tracker.BacteriaClosedMicrochannelTrackerLocalCorrections;
import boa.plugins.plugins.trackers.LAPTracker;
import boa.plugins.plugins.trackers.MutationTracker;
import boa.plugins.plugins.trackers.MicrochannelTracker;
import boa.plugins.plugins.trackers.ObjectIdxTracker;
import boa.plugins.plugins.transformations.AutoRotationXY;
Expand Down Expand Up @@ -496,10 +496,10 @@ public static void setParametersFluo(Experiment xp, boolean processing, boolean
);
// modification of scaling: lap * 2.5, gauss * scale (=2) quality * 2.23
mutation.setProcessingScheme(new SegmentAndTrack(
new LAPTracker().setCompartimentStructure(1).setSegmenter(
new MutationTracker().setCompartimentStructure(1).setSegmenter(
new MutationSegmenter(2.25, 1.625, 1.8).setScale(2.5, 3) // was 0.9, 0.65, 0.9, scale was 2 for mutH
).setSpotQualityThreshold(3.122) // 4.46 for mutH ?
.setLinkingMaxDistance(0.8, 0.82).setGapParameters(0.8, 0.15, 3).setTrackLength(8, 14)
.setLinkingMaxDistance(0.8, 0.82).setGapParameters(0.8, 0.15, 3)
).addPreFilters(new BandPass(0, 10, 0, 5) // was 10
).addPostFilters(new FeatureFilter(new Quality(), 2.23, true, true))); // was 1
}
Expand Down Expand Up @@ -575,7 +575,6 @@ public static void setParametersPhase(Experiment xp, boolean processing, boolean
new BacteriaClosedMicrochannelTrackerLocalCorrections()
.setSegmenter(new BacteriaIntensityPhase())
.setCostParameters(0.2, 2)
.setCorrectMotherCell(false)
).addTrackPreFilters(
new SubtractBackgroundMicrochannels(),
new NormalizeTrack(1, true)
Expand Down
1 change: 1 addition & 0 deletions src/main/java/boa/gui/GUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ public class GUI extends javax.swing.JFrame implements ImageObjectListener, User
public GUI() {
//logger.info("DBMaker: {}", checkClass("org.mapdb.DBMaker"));
ToolTipManager.sharedInstance().setInitialDelay(100);
ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE);
logger.info("Creating GUI instance...");
this.instance=this;
initComponents();
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/boa/plugins/ToolTip.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@
* @author jollion
*/
public interface ToolTip{
/**
* The returned tooltip string will be formatted as html in a box with a fixed with, so the \"<html>\" tag is not needed, and line skipping will be automatically managed
* @return the string that will be displayed as a tool tip when scrolling over the name of the plugin
*/
public String getToolTipText();
public static int tooltipWidth = 750;
public static int TOOL_TIP_BOX_WIDTH = 750;
public static String formatToolTip(String toolTip) {
if (toolTip.startsWith("<html>")) toolTip = toolTip.replace("<html>", "");
if (toolTip.endsWith("</html>")) toolTip = toolTip.replace("</html>", "");
return "<html><div style=\"width:"+tooltipWidth+"px\">" + toolTip + "</div></html>";
return "<html><div style=\"width:"+TOOL_TIP_BOX_WIDTH+"px\">" + toolTip + "</div></html>";
}
}
17 changes: 16 additions & 1 deletion src/main/java/boa/plugins/TrackParametrizable.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,23 @@
* @param <S> segmenter type
*/
public interface TrackParametrizable<S extends Segmenter> {
@FunctionalInterface public static interface ApplyToSegmenter<S> { public void apply(StructureObject parent, S segmenter);}
@FunctionalInterface public static interface ApplyToSegmenter<S> {
/**
* Parametrizes the {@param segmenter}
* This method may be called asynchronously with different pairs of {@param parent}/{@param segmenter}
* @param parent parent object from the parent track used to create the {@link boa.plugins.TrackParametrizable.ApplyToSegmenter apply to segmenter object} See: {@link #getApplyToSegmenter(int, java.util.List, boa.plugins.Segmenter, java.util.concurrent.ExecutorService) }. This is not necessary the segmentation parent that will be used as argument in {@link boa.plugins.Segmenter#runSegmenter(boa.image.Image, int, boa.data_structure.StructureObjectProcessing) }
* @param segmenter Segmenter instance that will be parametrized, prior to call the method {@link boa.plugins.Segmenter#runSegmenter(boa.image.Image, int, boa.data_structure.StructureObjectProcessing) }
*/
public void apply(StructureObject parent, S segmenter);
}
/**
*
* @param structureIdx index of the structure to be segmented via call to {@link boa.plugins.Segmenter#runSegmenter(boa.image.Image, int, boa.data_structure.StructureObjectProcessing) }
* @param parentTrack parent track (elements are parent of structure {@param structureIdx}
* @return ApplyToSegmenter object that will parametrize Segmenter instances before call to {@link boa.plugins.Segmenter#runSegmenter(boa.image.Image, int, boa.data_structure.StructureObjectProcessing) }
*/
public ApplyToSegmenter run(int structureIdx, List<StructureObject> parentTrack);

// + static helpers methods
public static <S extends Segmenter> ApplyToSegmenter<S> getApplyToSegmenter(int structureIdx, List<StructureObject> parentTrack, S segmenter, ExecutorService executor) {
if (segmenter instanceof TrackParametrizable) {
Expand Down
64 changes: 49 additions & 15 deletions src/main/java/boa/plugins/plugins/segmenters/MutationSegmenter.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,8 @@
import boa.configuration.parameters.BoundedNumberParameter;
import boa.configuration.parameters.NumberParameter;
import boa.configuration.parameters.Parameter;
import boa.configuration.parameters.ParameterUtils;
import boa.configuration.parameters.PluginParameter;
import boa.data_structure.Region;
import boa.data_structure.RegionPopulation;
import boa.data_structure.RegionPopulation.MeanIntensity;
import boa.data_structure.RegionPopulation.Or;
import boa.data_structure.RegionPopulation.Overlap;
import boa.data_structure.StructureObject;
import boa.data_structure.StructureObjectProcessing;
import boa.data_structure.Voxel;
Expand Down Expand Up @@ -71,25 +66,33 @@
import static boa.image.processing.WatershedTransform.watershed;
import boa.image.processing.neighborhood.CylindricalNeighborhood;
import boa.image.processing.neighborhood.Neighborhood;
import boa.plugins.ToolTip;
import boa.utils.Utils;

/**
*
* @author jollion
*/
public class MutationSegmenter implements Segmenter, UseMaps, ManualSegmenter, ObjectSplitter, ParameterSetup {
public class MutationSegmenter implements Segmenter, UseMaps, ManualSegmenter, ObjectSplitter, ParameterSetup, ToolTip {
public List<Image> intermediateImages;
public static boolean debug = false;
public static boolean displayImages = false;
ArrayNumberParameter scale = new ArrayNumberParameter("Scale", 0, new BoundedNumberParameter("Scale", 1, 2, 1, 5)).setSorted(true);
NumberParameter smoothScale = new BoundedNumberParameter("Smooth scale", 1, 2, 1, 5);
NumberParameter minSpotSize = new BoundedNumberParameter("Min. Spot Size (Voxels)", 0, 5, 1, null);
NumberParameter thresholdHigh = new NumberParameter("Threshold for Seeds", 2, 2.25);
NumberParameter thresholdLow = new NumberParameter("Threshold for propagation", 2, 1.63);
NumberParameter intensityThreshold = new NumberParameter("Intensity Threshold for Seeds", 2, 1.8); //
NumberParameter smoothScale = new BoundedNumberParameter("Smooth scale", 1, 2, 1, 5).setToolTipText("Scale (in pixels) for gaussian smooth");
NumberParameter minSpotSize = new BoundedNumberParameter("Min. Spot Size (Voxels)", 0, 5, 1, null).setToolTipText("In pixels: spots under this size will be removed");
NumberParameter thresholdHigh = new NumberParameter("Threshold for Seeds", 2, 2.25).setToolTipText("Higher value will increase false negative and decrease false positives.<br /> Laplacian Threshold for seed selection");
NumberParameter thresholdLow = new NumberParameter("Threshold for propagation", 2, 1.63).setToolTipText("Lower value will yield in larger spots.<br /> Laplacian Threshold for watershed propagation: propagation stops at this value.");
NumberParameter intensityThreshold = new NumberParameter("Intensity Threshold for Seeds", 2, 1.8).setToolTipText("Higher value will increase false negative and decrease false positives.<br /> Laplacian Threshold for seed selection");
boolean planeByPlane = false;
Parameter[] parameters = new Parameter[]{scale, smoothScale, minSpotSize, thresholdHigh, thresholdLow, intensityThreshold};
ProcessingVariables pv = new ProcessingVariables();
protected String toolTip = "<b>Spot Detection</b>. <br /> "
+ "<ul><li>Input image is scaled by removing the mean value and dividing by the standard-deviation value of the background signal within the segmentation parent</li>"
+ "<li>Spots are detected using a seeded watershed algorithm in the laplacian transform.</li> "
+ "<li>Seeds are set on regional maxima of the laplacian transform, within the mask of the segmentation parent, with laplacian value superior to <em>Threshold for Seeds</em> and gaussian value superior to <em>Intensity Threshold for Seeds</em></li>"
+ "<li>If several scales are provided, the laplacian scale space will be computed (3D for 2D input, and 4D for 3D input) and the seeds will be 3D/4D local extrema in the scale space in order to determine at the same time their scale and spatial localization</li>"
+ "<li>Watershed propagation is done within the segmentation parent mask until laplacian values reach <em>Threshold for propagation</em></li>"
+ "<li>A quality parameter in computed as √(laplacian x gaussian) at the center of the spot</li><ul>";

public MutationSegmenter() {}

Expand Down Expand Up @@ -136,12 +139,18 @@ public boolean canBeTested(String p) {
public void setTestParameter(String p) {
testParam = p;
}

/**
* See {@link #run(boa.image.Image, boa.data_structure.StructureObjectProcessing, double[], int, double, double, double, java.util.List) }
* @param input
* @param structureIdx
* @param parent
* @return
*/
@Override
public RegionPopulation runSegmenter(Image input, int structureIdx, StructureObjectProcessing parent) {
return run(input, parent, getScale(), minSpotSize.getValue().intValue(), thresholdHigh.getValue().doubleValue(), thresholdLow.getValue().doubleValue(), intensityThreshold.getValue().doubleValue(), intermediateImages);
}

/*public RegionPopulation run(Image input, StructureObjectProcessing parent, double[] scale, int minSpotSize, double thresholdHigh , double thresholdLow, double intensityThreshold, List<Image> intermediateImages) {
if (input.getSizeZ()>1) {
// tester sur average, max, ou plan par plan
Expand Down Expand Up @@ -187,6 +196,7 @@ public Image getScaledInput() {
protected Image getSmoothedMap() {
if (smooth==null) throw new RuntimeException("Smooth map not initialized");
if (!smoothScaled) {
if (!smooth.sameDimensions(input)) smooth = smooth.cropWithOffset(input.getBoundingBox()); // map was computed on parent that differs from segmentation parent
ImageOperations.affineOperation2WithOffset(smooth, smooth, smoothScale/ms[1], -ms[0]);
smoothScaled=true;
}
Expand All @@ -196,18 +206,37 @@ protected Image getSmoothedMap() {
protected Image[] getLaplacianMap() {
if (lap==null) throw new RuntimeException("Laplacian map not initialized");
if (!lapScaled) {
for (int i = 0; i<lap.length; ++i) ImageOperations.affineOperation2WithOffset(lap[i], lap[i], 1/ms[1], 0); // no additive coefficient
for (int i = 0; i<lap.length; ++i) {
if (!lap[i].sameDimensions(input)) lap[i] = lap[i].cropWithOffset(input.getBoundingBox()); // map was computed on parent that differs from segmentation parent
ImageOperations.affineOperation2WithOffset(lap[i], lap[i], 1/ms[1], 0);
} // no additive coefficient
lapScaled=true;
}
return lap;
}
}
/**
* Spots are detected using a seeded watershed algorithm in the laplacian transform
* Input image is scaled by removing the mean value and dividing by the standard-deviation value of the background within the segmentation parent
* Seeds are set on regional maxima of the laplacian transform, within the mask of {@param parent}, with laplacian value superior to {@param thresholdSeeds} and gaussian value superior to {@param intensityThreshold}
* If several scales are provided, the laplacian scale space will be computed (3D for 2D input, and 4D for 3D input) and the seeds will be 3D/4D local extrema in the scale space in order to determine at the same time their scale and spatial localization
* Watershed propagation is done within the mask of {@param parent} until laplacian values reach {@param thresholdPropagation}
* A quality parameter in computed as √(laplacian x gaussian) at the center of the spot
* @param input pre-diltered image from wich spots will be detected
* @param parent segmentation parent
* @param scale scale for laplacian filtering, corresponds to size of the objects to be detected, if several, objects will be detected in the scale space
* @param minSpotSize under this size spots will be erased
* @param thresholdSeeds minimal laplacian value to segment a spot
* @param thresholdPropagation laplacian value at the border of spots
* @param intensityThreshold minimal gaussian value to semgent a spot
* @param intermediateImages for testing purpose
* @return segmented spots
*/
public RegionPopulation run(Image input, StructureObjectProcessing parent, double[] scale, int minSpotSize, double thresholdSeeds, double thresholdPropagation, double intensityThreshold, List<Image> intermediateImages) {
Arrays.sort(scale);
ImageMask parentMask = parent.getMask().getSizeZ()!=input.getSizeZ() ? new ImageMask2D(parent.getMask()) : parent.getMask();
this.pv.initPV(input, parentMask, smoothScale.getValue().doubleValue()) ;
if (pv.smooth==null || pv.lap==null) setMaps(computeMaps(input, input));
// TODO: test is Use Scale is taken into acount.

Image smooth = pv.getSmoothedMap();
Image[] lapSPZ = ((List<Image>)Image.mergeImagesInZ(Arrays.asList(pv.getLaplacianMap()))).toArray(new Image[0]); // in case there are several z
Expand Down Expand Up @@ -294,6 +323,7 @@ public RegionPopulation run(Image input, StructureObjectProcessing parent, doubl
}
return pop;
}

private static void setCenterAndQuality(Image map, Image map2, RegionPopulation pop, int z) {
SubPixelLocalizator.setSubPixelCenter(map, pop.getRegions(), true); // lap -> better in case of close objects
for (Region o : pop.getRegions()) { // quality criterion : sqrt (smooth * lap)
Expand Down Expand Up @@ -431,4 +461,8 @@ public RegionPopulation splitObject(StructureObject parent, int structureIdx, Re
public void setSplitVerboseMode(boolean verbose) {
manualSplitVerbose=verbose;
}
@Override
public String getToolTipText() {
return toolTip;
}
}
Loading

0 comments on commit 8078e8e

Please sign in to comment.