use of uk.ac.sussex.gdsc.core.match.ClassificationResult 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.ClassificationResult in project GDSC-SMLM by aherbert.
the class FilterAnalysis method runAnalysis.
private int runAnalysis(Consumer<String> output, FilterSet filterSet, List<MemoryPeakResults> resultsList, int count, final int total) {
final double[] xValues = (isHeadless) ? null : new double[filterSet.size()];
final double[] yValues = (isHeadless) ? null : new double[filterSet.size()];
int index = 0;
filterSet.sort();
// Track if all the filters are the same type. If so then we can calculate the sensitivity of
// each parameter.
String type = null;
boolean allSameType = true;
Filter maxFilter = null;
double maxScore = -1;
for (final Filter filter : filterSet.getFilters()) {
if (count++ % 16 == 0) {
IJ.showProgress(count, total);
}
final ClassificationResult s = runFilter(output, filter, resultsList);
if (type == null) {
type = filter.getType();
} else if (!type.equals(filter.getType())) {
allSameType = false;
}
final double jaccard = s.getJaccard();
if (maxScore < jaccard) {
maxScore = jaccard;
maxFilter = filter;
}
if (xValues != null && yValues != null) {
xValues[index] = filter.getNumericalValue();
yValues[index++] = jaccard;
}
}
if (allSameType && settings.calculateSensitivity) {
final FilterScore filterScore = bestFilter.get(type);
if (filterScore != null) {
if (filterScore.score < maxScore) {
filterScore.update(maxFilter, maxScore);
}
} else {
bestFilter.put(type, new FilterScore(maxFilter, maxScore));
bestFilterOrder.add(type);
}
}
// Add spacer at end of each result set
if (settings.showResultsTable) {
output.accept("");
}
if (!isHeadless && settings.plotTopN > 0 && xValues != null) {
// Check the xValues are unique. Since the filters have been sorted by their
// numeric value we only need to compare adjacent entries.
boolean unique = true;
for (int ii = 0; ii < xValues.length - 1; ii++) {
if (xValues[ii] == xValues[ii + 1]) {
unique = false;
break;
}
}
String xAxisName = filterSet.getValueName();
// Check the values all refer to the same property
for (final Filter filter : filterSet.getFilters()) {
if (!xAxisName.equals(filter.getNumericalValueName())) {
unique = false;
break;
}
}
if (!unique) {
// If not unique then renumber them and use an arbitrary label
xAxisName = "Filter";
for (int ii = 0; ii < xValues.length; ii++) {
xValues[ii] = ii + 1.0;
}
}
final String title = filterSet.getName();
// Check if a previous filter set had the same name, update if necessary
final NamedPlot plot = getNamedPlot(title);
if (plot == null) {
plots.add(new NamedPlot(title, xAxisName, xValues, yValues));
} else {
plot.updateValues(xAxisName, xValues, yValues);
}
if (plots.size() > settings.plotTopN) {
Collections.sort(plots, NamedPlot::compare);
plots.remove(plots.size() - 1);
}
}
return count;
}
use of uk.ac.sussex.gdsc.core.match.ClassificationResult in project GDSC-SMLM by aherbert.
the class FilterAnalysis method runFilter.
private ClassificationResult runFilter(Consumer<String> output, Filter filter, List<MemoryPeakResults> resultsList) {
final ClassificationResult s = filter.score(resultsList);
if (settings.showResultsTable) {
final StringBuilder sb = new StringBuilder();
sb.append(filter.getName()).append('\t');
sb.append(s.getTruePositives() + s.getFalsePositives()).append('\t');
sb.append(s.getTruePositives()).append('\t');
sb.append(s.getFalsePositives()).append('\t');
sb.append(s.getTrueNegatives()).append('\t');
sb.append(s.getFalseNegatives()).append('\t');
sb.append(s.getJaccard()).append('\t');
sb.append(s.getPrecision()).append('\t');
sb.append(s.getRecall()).append('\t');
sb.append(s.getF1Score());
output.accept(sb.toString());
}
return s;
}
use of uk.ac.sussex.gdsc.core.match.ClassificationResult in project GDSC-SMLM by aherbert.
the class FilterAnalysis method calculateSensitivity.
private void calculateSensitivity(List<MemoryPeakResults> resultsList) {
if (!settings.calculateSensitivity) {
return;
}
if (!bestFilter.isEmpty()) {
IJ.showStatus("Calculating sensitivity ...");
final Consumer<String> output = createSensitivityWindow();
int currentIndex = 0;
for (final String type : bestFilterOrder) {
IJ.showProgress(currentIndex++, bestFilter.size());
final Filter filter = bestFilter.get(type).filter;
final ClassificationResult s = filter.score(resultsList);
final String message = type + "\t\t\t" + MathUtils.rounded(s.getJaccard(), 4) + "\t\t" + MathUtils.rounded(s.getPrecision(), 4) + "\t\t" + MathUtils.rounded(s.getRecall(), 4);
output.accept(message);
// List all the parameters that can be adjusted.
final int parameters = filter.getNumberOfParameters();
for (int index = 0; index < parameters; index++) {
// For each parameter compute as upward + downward delta and get the average gradient
final Filter higher = filter.adjustParameter(index, settings.delta);
final Filter lower = filter.adjustParameter(index, -settings.delta);
final ClassificationResult sHigher = higher.score(resultsList);
final ClassificationResult sLower = lower.score(resultsList);
final StringBuilder sb = new StringBuilder();
sb.append('\t').append(filter.getParameterName(index)).append('\t');
sb.append(MathUtils.rounded(filter.getParameterValue(index), 4)).append('\t');
final double dx1 = higher.getParameterValue(index) - filter.getParameterValue(index);
final double dx2 = filter.getParameterValue(index) - lower.getParameterValue(index);
addSensitivityScore(sb, s.getJaccard(), sHigher.getJaccard(), sLower.getJaccard(), dx1, dx2);
addSensitivityScore(sb, s.getPrecision(), sHigher.getPrecision(), sLower.getPrecision(), dx1, dx2);
addSensitivityScore(sb, s.getRecall(), sHigher.getRecall(), sLower.getRecall(), dx1, dx2);
output.accept(sb.toString());
}
}
output.accept("-=-=-=-");
ImageJUtils.finished();
}
}
use of uk.ac.sussex.gdsc.core.match.ClassificationResult in project GDSC-SMLM by aherbert.
the class BenchmarkFilterAnalysis method createResult.
private StringBuilder createResult(DirectFilter filter, FractionClassificationResult result, String resultsPrefix2) {
final StringBuilder sb = new StringBuilder(resultsPrefix);
sb.append(filter.getName()).append(resultsPrefix2).append(fitResultData.resultsPrefix3);
int index = 0;
// Integer results
if (settings.requireIntegerResults) {
final ClassificationResult r2 = createIntegerResult(result);
add(sb, r2.getTruePositives(), index++);
add(sb, r2.getFalsePositives(), index++);
add(sb, r2.getFalseNegatives(), index++);
add(sb, r2.getPrecision(), index++);
add(sb, r2.getRecall(), index++);
add(sb, r2.getF1Score(), index++);
add(sb, r2.getJaccard(), index++);
} else {
index += 7;
}
addCount(sb, result.getTruePositives(), index++);
addCount(sb, result.getFalsePositives(), index++);
addCount(sb, result.getFalseNegatives(), index++);
add(sb, result.getPrecision(), index++);
add(sb, result.getRecall(), index++);
add(sb, result.getF1Score(), index++);
add(sb, result.getJaccard(), index);
return sb;
}
Aggregations