use of uk.ac.sussex.gdsc.smlm.results.PeakResult in project GDSC-SMLM by aherbert.
the class ImageJ3DResultsViewer method createSphereSizeFromDeviations.
@Nullable
private static Point3f[] createSphereSizeFromDeviations(MemoryPeakResults results) {
if (!results.hasDeviations()) {
IJ.error(TITLE, "The results have no deviations");
return null;
}
// Currently the rendering is in nm
final TypeConverter<DistanceUnit> dc = results.getDistanceConverter(DistanceUnit.NM);
final Point3f[] size = new Point3f[results.size()];
final boolean failed = results.forEach(new PeakResultProcedureX() {
int index;
@Override
public boolean execute(PeakResult peakResult) {
final float x = peakResult.getParameterDeviation(PeakResult.X);
final float y = peakResult.getParameterDeviation(PeakResult.Y);
float z = peakResult.getParameterDeviation(PeakResult.Z);
// This should be OK as 2D fitting should provide these.
if (x == 0 || y == 0) {
return true;
}
if (z == 0) {
// Mean variance
z = (float) Math.sqrt((x * x + y * y) / 2);
}
// z = (x + y) / 2; // Mean Std Dev
size[index++] = new Point3f(dc.convert(x), dc.convert(y), dc.convert(z));
return false;
}
});
return (failed) ? null : size;
}
use of uk.ac.sussex.gdsc.smlm.results.PeakResult in project GDSC-SMLM by aherbert.
the class ImageJ3DResultsViewer method reorder.
private static void reorder(int[] indices, ResultsMetaData data) {
final MemoryPeakResults results = data.results;
final LocalList<Point3f> points = data.points;
final PeakResult[] originalPeakResults = results.toArray();
final Point3f[] originalPoints = points.toArray(new Point3f[0]);
// We need another array to store the output
final PeakResult[] peakResults = new PeakResult[originalPeakResults.length];
// Rewrite order
for (int i = 0; i < indices.length; i++) {
final int index = indices[i];
points.unsafeSet(i, originalPoints[index]);
peakResults[i] = originalPeakResults[index];
}
// Bulk update the results
results.setSortAfterEnd(false);
results.begin();
results.addAll(peakResults);
results.end();
final Point3f[] sizes = data.sizes;
if (sizes.length == indices.length) {
final Point3f[] originalSizes = sizes.clone();
// Rewrite order
for (int i = 0; i < indices.length; i++) {
final int index = indices[i];
sizes[i] = originalSizes[index];
}
}
}
use of uk.ac.sussex.gdsc.smlm.results.PeakResult in project GDSC-SMLM by aherbert.
the class FilterResults method filterResults.
/**
* Apply the filters to the data.
*/
private void filterResults() {
checkLimits();
final MemoryPeakResults newResults = new MemoryPeakResults();
newResults.copySettings(results);
newResults.setName(results.getName() + " Filtered");
// Initialise the mask
CoordFilter maskFilter;
final ImagePlus maskImp = WindowManager.getImage(filterSettings.getMaskTitle());
if (maskImp != null) {
final int maxx = maskImp.getWidth();
final int maxy = maskImp.getHeight();
final Rectangle bounds = results.getBounds();
final double ox = bounds.getX();
final double oy = bounds.getY();
final double scaleX = bounds.getWidth() / maxx;
final double scaleY = bounds.getHeight() / maxy;
// Improve to allow stacks
if (maskImp.getStackSize() > 1) {
// 3D filter. The frame is mapped to the stack index.
final ImageStack stack = maskImp.getImageStack();
final ImageProcessor ip = stack.getProcessor(1);
maskFilter = (t, x, y) -> {
// Check stack index
if (t >= 1 && t <= stack.size()) {
int ix = (int) ((x - ox) / scaleX);
int iy = (int) ((y - oy) / scaleY);
if (ix >= 0 && ix < maxx && iy >= 0 && iy < maxy) {
ip.setPixels(stack.getPixels(t));
return ip.get(iy * maxx + ix) != 0;
}
}
return false;
};
} else {
// 2D filter.
final ImageProcessor ip = maskImp.getProcessor();
maskFilter = (t, x, y) -> {
int ix = (int) ((x - ox) / scaleX);
int iy = (int) ((y - oy) / scaleY);
return (ix >= 0 && ix < maxx && iy >= 0 && iy < maxy && ip.get(iy * maxx + ix) != 0);
};
}
} else {
maskFilter = (t, x, y) -> true;
}
// Create the ticker with size+1 as we tick at the start of the loop
final Ticker ticker = ImageJUtils.createTicker(results.size() + 1, 0);
for (int i = 0, size = results.size(); i < size; i++) {
ticker.tick();
// We stored the drift=z, intensity=signal, background=snr
if (sp.z[i] > filterSettings.getMaxDrift()) {
continue;
}
if (sp.intensity[i] < filterSettings.getMinSignal()) {
continue;
}
if (sp.background[i] < filterSettings.getMinSnr()) {
continue;
}
final PeakResult peakResult = sp.peakResults[i];
// Check the coordinates are inside the mask
if (!maskFilter.match(peakResult.getFrame(), sp.x[i], sp.y[i])) {
continue;
}
if (pp != null && pp.precisions[i] > maxPrecision) {
continue;
}
if (wp != null) {
final float width = wp.wx[i];
if (width < filterSettings.getMinWidth() || width > filterSettings.getMaxWidth()) {
continue;
}
}
// Passed all filters. Add to the results
newResults.add(peakResult);
}
ImageJUtils.finished(TextUtils.pleural(newResults.size(), "Filtered localisation"));
MemoryPeakResults.addResults(newResults);
}
use of uk.ac.sussex.gdsc.smlm.results.PeakResult in project GDSC-SMLM by aherbert.
the class FilterResults method analyseResults.
/**
* Analyse the results and determine the range for each filter.
*/
private boolean analyseResults() {
IJ.showStatus("Analysing results ...");
final ArrayList<String> error = new ArrayList<>();
try {
wp = new WidthResultProcedure(results, DistanceUnit.PIXEL);
wp.getW();
final float[] limits = MathUtils.limits(wp.wx);
maxWidth = limits[1];
minWidth = limits[0];
averageWidth = MathUtils.sum(wp.wx) / wp.size();
} catch (final DataException ex) {
error.add(ex.getMessage());
wp = null;
maxWidth = minWidth = 0;
}
try {
pp = new PrecisionResultProcedure(results);
pp.getPrecision();
final double[] limits = MathUtils.limits(pp.precisions);
maxPrecision = limits[1];
minPrecision = limits[0];
} catch (final DataException ex) {
error.add(ex.getMessage());
pp = null;
maxPrecision = minPrecision = 0;
}
try {
sp = new StandardResultProcedure(results, DistanceUnit.PIXEL);
sp.getXyr();
// Re-use for convenience
sp.intensity = new float[sp.x.length];
sp.background = new float[sp.x.length];
sp.z = new float[sp.x.length];
for (int i = 0; i < sp.size(); i++) {
if (i % 64 == 0) {
IJ.showProgress(i, sp.size());
}
final PeakResult result = sp.peakResults[i];
final float drift = getDrift(result, sp.x[i], sp.y[i]);
if (maxDrift < drift) {
maxDrift = drift;
}
if (minDrift > drift) {
minDrift = drift;
}
final float signal = result.getIntensity();
if (maxSignal < signal) {
maxSignal = signal;
}
if (minSignal > signal) {
minSignal = signal;
}
final float snr = getSnr(result);
if (maxSnr < snr) {
maxSnr = snr;
}
if (minSnr > snr) {
minSnr = snr;
}
// for convenience
sp.z[i] = drift;
sp.intensity[i] = signal;
sp.background[i] = snr;
}
} catch (final DataException ex) {
error.add(ex.getMessage());
sp = null;
}
if (error.size() == 3 || sp == null) {
final StringBuilder sb = new StringBuilder("Unable to analyse the results:\n");
for (final String s : error) {
sb.append(s).append(".\n");
}
IJ.error(TITLE, sb.toString());
return false;
}
ImageJUtils.finished();
return true;
}
use of uk.ac.sussex.gdsc.smlm.results.PeakResult in project GDSC-SMLM by aherbert.
the class DrawClusters 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
final MemoryPeakResults results = ResultsManager.loadInputResults(settings.inputOption, false, DistanceUnit.PIXEL);
if (MemoryPeakResults.isEmpty(results)) {
IJ.error(TITLE, "No results could be loaded");
return;
}
// Get the traces
final Trace[] traces = TraceManager.convert(results);
if (traces == null || traces.length == 0) {
IJ.error(TITLE, "No traces could be loaded");
return;
}
// Filter traces to a min size
int maxFrame = 0;
int count = 0;
final int myMaxSize = (settings.maxSize < settings.minSize) ? Integer.MAX_VALUE : settings.maxSize;
final boolean myDrawLines = myMaxSize > 1 && settings.drawLines;
for (int i = 0; i < traces.length; i++) {
if (settings.expandToSingles) {
traces[i].expandToSingles();
}
if (traces[i].size() >= settings.minSize && traces[i].size() <= myMaxSize) {
traces[count++] = traces[i];
traces[i].sort();
if (maxFrame < traces[i].getTail().getFrame()) {
maxFrame = traces[i].getTail().getFrame();
}
}
}
if (count == 0) {
IJ.error(TITLE, "No traces achieved the size limits");
return;
}
final String msg = String.format(TITLE + ": %d / %s (%s)", count, TextUtils.pleural(traces.length, "trace"), TextUtils.pleural(results.size(), "localisation"));
IJ.showStatus(msg);
final Rectangle bounds = results.getBounds(true);
ImagePlus imp = WindowManager.getImage(settings.title);
boolean isUseStackPosition = settings.useStackPosition;
if (imp == null) {
// Create a default image using 100 pixels as the longest edge
final double maxD = (bounds.width > bounds.height) ? bounds.width : bounds.height;
int width;
int height;
if (maxD == 0) {
// Note that imageSize can be zero (for auto sizing)
width = height = (settings.imageSize == 0) ? 20 : settings.imageSize;
} else if (settings.imageSize == 0) {
// Note that imageSize can be zero (for auto sizing)
width = bounds.width;
height = bounds.height;
} else {
width = (int) (settings.imageSize * bounds.width / maxD);
height = (int) (settings.imageSize * bounds.height / maxD);
}
final ByteProcessor bp = new ByteProcessor(width, height);
if (isUseStackPosition) {
final ImageStack stack = new ImageStack(width, height, maxFrame);
for (int i = 1; i <= maxFrame; i++) {
// Do not clone as the image is empty
stack.setPixels(bp.getPixels(), i);
}
imp = ImageJUtils.display(TITLE, stack);
} else {
imp = ImageJUtils.display(TITLE, bp);
}
// Enlarge
final ImageWindow iw = imp.getWindow();
for (int i = 9; i-- > 0 && iw.getWidth() < 500 && iw.getHeight() < 500; ) {
iw.getCanvas().zoomIn(imp.getWidth() / 2, imp.getHeight() / 2);
}
// Check if the image has enough frames for all the traces
} else if (maxFrame > imp.getNFrames()) {
isUseStackPosition = false;
}
final float xScale = (float) (imp.getWidth() / bounds.getWidth());
final float yScale = (float) (imp.getHeight() / bounds.getHeight());
// Create ROIs and store data to sort them
final Roi[] rois = new Roi[count];
final int[][] frames = (isUseStackPosition) ? new int[count][] : null;
final int[] indices = SimpleArrayUtils.natural(count);
final double[] values = new double[count];
for (int i = 0; i < count; i++) {
final Trace trace = traces[i];
final int npoints = trace.size();
final float[] xpoints = new float[npoints];
final float[] ypoints = new float[npoints];
int ii = 0;
if (frames != null) {
frames[i] = new int[npoints];
}
for (int k = 0; k < trace.size(); k++) {
final PeakResult result = trace.get(k);
xpoints[ii] = (result.getXPosition() - bounds.x) * xScale;
ypoints[ii] = (result.getYPosition() - bounds.y) * yScale;
if (frames != null) {
frames[i][ii] = result.getFrame();
}
ii++;
}
Roi roi;
if (myDrawLines) {
roi = new PolygonRoi(xpoints, ypoints, npoints, Roi.POLYLINE);
if (settings.splineFit) {
((PolygonRoi) roi).fitSpline();
}
} else {
roi = new OffsetPointRoi(xpoints, ypoints, npoints);
((PointRoi) roi).setShowLabels(false);
}
rois[i] = roi;
switch(settings.sort) {
case // Sort by ID
1:
values[i] = traces[i].getId();
break;
case // Sort by time
2:
values[i] = traces[i].getHead().getFrame();
break;
case // Sort by size descending
3:
values[i] = -traces[i].size();
break;
case // Sort by length descending
4:
values[i] = -roi.getLength();
break;
case // Mean Square Displacement
5:
values[i] = -traces[i].getMsd();
break;
case // Mean / Frame
6:
values[i] = -traces[i].getMeanDistance();
break;
// No sort
case 0:
default:
break;
}
}
if (settings.sort > 0) {
SortUtils.sortIndices(indices, values, true);
}
// Draw the traces as ROIs on an overlay
final Overlay o = new Overlay();
final LUT lut = LutHelper.createLut(settings.lut);
final double scale = 256.0 / count;
if (frames != null) {
// Add the tracks on the frames containing the results
final boolean isHyperStack = imp.isDisplayedHyperStack();
for (int i = 0; i < count; i++) {
final int index = indices[i];
final Color c = LutHelper.getColour(lut, (int) (i * scale));
final PolygonRoi roi = (PolygonRoi) rois[index];
roi.setFillColor(c);
roi.setStrokeColor(c);
// roi.setStrokeWidth(settings.lineWidth);
roi.updateWideLine(settings.lineWidth);
final FloatPolygon fp = roi.getNonSplineFloatPolygon();
// For each frame in the track, add the ROI track and a point ROI for the current position
for (int j = 0; j < frames[index].length; j++) {
addToOverlay(o, (Roi) roi.clone(), isHyperStack, frames[index][j]);
final PointRoi pointRoi = new OffsetPointRoi(fp.xpoints[j], fp.ypoints[j]);
pointRoi.setPointType(3);
pointRoi.setFillColor(c);
pointRoi.setStrokeColor(Color.black);
addToOverlay(o, pointRoi, isHyperStack, frames[index][j]);
}
}
} else {
// Add the tracks as a single overlay
for (int i = 0; i < count; i++) {
final Roi roi = rois[indices[i]];
roi.setStrokeColor(new Color(lut.getRGB((int) (i * scale))));
// roi.setStrokeWidth(settings.lineWidth);
roi.updateWideLine(settings.lineWidth);
o.add(roi);
}
}
imp.setOverlay(o);
IJ.showStatus(msg);
}
Aggregations