use of uk.ac.sussex.gdsc.core.match.Coordinate in project GDSC-SMLM by aherbert.
the class TraceMatchCalculator method compareCoordinates.
@SuppressWarnings("null")
private void compareCoordinates(MemoryPeakResults results1, MemoryPeakResults results2, MemoryPeakResults results3, double distanceThreshold) {
final Pulse[] p1 = extractPulses(results1);
final Pulse[] p2 = extractPulses(results2);
final Pulse[] p3 = extractPulses(results3);
final List<Pulse> tp = null;
List<Pulse> fp = null;
List<Pulse> fn = null;
List<PointPair> pairs = null;
final List<Pulse> tp2 = null;
List<Pulse> fp2 = null;
List<Pulse> fn2 = null;
List<PointPair> pairs2 = null;
if (settings.showPairs) {
pairs = new LinkedList<>();
fp = new LinkedList<>();
fn = new LinkedList<>();
pairs2 = new LinkedList<>();
fp2 = new LinkedList<>();
fn2 = new LinkedList<>();
}
final MatchResult result = MatchCalculator.analyseResults2D(p1, p2, distanceThreshold, tp, fp, fn, pairs);
final MatchResult result2 = MatchCalculator.analyseResults2D(p1, p3, distanceThreshold, tp2, fp2, fn2, pairs2);
// Create output
Consumer<String> resultsOutput;
if (!java.awt.GraphicsEnvironment.isHeadless()) {
final TextWindow resultsWindow = ImageJUtils.refresh(resultsWindowRef, () -> new TextWindow(TITLE + " Results", createResultsHeader(), "", 900, 300));
resultsOutput = resultsWindow::append;
if (settings.showPairs) {
if (p3 == null) {
// Produce a pairs output
final WindowAndPainter wap = refresh(pairsWindowRef, true, resultsWindow, results1);
// Add the unmatched points
WindowManager.getIDList();
for (final Coordinate c : fn) {
pairs.add(new PointPair(c, null));
}
for (final Coordinate c : fp) {
pairs.add(new PointPair(null, c));
}
final List<? extends PointPair> sortedPairs = sort(pairs);
for (final PointPair pair : sortedPairs) {
addPairResult(wap.textWindow, pair);
}
} else {
// Produce a triple output
final WindowAndPainter wap = refresh(triplesWindowRef, false, resultsWindow, results1);
final HashMap<Pulse, Triple> map = new HashMap<>();
final ArrayList<Triple> triples = new ArrayList<>(pairs.size());
for (final PointPair pair : pairs) {
final Pulse p = (Pulse) pair.getPoint1();
final Triple t = new Triple(p, (Pulse) pair.getPoint2(), null);
triples.add(t);
map.put(p, t);
}
// Complete the reference set of points
for (final Coordinate c : fn) {
final Pulse p = (Pulse) c;
final Triple t = new Triple(p, null, null);
triples.add(t);
map.put(p, t);
}
// Add the unmatched points
for (final Coordinate c : fp) {
triples.add(new Triple(null, (Pulse) c, null));
}
for (final Coordinate c : fp2) {
triples.add(new Triple(null, null, (Pulse) c));
}
// Add the results from the second match
for (final PointPair pair : pairs2) {
final Pulse p = (Pulse) pair.getPoint1();
final Pulse pp = (Pulse) pair.getPoint2();
final Triple triple = map.get(p);
if (triple != null) {
triple.p3 = pp;
} else {
triples.add(new Triple(null, null, pp));
}
}
final List<? extends Triple> sortedTriples = sort(triples);
for (final Triple t : sortedTriples) {
addTripleResult(wap.textWindow, t);
}
}
}
} else {
if (writeHeader.compareAndSet(true, false)) {
IJ.log(createResultsHeader());
}
resultsOutput = IJ::log;
}
final StringBuilder sb = new StringBuilder();
addResult(resultsOutput, sb, settings.inputOption1, settings.inputOption2, distanceThreshold, result);
if (p3 != null) {
addResult(resultsOutput, sb, settings.inputOption1, settings.inputOption3, distanceThreshold, result2);
}
}
use of uk.ac.sussex.gdsc.core.match.Coordinate in project GDSC-SMLM by aherbert.
the class SpotFinderPreview method run.
private void run(ImageProcessor ip, MaximaSpotFilter filter) {
if (refreshing) {
return;
}
currentSlice = imp.getCurrentSlice();
final Rectangle bounds = ip.getRoi();
// Crop to the ROI
FloatProcessor fp = ip.crop().toFloat(0, null);
float[] data = (float[]) fp.getPixels();
final int width = fp.getWidth();
final int height = fp.getHeight();
// Store the mean bias and gain of the region data.
// This is used to correctly overlay the filtered data on the original image.
double bias = 0;
double gain = 1;
boolean adjust = false;
// Set weights
final CameraModel cameraModel = fitConfig.getCameraModel();
if (!(cameraModel instanceof FakePerPixelCameraModel)) {
// This should be done on the normalised data
final float[] w = cameraModel.getNormalisedWeights(bounds);
filter.setWeights(w, width, height);
data = data.clone();
if (data.length < ip.getPixelCount()) {
adjust = true;
bias = MathUtils.sum(cameraModel.getBias(bounds)) / data.length;
gain = MathUtils.sum(cameraModel.getGain(bounds)) / data.length;
}
cameraModel.removeBiasAndGain(bounds, data);
}
final Spot[] spots = filter.rank(data, width, height);
data = filter.getPreprocessedData();
final int size = spots.length;
if (topNScrollBar != null) {
topNScrollBar.setMaximum(size);
selectScrollBar.setMaximum(size);
}
fp = new FloatProcessor(width, height, data);
final FloatProcessor out = new FloatProcessor(ip.getWidth(), ip.getHeight());
out.copyBits(ip, 0, 0, Blitter.COPY);
if (adjust) {
fp.multiply(gain);
fp.add(bias);
}
out.insert(fp, bounds.x, bounds.y);
final double min = fp.getMin();
final double max = fp.getMax();
out.setMinAndMax(min, max);
final Overlay o = new Overlay();
o.add(new ImageRoi(0, 0, out));
if (label != null) {
// Get results for frame
final Coordinate[] actual = ResultsMatchCalculator.getCoordinates(actualCoordinates, imp.getCurrentSlice());
final Coordinate[] predicted = new Coordinate[size];
for (int i = 0; i < size; i++) {
predicted[i] = new BasePoint(spots[i].x + bounds.x, spots[i].y + bounds.y);
}
// Compute assignments
final LocalList<FractionalAssignment> fractionalAssignments = new LocalList<>(3 * predicted.length);
final double matchDistance = settings.distance * fitConfig.getInitialPeakStdDev();
final RampedScore score = RampedScore.of(matchDistance, matchDistance * settings.lowerDistance / 100, false);
final double dmin = matchDistance * matchDistance;
final int nActual = actual.length;
final int nPredicted = predicted.length;
for (int j = 0; j < nPredicted; j++) {
// Centre in the middle of the pixel
final float x = predicted[j].getX() + 0.5f;
final float y = predicted[j].getY() + 0.5f;
// Any spots that match
for (int i = 0; i < nActual; i++) {
final double dx = (x - actual[i].getX());
final double dy = (y - actual[i].getY());
final double d2 = dx * dx + dy * dy;
if (d2 <= dmin) {
final double d = Math.sqrt(d2);
final double s = score.score(d);
if (s == 0) {
continue;
}
double distance = 1 - s;
if (distance == 0) {
// In the case of a match below the distance thresholds
// the distance will be 0. To distinguish between candidates all below
// the thresholds just take the closest.
// We know d2 is below dmin so we subtract the delta.
distance -= (dmin - d2);
}
// Store the match
fractionalAssignments.add(new ImmutableFractionalAssignment(i, j, distance, s));
}
}
}
final FractionalAssignment[] assignments = fractionalAssignments.toArray(new FractionalAssignment[0]);
// Compute matches
final RankedScoreCalculator calc = RankedScoreCalculator.create(assignments, nActual - 1, nPredicted - 1);
final boolean save = settings.showTP || settings.showFP;
final double[] calcScore = calc.score(nPredicted, settings.multipleMatches, save);
final ClassificationResult result = RankedScoreCalculator.toClassificationResult(calcScore, nActual);
// Compute AUC and max jaccard (and plot)
final double[][] curve = RankedScoreCalculator.getPrecisionRecallCurve(assignments, nActual, nPredicted);
final double[] precision = curve[0];
final double[] recall = curve[1];
final double[] jaccard = curve[2];
final double auc = AucCalculator.auc(precision, recall);
// Show scores
final String scoreLabel = String.format("Slice=%d, AUC=%s, R=%s, Max J=%s", imp.getCurrentSlice(), MathUtils.rounded(auc), MathUtils.rounded(result.getRecall()), MathUtils.rounded(MathUtils.maxDefault(0, jaccard)));
setLabel(scoreLabel);
// Plot
String title = TITLE + " Performance";
Plot plot = new Plot(title, "Spot Rank", "");
final double[] rank = SimpleArrayUtils.newArray(precision.length, 0, 1.0);
plot.setLimits(0, nPredicted, 0, 1.05);
plot.setColor(Color.blue);
plot.addPoints(rank, precision, Plot.LINE);
plot.setColor(Color.red);
plot.addPoints(rank, recall, Plot.LINE);
plot.setColor(Color.black);
plot.addPoints(rank, jaccard, Plot.LINE);
plot.setColor(Color.black);
plot.addLabel(0, 0, scoreLabel);
final WindowOrganiser windowOrganiser = new WindowOrganiser();
ImageJUtils.display(title, plot, 0, windowOrganiser);
title = TITLE + " Precision-Recall";
plot = new Plot(title, "Recall", "Precision");
plot.setLimits(0, 1, 0, 1.05);
plot.setColor(Color.red);
plot.addPoints(recall, precision, Plot.LINE);
plot.drawLine(recall[recall.length - 1], precision[recall.length - 1], recall[recall.length - 1], 0);
plot.setColor(Color.black);
plot.addLabel(0, 0, scoreLabel);
ImageJUtils.display(title, plot, 0, windowOrganiser);
windowOrganiser.tile();
// Create Rois for TP and FP
if (save) {
final double[] matchScore = RankedScoreCalculator.getMatchScore(calc.getScoredAssignments(), nPredicted);
int matches = 0;
for (int i = 0; i < matchScore.length; i++) {
if (matchScore[i] != 0) {
matches++;
}
}
if (settings.showTP) {
final float[] x = new float[matches];
final float[] y = new float[x.length];
int count = 0;
for (int i = 0; i < matchScore.length; i++) {
if (matchScore[i] != 0) {
final BasePoint p = (BasePoint) predicted[i];
x[count] = p.getX() + 0.5f;
y[count] = p.getY() + 0.5f;
count++;
}
}
addRoi(0, o, x, y, count, Color.green);
}
if (settings.showFP) {
final float[] x = new float[nPredicted - matches];
final float[] y = new float[x.length];
int count = 0;
for (int i = 0; i < matchScore.length; i++) {
if (matchScore[i] == 0) {
final BasePoint p = (BasePoint) predicted[i];
x[count] = p.getX() + 0.5f;
y[count] = p.getY() + 0.5f;
count++;
}
}
addRoi(0, o, x, y, count, Color.red);
}
}
} else {
final WindowOrganiser wo = new WindowOrganiser();
// Option to show the number of neighbours within a set pixel box radius
final int[] count = spotFilterHelper.countNeighbours(spots, width, height, settings.neighbourRadius);
// Show as histogram the totals...
new HistogramPlotBuilder(TITLE, StoredData.create(count), "Neighbours").setIntegerBins(true).setPlotLabel("Radius = " + settings.neighbourRadius).show(wo);
// TODO - Draw n=0, n=1 on the image overlay
final LUT lut = LutHelper.createLut(LutColour.FIRE_LIGHT);
// These are copied by the ROI
final float[] x = new float[1];
final float[] y = new float[1];
// Plot the intensity
final double[] intensity = new double[size];
final double[] rank = SimpleArrayUtils.newArray(size, 1, 1.0);
final int top = (settings.topN > 0) ? settings.topN : size;
final int size_1 = size - 1;
for (int i = 0; i < size; i++) {
intensity[i] = spots[i].intensity;
if (i < top) {
x[0] = spots[i].x + bounds.x + 0.5f;
y[0] = spots[i].y + bounds.y + 0.5f;
final Color c = LutHelper.getColour(lut, size_1 - i, size);
addRoi(0, o, x, y, 1, c, 2, 1);
}
}
final String title = TITLE + " Intensity";
final Plot plot = new Plot(title, "Rank", "Intensity");
plot.setColor(Color.blue);
plot.addPoints(rank, intensity, Plot.LINE);
if (settings.topN > 0 && settings.topN < size) {
plot.setColor(Color.magenta);
plot.drawLine(settings.topN, 0, settings.topN, intensity[settings.topN - 1]);
}
if (settings.select > 0 && settings.select < size) {
plot.setColor(Color.yellow);
final int index = settings.select - 1;
final double in = intensity[index];
plot.drawLine(settings.select, 0, settings.select, in);
x[0] = spots[index].x + bounds.x + 0.5f;
y[0] = spots[index].y + bounds.y + 0.5f;
final Color c = LutHelper.getColour(lut, size_1 - settings.select, size);
addRoi(0, o, x, y, 1, c, 3, 3);
plot.setColor(Color.black);
plot.addLabel(0, 0, "Selected spot intensity = " + MathUtils.rounded(in));
}
ImageJUtils.display(title, plot, 0, wo);
wo.tile();
}
imp.setOverlay(o);
}
use of uk.ac.sussex.gdsc.core.match.Coordinate in project GDSC-SMLM by aherbert.
the class ResultsMatchCalculator method runCompareCoordinates.
@SuppressWarnings("null")
private void runCompareCoordinates(MemoryPeakResults results1, MemoryPeakResults results2) {
final boolean requirePairs = settings.showPairs || settings.isSaveClassifications();
final boolean saveMatched = settings.isSaveMatched();
final boolean saveUnmatched = settings.isSaveUnmatched();
final TextFilePeakResults fileResults = createFilePeakResults(results2);
final List<PointPair> allMatches = new LinkedList<>();
final List<PointPair> pairs = (requirePairs) ? new LinkedList<>() : null;
final double maxDistance = settings.distanceThreshold + settings.increments * settings.delta;
// Divide the results into time points
final TIntObjectHashMap<List<Coordinate>> actualCoordinates = getCoordinates(results1, settings.coordinateMethod1);
final TIntObjectHashMap<List<Coordinate>> predictedCoordinates = getCoordinates(results2, settings.coordinateMethod2);
int n1 = 0;
int n2 = 0;
// Process each time point
for (final int t : getTimepoints(actualCoordinates, predictedCoordinates)) {
final Coordinate[] actual = getCoordinates(actualCoordinates, t);
final Coordinate[] predicted = getCoordinates(predictedCoordinates, t);
final List<Coordinate> tp = null;
List<Coordinate> fp = null;
List<Coordinate> fn = null;
final List<PointPair> matches = new LinkedList<>();
if (requirePairs) {
fp = new LinkedList<>();
fn = new LinkedList<>();
}
MatchCalculator.analyseResults2D(actual, predicted, maxDistance, tp, fp, fn, matches);
// Aggregate
n1 += actual.length;
n2 += predicted.length;
allMatches.addAll(matches);
if (settings.showPairs) {
pairs.addAll(matches);
for (final Coordinate c : fn) {
pairs.add(new PointPair(c, null));
}
for (final Coordinate c : fp) {
pairs.add(new PointPair(null, c));
}
}
if (fileResults != null) {
// Matches are marked in the original value with 1 for true, 0 for false
if (saveMatched) {
for (final PointPair pair : matches) {
PeakResult result = ((PeakResultPoint) pair.getPoint2()).getPeakResult();
result = result.copy();
result.setOrigValue(1);
fileResults.add(result);
}
}
if (saveUnmatched) {
for (final Coordinate c : fp) {
PeakResult result = ((PeakResultPoint) c).getPeakResult();
result = result.copy();
result.setOrigValue(0);
fileResults.add(result);
}
}
}
}
if (fileResults != null) {
fileResults.end();
}
final boolean doIdAnalysis1 = settings.idAnalysis && haveIds(results1);
final boolean doIdAnalysis2 = settings.idAnalysis && haveIds(results2);
// Create output.
// This supports headless mode with just the results table
// or graphical mode with a results table and pairs window.
final boolean headless = java.awt.GraphicsEnvironment.isHeadless();
TextWindow resultsWindow = null;
if (!headless) {
resultsWindow = (settings.showTable) ? createResultsWindow(doIdAnalysis1 || doIdAnalysis2) : null;
showPairs(results1, pairs, resultsWindow);
}
showResults(results1, results2, allMatches, n1, n2, doIdAnalysis1, doIdAnalysis2, resultsWindow);
savePairs(results1, results2, allMatches);
}
use of uk.ac.sussex.gdsc.core.match.Coordinate in project GDSC-SMLM by aherbert.
the class ResultsMatchCalculator method getTimepoints.
/**
* Merge the time points from each map into a single sorted list of unique time points.
*
* @param actualCoordinates the actual coordinates
* @param predictedCoordinates the predicted coordinates
* @return a list of time points
*/
private static int[] getTimepoints(TIntObjectHashMap<List<Coordinate>> actualCoordinates, TIntObjectHashMap<List<Coordinate>> predictedCoordinates) {
// Do inline to avoid materialising the keys arrays
final TIntHashSet hashset = new TIntHashSet(Math.max(actualCoordinates.size(), predictedCoordinates.size()));
final TIntProcedure p = value -> {
hashset.add(value);
return true;
};
actualCoordinates.forEachKey(p);
predictedCoordinates.forEachKey(p);
final int[] set = hashset.toArray();
Arrays.sort(set);
return set;
}
use of uk.ac.sussex.gdsc.core.match.Coordinate in project GDSC-SMLM by aherbert.
the class ResultsMatchCalculator method compareCoordinates.
/**
* Compare the coordinates on a frame-by-frame basis.
*
* @param actualCoordinates the actual coordinates
* @param predictedCoordinates the predicted coordinates
* @param distance the distance
* @return the match result
*/
public static MatchResult compareCoordinates(TIntObjectHashMap<List<Coordinate>> actualCoordinates, TIntObjectHashMap<List<Coordinate>> predictedCoordinates, double distance) {
int tp = 0;
int fp = 0;
int fn = 0;
// Process each time point
for (final int t : getTimepoints(actualCoordinates, predictedCoordinates)) {
final Coordinate[] actual = getCoordinates(actualCoordinates, t);
final Coordinate[] predicted = getCoordinates(predictedCoordinates, t);
final MatchResult r = MatchCalculator.analyseResults2D(actual, predicted, distance);
// Aggregate
tp += r.getTruePositives();
fp += r.getFalsePositives();
fn += r.getFalseNegatives();
}
return new MatchResult(tp, fp, fn, 0);
}
Aggregations