use of uk.ac.sussex.gdsc.smlm.results.PeakResult in project GDSC-SMLM by aherbert.
the class HysteresisFilter method setup.
@Override
public void setup(MemoryPeakResults peakResults) {
ok = new HashSet<>();
// Create a set of candidates and valid peaks
final MemoryPeakResults traceResults = new MemoryPeakResults();
// Initialise peaks to check
final LinkedList<PeakResult> candidates = new LinkedList<>();
peakResults.forEach((PeakResultProcedure) result -> {
switch(getStatus(result)) {
case OK:
ok.add(result);
traceResults.add(result);
break;
case CANDIDATE:
candidates.add(result);
traceResults.add(result);
break;
default:
break;
}
});
if (candidates.isEmpty()) {
// No candidates for tracing so just return
return;
}
double distanceThreshold;
switch(searchDistanceMode) {
case 1:
distanceThreshold = searchDistance / peakResults.getNmPerPixel();
break;
case 0:
default:
distanceThreshold = getSearchDistanceUsingCandidates(peakResults, candidates);
}
if (distanceThreshold <= 0) {
return;
}
// This must be in frames
int myTimeThreshold;
if (timeThresholdMode == 1) {
// time threshold is in Seconds.
// Default to 1 frame if not calibrated.
myTimeThreshold = 1;
if (peakResults.hasCalibration()) {
// Convert time threshold in seconds to frames
final CalibrationReader cr = peakResults.getCalibrationReader();
final double et = cr.getExposureTime();
if (et > 0) {
myTimeThreshold = (int) Math.round((this.timeThreshold / et));
}
}
} else {
// frames
myTimeThreshold = (int) this.timeThreshold;
}
if (myTimeThreshold <= 0) {
return;
}
// Trace through candidates
final TraceManager tm = new TraceManager(traceResults);
tm.setTraceMode(TraceMode.LATEST_FORERUNNER);
tm.traceMolecules(distanceThreshold, myTimeThreshold);
final Trace[] traces = tm.getTraces();
for (final Trace trace : traces) {
if (trace.size() > 1) {
// Check if the trace touches a valid point
boolean isOk = false;
for (int i = 0; i < trace.size(); i++) {
if (ok.contains(trace.get(i))) {
isOk = true;
break;
}
}
// Add the entire trace to the OK points
if (isOk) {
for (int i = 0; i < trace.size(); i++) {
ok.add(trace.get(i));
}
}
}
}
}
use of uk.ac.sussex.gdsc.smlm.results.PeakResult in project GDSC-SMLM by aherbert.
the class Filter method score.
/**
* Filter the results and return the performance score. Allows benchmarking the filter by marking
* the results as true or false.
*
* <p>Any input PeakResult with an original value that is not zero will be treated as a true
* result, all other results are false. The filter is run and the results are marked as true
* positive, false negative and false positive.
*
* <p>The number of consecutive rejections are counted per frame. When the configured number of
* failures is reached all remaining results for the frame are rejected. This assumes the results
* are ordered by the frame.
*
* @param resultsList a list of results to analyse
* @param failures the number of failures to allow per frame before all peaks are rejected
* @return the score
*/
public ClassificationResult score(List<MemoryPeakResults> resultsList, final int failures) {
final int[] s = new int[4];
for (final MemoryPeakResults peakResults : resultsList) {
setup(peakResults);
final FrameCounter counter = new FrameCounter();
peakResults.forEach((PeakResultProcedure) peak -> {
counter.advanceAndReset(peak.getFrame());
final boolean isTrue = peak.getOrigValue() != 0;
final boolean isPositive;
if (counter.getCount() > failures) {
isPositive = false;
} else {
isPositive = accept(peak);
}
if (isPositive) {
counter.reset();
} else {
counter.increment();
}
if (isTrue) {
if (isPositive) {
s[TP]++;
} else {
s[FN]++;
}
} else if (isPositive) {
s[FP]++;
} else {
s[TN]++;
}
});
end();
}
return new ClassificationResult(s[TP], s[FP], s[TN], s[FN]);
}
use of uk.ac.sussex.gdsc.smlm.results.PeakResult in project GDSC-SMLM by aherbert.
the class PeakResultTableModel method createTableStructure.
/**
* Called when the structure of the table should be created. If the structure has not changed or
* no live table are attached then this does nothing.
*
* @param changed Set to true if a property controlling the structure has changed
*/
private void createTableStructure(boolean changed) {
if (changed) {
columnsComputed.set(false);
}
// so it can be turned off by PeakResultTableModelFrame.
if (liveCount.get() == 0 || columnsComputed.get()) {
return;
}
columnsComputed.set(true);
rounder = RounderUtils.create(tableSettings.getRoundingPrecision());
// Create the converters
final PeakResultConversionHelper helper = new PeakResultConversionHelper(calibration, psf);
helper.setIntensityUnit(tableSettings.getIntensityUnit());
helper.setDistanceUnit(tableSettings.getDistanceUnit());
helper.setAngleUnit(tableSettings.getAngleUnit());
final Converter[] converters = helper.getConverters();
final Converter ic = converters[PeakResult.INTENSITY];
final String[] paramNames = helper.getNames();
final String[] unitNames = helper.getUnitNames();
// Calibration tableCalibration = (helper.isCalibrationChanged()) ? helper.getCalibration() :
// calibration;
// Organise the data columns.
// This is done as per the IJTablePeakResults for consistency
final LocalList<PeakResultData<?>> valuesList = new LocalList<>();
final LocalList<String> namesList = new LocalList<>();
rowCounter = tableSettings.getShowRowCounter();
if (rowCounter) {
valuesList.add(new PeakResultDataFrame());
namesList.add("#");
}
valuesList.add(new PeakResultDataFrame());
addName(valuesList, namesList);
if (showEndFrame) {
valuesList.add(new PeakResultDataEndFrame());
addName(valuesList, namesList);
}
if (showId) {
valuesList.add(new PeakResultDataId());
addName(valuesList, namesList);
}
if (showCategory) {
valuesList.add(new PeakResultDataCategory());
addName(valuesList, namesList);
}
if (tableSettings.getShowFittingData()) {
valuesList.add(new PeakResultDataOrigX());
addName(valuesList, namesList);
valuesList.add(new PeakResultDataOrigY());
addName(valuesList, namesList);
valuesList.add(new PeakResultDataOrigValue());
addName(valuesList, namesList);
valuesList.add(new PeakResultDataError());
addName(valuesList, namesList);
}
if (tableSettings.getShowNoiseData()) {
// Must be converted
valuesList.add(new PeakResultDataFloat() {
@Override
public Float getValue(PeakResult result) {
return ic.convert(result.getNoise());
}
});
addName("Noise", namesList, unitNames[PeakResult.INTENSITY]);
valuesList.add(new PeakResultDataFloat() {
@Override
public Float getValue(PeakResult result) {
return ic.convert(result.getMeanIntensity());
}
});
addName("Mean" + paramNames[PeakResult.INTENSITY], namesList, unitNames[PeakResult.INTENSITY]);
valuesList.add(new PeakResultDataSnr());
addName(valuesList, namesList);
}
int[] outIndices = SimpleArrayUtils.natural(converters.length);
if (!showZ) {
final TIntArrayList list = new TIntArrayList(outIndices);
list.remove(PeakResult.Z);
outIndices = list.toArray();
}
for (final int i : outIndices) {
// Must be converted
valuesList.add(new PeakResultDataParameterConverter(converters[i], i));
addName(paramNames[i], namesList, unitNames[i]);
if (showDeviations) {
valuesList.add(new PeakResultDataParameterDeviationConverter(converters[i], i));
namesList.add("+/-");
}
}
if (tableSettings.getShowPrecision()) {
PeakResultDataPrecision precision = null;
try {
final Gaussian2DPeakResultCalculator calculator = Gaussian2DPeakResultHelper.create(getPsf(), calibration, Gaussian2DPeakResultHelper.LSE_PRECISION);
precision = new PeakResultDataPrecision() {
@Override
public Double getValue(PeakResult result) {
if (result.hasPrecision()) {
return result.getPrecision();
}
if (calculator != null) {
return calculator.getLsePrecision(result.getParameters(), result.getNoise());
}
return 0.0;
}
};
} catch (final ConfigurationException | ConversionException ex) {
// Ignore
}
if (precision == null) {
precision = new PeakResultDataPrecision();
}
valuesList.add(precision);
namesList.add("Precision (nm)");
}
values = valuesList.toArray(new PeakResultData<?>[0]);
names = namesList.toArray(new String[0]);
fireTableStructureChanged();
}
use of uk.ac.sussex.gdsc.smlm.results.PeakResult in project GDSC-SMLM by aherbert.
the class TcPalmAnalysis method createBurstLocalisations.
/**
* Creates the burst localisations using the ranges of the current bursts.
*
* @param clusters the clusters
* @param bursts the bursts
* @return the burst localisations
*/
private static LocalList<LocalList<PeakResult>> createBurstLocalisations(LocalList<ClusterData> clusters, LocalList<int[]> bursts) {
final LocalList<LocalList<PeakResult>> burstsLocalisations = new LocalList<>();
// TODO: Make more efficient. Order clusters by frame and burst by frame
// Do a single sweep over the clusters and extract the peaks within the burst ranges.
bursts.forEach(range -> {
final int min = range[0];
final int max = range[1];
final LocalList<PeakResult> list = new LocalList<>();
// Build from the current selection
clusters.forEach(cluster -> {
cluster.results.forEach(peak -> {
final int t = peak.getFrame();
if (t >= min && t <= max) {
list.add(peak);
}
});
});
burstsLocalisations.add(list);
});
return burstsLocalisations;
}
use of uk.ac.sussex.gdsc.smlm.results.PeakResult in project GDSC-SMLM by aherbert.
the class SpotInspector method run.
@Override
public void run(String arg) {
SmlmUsageTracker.recordPlugin(this.getClass(), arg);
if (MemoryPeakResults.isMemoryEmpty()) {
IJ.error(TITLE, "No localisations in memory");
return;
}
if (!showDialog()) {
return;
}
// Load the results
results = ResultsManager.loadInputResults(settings.inputOption, false, DistanceUnit.PIXEL, null);
if (MemoryPeakResults.isEmpty(results)) {
IJ.error(TITLE, "No results could be loaded");
IJ.showStatus("");
return;
}
// Check if the original image is open
ImageSource source = results.getSource();
if (source == null) {
IJ.error(TITLE, "Unknown original source image");
return;
}
source = source.getOriginal();
source.setReadHint(ReadHint.NONSEQUENTIAL);
if (!source.open()) {
IJ.error(TITLE, "Cannot open original source image: " + source.toString());
return;
}
final float stdDevMax = getStandardDeviation(results);
if (stdDevMax < 0) {
// TODO - Add dialog to get the initial peak width
IJ.error(TITLE, "Fitting configuration (for initial peak width) is not available");
return;
}
// Rank spots
rankedResults = new ArrayList<>(results.size());
// Data for the sorting
final PrecisionResultProcedure pp;
if (settings.sortOrderIndex == 1) {
pp = new PrecisionResultProcedure(results);
pp.getPrecision();
} else {
pp = null;
}
// Build procedures to get:
// Shift = position in pixels - originXY
final StandardResultProcedure sp;
if (settings.sortOrderIndex == 9) {
sp = new StandardResultProcedure(results, DistanceUnit.PIXEL);
sp.getXyr();
} else {
sp = null;
}
// SD = gaussian widths only for Gaussian PSFs
final WidthResultProcedure wp;
if (settings.sortOrderIndex >= 6 && settings.sortOrderIndex <= 8) {
wp = new WidthResultProcedure(results, DistanceUnit.PIXEL);
wp.getWxWy();
} else {
wp = null;
}
// Amplitude for Gaussian PSFs
final HeightResultProcedure hp;
if (settings.sortOrderIndex == 2) {
hp = new HeightResultProcedure(results, IntensityUnit.PHOTON);
hp.getH();
} else {
hp = null;
}
final Counter c = new Counter();
results.forEach((PeakResultProcedure) result -> {
final float[] score = getScore(result, c.getAndIncrement(), pp, sp, wp, hp, stdDevMax);
rankedResults.add(new PeakResultRank(result, score[0], score[1]));
});
Collections.sort(rankedResults, PeakResultRank::compare);
// Prepare results table
final ImageJTablePeakResults table = new ImageJTablePeakResults(false, results.getName(), true);
table.copySettings(results);
table.setTableTitle(TITLE);
table.setAddCounter(true);
table.setShowZ(results.is3D());
// TODO - Add to settings
table.setShowFittingData(true);
table.setShowNoiseData(true);
if (settings.showCalibratedValues) {
table.setDistanceUnit(DistanceUnit.NM);
table.setIntensityUnit(IntensityUnit.PHOTON);
} else {
table.setDistanceUnit(DistanceUnit.PIXEL);
table.setIntensityUnit(IntensityUnit.COUNT);
}
table.begin();
// Add a mouse listener to jump to the frame for the clicked line
textPanel = table.getResultsWindow().getTextPanel();
// We must ignore old instances of this class from the mouse listeners
id = currentId.incrementAndGet();
textPanel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent event) {
SpotInspector.this.mouseClicked(event);
}
});
// Add results to the table
int count = 0;
for (final PeakResultRank rank : rankedResults) {
rank.rank = count++;
table.add(rank.peakResult);
}
table.end();
if (settings.plotScore || settings.plotHistogram) {
// Get values for the plots
float[] xValues = null;
float[] yValues = null;
double yMin;
double yMax;
int spotNumber = 0;
xValues = new float[rankedResults.size()];
yValues = new float[xValues.length];
for (final PeakResultRank rank : rankedResults) {
xValues[spotNumber] = spotNumber + 1;
yValues[spotNumber++] = recoverScore(rank.score);
}
// Set the min and max y-values using 1.5 x IQR
final DescriptiveStatistics stats = new DescriptiveStatistics();
for (final float v : yValues) {
stats.addValue(v);
}
if (settings.removeOutliers) {
final double lower = stats.getPercentile(25);
final double upper = stats.getPercentile(75);
final double iqr = upper - lower;
yMin = Math.max(lower - iqr, stats.getMin());
yMax = Math.min(upper + iqr, stats.getMax());
IJ.log(String.format("Data range: %f - %f. Plotting 1.5x IQR: %f - %f", stats.getMin(), stats.getMax(), yMin, yMax));
} else {
yMin = stats.getMin();
yMax = stats.getMax();
IJ.log(String.format("Data range: %f - %f", yMin, yMax));
}
plotScore(xValues, yValues, yMin, yMax);
plotHistogram(yValues);
}
// Extract spots into a stack
final int w = source.getWidth();
final int h = source.getHeight();
final int size = 2 * settings.radius + 1;
final ImageStack spots = new ImageStack(size, size, rankedResults.size());
// To assist the extraction of data from the image source, process them in time order to allow
// frame caching. Then set the appropriate slice in the result stack
Collections.sort(rankedResults, (o1, o2) -> Integer.compare(o1.peakResult.getFrame(), o2.peakResult.getFrame()));
for (final PeakResultRank rank : rankedResults) {
final PeakResult r = rank.peakResult;
// Extract image
// Note that the coordinates are relative to the middle of the pixel (0.5 offset)
// so do not round but simply convert to int
final int x = (int) (r.getXPosition());
final int y = (int) (r.getYPosition());
// Extract a region but crop to the image bounds
int minX = x - settings.radius;
int minY = y - settings.radius;
final int maxX = Math.min(x + settings.radius + 1, w);
final int maxY = Math.min(y + settings.radius + 1, h);
int padX = 0;
int padY = 0;
if (minX < 0) {
padX = -minX;
minX = 0;
}
if (minY < 0) {
padY = -minY;
minY = 0;
}
final int sizeX = maxX - minX;
final int sizeY = maxY - minY;
float[] data = source.get(r.getFrame(), new Rectangle(minX, minY, sizeX, sizeY));
// Prevent errors with missing data
if (data == null) {
data = new float[sizeX * sizeY];
}
ImageProcessor spotIp = new FloatProcessor(sizeX, sizeY, data, null);
// Pad if necessary, i.e. the crop is too small for the stack
if (padX > 0 || padY > 0 || sizeX < size || sizeY < size) {
final ImageProcessor spotIp2 = spotIp.createProcessor(size, size);
spotIp2.insert(spotIp, padX, padY);
spotIp = spotIp2;
}
final int slice = rank.rank + 1;
spots.setPixels(spotIp.getPixels(), slice);
spots.setSliceLabel(MathUtils.rounded(rank.originalScore), slice);
}
source.close();
// Reset to the rank order
Collections.sort(rankedResults, PeakResultRank::compare);
final ImagePlus imp = ImageJUtils.display(TITLE, spots);
imp.setRoi((PointRoi) null);
// Make bigger
for (int i = 10; i-- > 0; ) {
imp.getWindow().getCanvas().zoomIn(imp.getWidth() / 2, imp.getHeight() / 2);
}
}
Aggregations