use of org.mastodon.tracking.detection.DetectionCreatorFactory in project mastodon-tracking by mastodon-sc.
the class SemiAutomaticTracker method compute.
@Override
public void compute(final Collection<Spot> input, final Map<String, Object> settings, final Model model) {
if (null == log)
log = logService;
if (null == input || input.isEmpty()) {
log.info("Spot collection to track is empty. Stopping.");
return;
}
final List<SourceAndConverter<?>> sources = data.getSources();
final ModelGraph graph = model.getGraph();
final SpatioTemporalIndex<Spot> spatioTemporalIndex = model.getSpatioTemporalIndex();
if (null != selectionModel)
selectionModel.clearSelection();
/*
* Quality and link-cost features. If they do not exist, create them and
* register them.
*/
final DetectionQualityFeature qualityFeature = DetectionQualityFeature.getOrRegister(model.getFeatureModel(), graph.vertices().getRefPool());
final LinkCostFeature linkCostFeature = LinkCostFeature.getOrRegister(model.getFeatureModel(), graph.edges().getRefPool());
/*
* Check settings map.
*/
ok = false;
final StringBuilder errorHandler = new StringBuilder();
if (!checkSettingsValidity(settings, errorHandler)) {
errorMessage = errorHandler.toString();
return;
}
/*
* Extract parameters from map.
*/
final int setup = (int) settings.get(KEY_SETUP_ID);
final double qualityFactor = (double) settings.get(KEY_QUALITY_FACTOR);
final double distanceFactor = (double) settings.get(KEY_DISTANCE_FACTOR);
final boolean forward = (boolean) settings.get(KEY_FORWARD_IN_TIME);
final int nTimepoints = (int) settings.get(KEY_N_TIMEPOINTS);
final boolean allowLinkingToExisting = (boolean) settings.get(KEY_ALLOW_LINKING_TO_EXISTING);
final boolean allowLinkingIfIncoming = (boolean) settings.get(KEY_ALLOW_LINKING_IF_HAS_INCOMING);
final boolean allowLinkingIfOutgoing = (boolean) settings.get(KEY_ALLOW_LINKING_IF_HAS_OUTGOING);
final boolean continueIfLinkExists = (boolean) settings.get(KEY_CONTINUE_IF_LINK_EXISTS);
final double neighborhoodFactor = Math.max(NEIGHBORHOOD_FACTOR, distanceFactor + 1.);
final boolean detectSpots = (boolean) settings.get(KEY_DETECT_SPOT);
/*
* Units.
*/
final String units = sources.get(setup).getSpimSource().getVoxelDimensions().unit();
/*
* First and last time-points.
*/
final int minTimepoint = 0;
final int maxTimepoint = data.getNumTimepoints() - 1;
/*
* Loop over each spot input.
*/
final double[][] cov = new double[3][3];
INPUT: for (final Spot first : input) {
graph.notifyGraphChanged();
/*
* Initialize motion-model for this spot.
*/
final MotionModel motionModel = initializeMotionModel(first, graph);
/*
* Loop over time.
*/
final int firstTimepoint = first.getTimepoint();
int tp = firstTimepoint;
final Spot source = model.getGraph().vertexRef();
source.refTo(first);
log.info("Semi-automatic tracking from spot " + first.getLabel() + ", going " + (forward ? "forward" : "backward") + " in time.");
TIME: while (Math.abs(tp - firstTimepoint) < nTimepoints && (forward ? tp < maxTimepoint : tp > minTimepoint)) {
// Are we canceled?
if (isCanceled()) {
log.warn("Canceled: " + getCancelReason());
return;
}
tp = (forward ? tp + 1 : tp - 1);
// Check if there is some data at this timepoint.
if (!DetectionUtil.isPresent(sources, setup, tp))
continue TIME;
// Best radius is smallest radius of ellipse.
source.getCovariance(cov);
eig.decomposeSymmetric(cov);
final double[] eigVals = eig.getRealEigenvalues();
double minEig = Double.POSITIVE_INFINITY;
for (int k = 0; k < eigVals.length; k++) minEig = Math.min(minEig, eigVals[k]);
final double radius = Math.sqrt(minEig);
// Does the source have a quality value?
final double threshold;
if (qualityFeature.isSet(source))
threshold = qualityFeature.value(source) * qualityFactor;
else
threshold = 0.;
/*
* Predict around what position to look for a candidate.
*/
final RealLocalizable predict = motionModel.predict();
/*
* Do we have an existing spot around this location, and do we
* have the right to link to it?
*/
spatioTemporalIndex.readLock().lock();
Spot target = null;
final double distance;
try {
final SpatialIndex<Spot> spatialIndex = spatioTemporalIndex.getSpatialIndex(tp);
final NearestNeighborSearch<Spot> nn = spatialIndex.getNearestNeighborSearch();
nn.search(predict);
target = nn.getSampler().get();
distance = nn.getDistance();
} finally {
spatioTemporalIndex.readLock().unlock();
}
final double[] pos = new double[3];
predict.localize(pos);
if (target != null && (distance < distanceFactor * radius)) {
// Select it.
if (null != selectionModel)
selectionModel.setSelected(target, true);
log.info(String.format(" - Found an exising spot at t=%d for spot %s close to candidate: %s.", tp, source.getLabel(), target.getLabel()));
if (!allowLinkingToExisting) {
log.info(" - Stopping semi-automatic tracking for spot " + first.getLabel() + ".");
continue INPUT;
}
// Are they connected?
final Link eref = graph.edgeRef();
final boolean connected = forward ? graph.getEdge(source, target, eref) != null : graph.getEdge(target, source, eref) != null;
if (!connected) {
// Should we link them?
if (!allowLinkingIfIncoming && !target.incomingEdges().isEmpty()) {
log.info(" - Existing spot has incoming links. Stopping semi-automatic tracking for spot " + first.getLabel() + ".");
continue INPUT;
}
if (!allowLinkingIfOutgoing && !target.outgoingEdges().isEmpty()) {
log.info(" - Existing spot has outgoing links. Stopping semi-automatic tracking for spot " + first.getLabel() + ".");
continue INPUT;
}
// Yes.
final Link edge;
graph.getLock().writeLock().lock();
try {
if (forward)
edge = graph.addEdge(source, target, eref).init();
else
edge = graph.addEdge(target, source, eref).init();
} finally {
graph.getLock().writeLock().unlock();
}
final double cost = motionModel.costTo(target);
log.info(String.format(" - Linking spot %s at t=%d to spot %s at t=%d with linking cost %.1f.", source.getLabel(), source.getTimepoint(), target.getLabel(), target.getTimepoint(), cost));
linkCostFeature.set(edge, cost);
if (null != navigationHandler)
navigationHandler.notifyNavigateToVertex(target);
if (null != focusModel)
focusModel.focusVertex(target);
} else {
// They are connected.
log.info(String.format(" - Spots %s at t=%d and %s at t=%d are already linked.", source.getLabel(), source.getTimepoint(), target.getLabel(), target.getTimepoint()));
if (!continueIfLinkExists) {
log.info(" - Stopping semi-automatic tracking for spot " + first.getLabel() + ".");
continue INPUT;
}
}
// Update tracker with the new target.
motionModel.update(target);
// Deselect source spot.
if (null != selectionModel)
selectionModel.setSelected(source, false);
// Select, focus and navigate to new spot.
if (null != navigationHandler)
navigationHandler.notifyNavigateToVertex(target);
if (null != selectionModel)
selectionModel.setSelected(target, true);
if (null != focusModel)
focusModel.focusVertex(target);
// Target becomes source and we loop over next time-point.
graph.releaseRef(eref);
source.refTo(target);
continue TIME;
} else if (detectSpots) {
/*
* There is no candidate around the predicted position, or
* we do not have the right to link to it. We therefore have
* to search for candidates from the image.
*/
/*
* Build ROI to process.
*/
final AffineTransform3D transform = DetectionUtil.getTransform(sources, tp, setup, 0);
final Point center = new Point(3);
transform.applyInverse(new Round<>(center), predict);
final long x = center.getLongPosition(0);
final long y = center.getLongPosition(1);
final long rx = (long) Math.ceil(neighborhoodFactor * radius);
final long ry = (long) Math.ceil(neighborhoodFactor * radius);
final FinalInterval roi;
if (DetectionUtil.numDimensions(sources, setup, tp) == 3) {
final long z = center.getLongPosition(2);
final long rz = (long) Math.ceil(neighborhoodFactor * radius);
final long[] min = new long[] { x - rx, y - ry, z - rz };
final long[] max = new long[] { x + rx, y + ry, z + rz };
roi = new FinalInterval(min, max);
} else {
final long[] min = new long[] { x - rx, y - ry };
final long[] max = new long[] { x + rx, y + ry };
roi = new FinalInterval(min, max);
}
/*
* User built-in detector.
*/
final List<Detection> detections = new ArrayList<>();
final DetectionCreatorFactory detectionCreator = createDetectionCreatorFactoryFor(detections);
// Configure detector.
final Map<String, Object> detectorSettings = DetectionUtil.getDefaultDetectorSettingsMap();
detectorSettings.put(KEY_RADIUS, Double.valueOf(radius));
detectorSettings.put(KEY_THRESHOLD, Double.valueOf(threshold));
detectorSettings.put(KEY_SETUP_ID, Integer.valueOf(setup));
detectorSettings.put(KEY_MIN_TIMEPOINT, Integer.valueOf(tp));
detectorSettings.put(KEY_MAX_TIMEPOINT, Integer.valueOf(tp));
detectorSettings.put(KEY_ROI, roi);
final DetectorOp detector = (DetectorOp) Inplaces.binary1(ops(), DoGDetectorOp.class, detectionCreator, sources, detectorSettings);
detector.mutate1(detectionCreator, sources);
if (detections.isEmpty()) {
log.info(String.format(" - No target spot found at t=%d for spot %s above desired quality threshold.", tp, source.getLabel()));
continue INPUT;
}
/*
* Find a suitable candidate with largest quality.
*/
// Sort peaks by quality.
detections.sort(detectionComparator);
boolean found = false;
Detection candidate = null;
double sqDist = 0.;
for (final Detection p : detections) {
// Compute square distance.
sqDist = 0.;
for (int d = 0; d < source.numDimensions(); d++) {
final double dx = p.getDoublePosition(d) - source.getDoublePosition(d);
sqDist += dx * dx;
}
if (sqDist < distanceFactor * distanceFactor * radius * radius) {
found = true;
candidate = p;
break;
}
}
if (!found) {
log.info(String.format(" - Suitable spot found at t=%d, but outside the tolerance radius for spot %s (at a distance of %.1f %s).", tp, source.getLabel(), Math.sqrt(sqDist), units));
log.info(" - Stopping semi-automatic tracking for spot " + first.getLabel() + ".");
continue INPUT;
}
candidate.localize(pos);
/*
* Let's keep this candidate.
*/
graph.getLock().writeLock().lock();
final Link eref = graph.edgeRef();
final Spot vref = graph.vertexRef();
final Link edge;
try {
target = graph.addVertex(vref).init(tp, pos, radius);
if (forward)
edge = graph.addEdge(source, target, eref).init();
else
edge = graph.addEdge(target, source, eref).init();
} finally {
graph.getLock().writeLock().unlock();
}
final double cost = motionModel.costTo(target);
final double quality = candidate.quality;
log.info(String.format(" - Linking spot %s at t=%d to spot %s at t=%d with linking cost %.1f.", source.getLabel(), source.getTimepoint(), target.getLabel(), target.getTimepoint(), cost));
linkCostFeature.set(edge, cost);
qualityFeature.set(target, quality);
// Update tracker with the new target.
motionModel.update(target);
// Deselect source spot.
if (null != selectionModel)
selectionModel.setSelected(source, false);
// Select, focus and navigate to new spot.
if (null != navigationHandler)
navigationHandler.notifyNavigateToVertex(target);
if (null != selectionModel)
selectionModel.setSelected(target, true);
if (null != focusModel)
focusModel.focusVertex(target);
source.refTo(target);
graph.releaseRef(eref);
graph.releaseRef(vref);
} else {
/*
* Could not find an existing spot and cannot create new
* one. We have to stop.
*/
log.info(" - No spot to link to. Stopping semi-automatic tracking for spot " + first.getLabel() + ".");
continue INPUT;
}
}
log.info(" - Finished semi-automatic tracking for spot " + first.getLabel() + ".");
}
/*
* Return.
*/
graph.notifyGraphChanged();
ok = true;
}
use of org.mastodon.tracking.detection.DetectionCreatorFactory in project mastodon-tracking by mastodon-sc.
the class AbstractSpotDetectorOp method exec.
protected void exec(final List<SourceAndConverter<?>> sources, final ModelGraph graph, final Class<? extends DetectorOp> cl) {
ok = false;
final long start = System.currentTimeMillis();
if (null == qualityFeature)
qualityFeature = new DetectionQualityFeature(graph.vertices().getRefPool());
/*
* Resolve add detection behavior.
*/
final DetectionCreatorFactory detectionCreator;
if (null == sti) {
detectionCreator = MamutDetectionCreatorFactories.getAddDetectionCreatorFactory(graph, qualityFeature);
} else {
DetectionBehavior detectionBehavior = DetectionBehavior.ADD;
final String addBehavior = (String) settings.get(KEY_ADD_BEHAVIOR);
if (null != addBehavior) {
try {
detectionBehavior = MamutDetectionCreatorFactories.DetectionBehavior.valueOf(addBehavior);
} catch (final IllegalArgumentException e) {
}
}
detectionCreator = detectionBehavior.getFactory(graph, qualityFeature, sti);
}
this.detector = (DetectorOp) Inplaces.binary1(ops(), cl, detectionCreator, sources, settings);
detector.setLogger(log);
detector.setStatusService(statusService);
try {
detector.mutate1(detectionCreator, sources);
ok = detector.isSuccessful();
if (!ok)
errorMessage = detector.getErrorMessage();
} catch (final OutOfMemoryError oome) {
errorMessage = "Not enough memory to process the image.";
ok = false;
return;
} finally {
final long end = System.currentTimeMillis();
processingTime = end - start;
this.detector = null;
}
}
Aggregations