Search in sources :

Example 1 with BasePoint

use of gdsc.core.match.BasePoint in project GDSC-SMLM by aherbert.

the class PSFCreator method run.

/*
	 * (non-Javadoc)
	 * 
	 * @see ij.plugin.filter.PlugInFilter#run(ij.process.ImageProcessor)
	 */
public void run(ImageProcessor ip) {
    loadConfiguration();
    BasePoint[] spots = getSpots();
    if (spots.length == 0) {
        IJ.error(TITLE, "No spots without neighbours within " + (boxRadius * 2) + "px");
        return;
    }
    ImageStack stack = getImageStack();
    final int width = imp.getWidth();
    final int height = imp.getHeight();
    final int currentSlice = imp.getSlice();
    // Adjust settings for a single maxima
    config.setIncludeNeighbours(false);
    fitConfig.setDuplicateDistance(0);
    ArrayList<double[]> centres = new ArrayList<double[]>(spots.length);
    int iterations = 1;
    LoessInterpolator loess = new LoessInterpolator(smoothing, iterations);
    // TODO - The fitting routine may not produce many points. In this instance the LOESS interpolator
    // fails to smooth the data very well. A higher bandwidth helps this but perhaps 
    // try a different smoothing method.
    // For each spot
    Utils.log(TITLE + ": " + imp.getTitle());
    Utils.log("Finding spot locations...");
    Utils.log("  %d spot%s without neighbours within %dpx", spots.length, ((spots.length == 1) ? "" : "s"), (boxRadius * 2));
    StoredDataStatistics averageSd = new StoredDataStatistics();
    StoredDataStatistics averageA = new StoredDataStatistics();
    Statistics averageRange = new Statistics();
    MemoryPeakResults allResults = new MemoryPeakResults();
    allResults.setName(TITLE);
    allResults.setBounds(new Rectangle(0, 0, width, height));
    MemoryPeakResults.addResults(allResults);
    for (int n = 1; n <= spots.length; n++) {
        BasePoint spot = spots[n - 1];
        final int x = (int) spot.getX();
        final int y = (int) spot.getY();
        MemoryPeakResults results = fitSpot(stack, width, height, x, y);
        allResults.addAllf(results.getResults());
        if (results.size() < 5) {
            Utils.log("  Spot %d: Not enough fit results %d", n, results.size());
            continue;
        }
        // Get the results for the spot centre and width
        double[] z = new double[results.size()];
        double[] xCoord = new double[z.length];
        double[] yCoord = new double[z.length];
        double[] sd = new double[z.length];
        double[] a = new double[z.length];
        int i = 0;
        for (PeakResult peak : results.getResults()) {
            z[i] = peak.getFrame();
            xCoord[i] = peak.getXPosition() - x;
            yCoord[i] = peak.getYPosition() - y;
            sd[i] = FastMath.max(peak.getXSD(), peak.getYSD());
            a[i] = peak.getAmplitude();
            i++;
        }
        // Smooth the amplitude plot
        double[] smoothA = loess.smooth(z, a);
        // Find the maximum amplitude
        int maximumIndex = findMaximumIndex(smoothA);
        // Find the range at a fraction of the max. This is smoothed to find the X/Y centre
        int start = 0, stop = smoothA.length - 1;
        double limit = smoothA[maximumIndex] * amplitudeFraction;
        for (int j = 0; j < smoothA.length; j++) {
            if (smoothA[j] > limit) {
                start = j;
                break;
            }
        }
        for (int j = smoothA.length; j-- > 0; ) {
            if (smoothA[j] > limit) {
                stop = j;
                break;
            }
        }
        averageRange.add(stop - start + 1);
        // Extract xy centre coords and smooth
        double[] smoothX = new double[stop - start + 1];
        double[] smoothY = new double[smoothX.length];
        double[] smoothSd = new double[smoothX.length];
        double[] newZ = new double[smoothX.length];
        for (int j = start, k = 0; j <= stop; j++, k++) {
            smoothX[k] = xCoord[j];
            smoothY[k] = yCoord[j];
            smoothSd[k] = sd[j];
            newZ[k] = z[j];
        }
        smoothX = loess.smooth(newZ, smoothX);
        smoothY = loess.smooth(newZ, smoothY);
        smoothSd = loess.smooth(newZ, smoothSd);
        // Since the amplitude is not very consistent move from this peak to the 
        // lowest width which is the in-focus spot.
        maximumIndex = findMinimumIndex(smoothSd, maximumIndex - start);
        // Find the centre at the amplitude peak
        double cx = smoothX[maximumIndex] + x;
        double cy = smoothY[maximumIndex] + y;
        int cz = (int) newZ[maximumIndex];
        double csd = smoothSd[maximumIndex];
        double ca = smoothA[maximumIndex + start];
        // The average should weight the SD using the signal for each spot
        averageSd.add(smoothSd[maximumIndex]);
        averageA.add(ca);
        if (ignoreSpot(n, z, a, smoothA, xCoord, yCoord, sd, newZ, smoothX, smoothY, smoothSd, cx, cy, cz, csd)) {
            Utils.log("  Spot %d was ignored", n);
            continue;
        }
        // Store result - it may have been moved interactively
        maximumIndex += this.slice - cz;
        cz = (int) newZ[maximumIndex];
        csd = smoothSd[maximumIndex];
        ca = smoothA[maximumIndex + start];
        Utils.log("  Spot %d => x=%.2f, y=%.2f, z=%d, sd=%.2f, A=%.2f\n", n, cx, cy, cz, csd, ca);
        centres.add(new double[] { cx, cy, cz, csd, n });
    }
    if (interactiveMode) {
        imp.setSlice(currentSlice);
        imp.setOverlay(null);
        // Hide the amplitude and spot plots
        Utils.hide(TITLE_AMPLITUDE);
        Utils.hide(TITLE_PSF_PARAMETERS);
    }
    if (centres.isEmpty()) {
        String msg = "No suitable spots could be identified centres";
        Utils.log(msg);
        IJ.error(TITLE, msg);
        return;
    }
    // Find the limits of the z-centre
    int minz = (int) centres.get(0)[2];
    int maxz = minz;
    for (double[] centre : centres) {
        if (minz > centre[2])
            minz = (int) centre[2];
        else if (maxz < centre[2])
            maxz = (int) centre[2];
    }
    IJ.showStatus("Creating PSF image");
    // Create a stack that can hold all the data.
    ImageStack psf = createStack(stack, minz, maxz, magnification);
    // For each spot
    Statistics stats = new Statistics();
    boolean ok = true;
    for (int i = 0; ok && i < centres.size(); i++) {
        double progress = (double) i / centres.size();
        final double increment = 1.0 / (stack.getSize() * centres.size());
        IJ.showProgress(progress);
        double[] centre = centres.get(i);
        // Extract the spot
        float[][] spot = new float[stack.getSize()][];
        Rectangle regionBounds = null;
        for (int slice = 1; slice <= stack.getSize(); slice++) {
            ImageExtractor ie = new ImageExtractor((float[]) stack.getPixels(slice), width, height);
            if (regionBounds == null)
                regionBounds = ie.getBoxRegionBounds((int) centre[0], (int) centre[1], boxRadius);
            spot[slice - 1] = ie.crop(regionBounds);
        }
        int n = (int) centre[4];
        final float b = getBackground(n, spot);
        if (!subtractBackgroundAndWindow(spot, b, regionBounds.width, regionBounds.height, centre, loess)) {
            Utils.log("  Spot %d was ignored", n);
            continue;
        }
        stats.add(b);
        // Adjust the centre using the crop
        centre[0] -= regionBounds.x;
        centre[1] -= regionBounds.y;
        // This takes a long time so this should track progress
        ok = addToPSF(maxz, magnification, psf, centre, spot, regionBounds, progress, increment, centreEachSlice);
    }
    if (interactiveMode) {
        Utils.hide(TITLE_INTENSITY);
    }
    IJ.showProgress(1);
    if (threadPool != null) {
        threadPool.shutdownNow();
        threadPool = null;
    }
    if (!ok || stats.getN() == 0)
        return;
    final double avSd = getAverage(averageSd, averageA, 2);
    Utils.log("  Average background = %.2f, Av. SD = %s px", stats.getMean(), Utils.rounded(avSd, 4));
    normalise(psf, maxz, avSd * magnification, false);
    IJ.showProgress(1);
    psfImp = Utils.display("PSF", psf);
    psfImp.setSlice(maxz);
    psfImp.resetDisplayRange();
    psfImp.updateAndDraw();
    double[][] fitCom = new double[2][psf.getSize()];
    Arrays.fill(fitCom[0], Double.NaN);
    Arrays.fill(fitCom[1], Double.NaN);
    double fittedSd = fitPSF(psf, loess, maxz, averageRange.getMean(), fitCom);
    // Compute the drift in the PSF:
    // - Use fitted centre if available; otherwise find CoM for each frame
    // - express relative to the average centre
    double[][] com = calculateCentreOfMass(psf, fitCom, nmPerPixel / magnification);
    double[] slice = Utils.newArray(psf.getSize(), 1, 1.0);
    String title = TITLE + " CoM Drift";
    Plot2 plot = new Plot2(title, "Slice", "Drift (nm)");
    plot.addLabel(0, 0, "Red = X; Blue = Y");
    //double[] limitsX = Maths.limits(com[0]);
    //double[] limitsY = Maths.limits(com[1]);
    double[] limitsX = getLimits(com[0]);
    double[] limitsY = getLimits(com[1]);
    plot.setLimits(1, psf.getSize(), Math.min(limitsX[0], limitsY[0]), Math.max(limitsX[1], limitsY[1]));
    plot.setColor(Color.red);
    plot.addPoints(slice, com[0], Plot.DOT);
    plot.addPoints(slice, loess.smooth(slice, com[0]), Plot.LINE);
    plot.setColor(Color.blue);
    plot.addPoints(slice, com[1], Plot.DOT);
    plot.addPoints(slice, loess.smooth(slice, com[1]), Plot.LINE);
    Utils.display(title, plot);
    // TODO - Redraw the PSF with drift correction applied. 
    // This means that the final image should have no drift.
    // This is relevant when combining PSF images. It doesn't matter too much for simulations 
    // unless the drift is large.
    // Add Image properties containing the PSF details
    final double fwhm = getFWHM(psf, maxz);
    psfImp.setProperty("Info", XmlUtils.toXML(new PSFSettings(maxz, nmPerPixel / magnification, nmPerSlice, stats.getN(), fwhm, createNote())));
    Utils.log("%s : z-centre = %d, nm/Pixel = %s, nm/Slice = %s, %d images, PSF SD = %s nm, FWHM = %s px\n", psfImp.getTitle(), maxz, Utils.rounded(nmPerPixel / magnification, 3), Utils.rounded(nmPerSlice, 3), stats.getN(), Utils.rounded(fittedSd * nmPerPixel, 4), Utils.rounded(fwhm));
    createInteractivePlots(psf, maxz, nmPerPixel / magnification, fittedSd * nmPerPixel);
    IJ.showStatus("");
}
Also used : ImageStack(ij.ImageStack) BasePoint(gdsc.core.match.BasePoint) ArrayList(java.util.ArrayList) StoredDataStatistics(gdsc.core.utils.StoredDataStatistics) Rectangle(java.awt.Rectangle) Plot2(ij.gui.Plot2) Statistics(gdsc.core.utils.Statistics) StoredDataStatistics(gdsc.core.utils.StoredDataStatistics) DescriptiveStatistics(org.apache.commons.math3.stat.descriptive.DescriptiveStatistics) Point(java.awt.Point) BasePoint(gdsc.core.match.BasePoint) PeakResult(gdsc.smlm.results.PeakResult) LoessInterpolator(org.apache.commons.math3.analysis.interpolation.LoessInterpolator) MemoryPeakResults(gdsc.smlm.results.MemoryPeakResults) ImageExtractor(gdsc.core.utils.ImageExtractor) PSFSettings(gdsc.smlm.ij.settings.PSFSettings)

Example 2 with BasePoint

use of gdsc.core.match.BasePoint in project GDSC-SMLM by aherbert.

the class SpotFinderPreview method run.

/*
	 * (non-Javadoc)
	 * 
	 * @see ij.plugin.filter.PlugInFilter#run(ij.process.ImageProcessor)
	 */
public void run(ImageProcessor ip) {
    Rectangle bounds = ip.getRoi();
    MaximaSpotFilter filter = config.createSpotFilter(true);
    // Crop to the ROI
    FloatProcessor fp = ip.crop().toFloat(0, null);
    float[] data = (float[]) fp.getPixels();
    int width = fp.getWidth();
    int height = fp.getHeight();
    Spot[] spots = filter.rank(data, width, height);
    data = filter.getPreprocessedData();
    fp = new FloatProcessor(width, height, data);
    ip = ip.duplicate();
    ip.insert(fp, bounds.x, bounds.y);
    //ip.resetMinAndMax();
    ip.setMinAndMax(fp.getMin(), fp.getMax());
    Overlay o = new Overlay();
    o.add(new ImageRoi(0, 0, ip));
    if (label != null) {
        // Get results for frame
        Coordinate[] actual = ResultsMatchCalculator.getCoordinates(actualCoordinates, imp.getCurrentSlice());
        Coordinate[] predicted = new Coordinate[spots.length];
        for (int i = 0; i < spots.length; i++) {
            predicted[i] = new BasePoint(spots[i].x + bounds.x, spots[i].y + bounds.y);
        }
        // Q. Should this use partial scoring with multi-matches allowed.
        // If so then this needs to be refactored out of the BenchmarkSpotFilter class.
        // TODO - compute AUC and max jaccard and plot			
        // Compute matches
        List<PointPair> matches = new ArrayList<PointPair>(Math.min(actual.length, predicted.length));
        List<Coordinate> FP = new ArrayList<Coordinate>(predicted.length);
        MatchResult result = MatchCalculator.analyseResults2D(actual, predicted, distance * fitConfig.getInitialPeakStdDev0(), null, FP, null, matches);
        // Show scores
        setLabel(String.format("P=%s, R=%s, J=%s", Utils.rounded(result.getPrecision()), Utils.rounded(result.getRecall()), Utils.rounded(result.getJaccard())));
        // Create Rois for TP and FP
        if (showTP) {
            float[] x = new float[matches.size()];
            float[] y = new float[x.length];
            int n = 0;
            for (PointPair pair : matches) {
                BasePoint p = (BasePoint) pair.getPoint2();
                x[n] = p.getX() + 0.5f;
                y[n] = p.getY() + 0.5f;
                n++;
            }
            addRoi(0, o, x, y, n, Color.green);
        }
        if (showFP) {
            float[] x = new float[predicted.length - matches.size()];
            float[] y = new float[x.length];
            int n = 0;
            for (Coordinate c : FP) {
                BasePoint p = (BasePoint) c;
                x[n] = p.getX() + 0.5f;
                y[n] = p.getY() + 0.5f;
                n++;
            }
            addRoi(0, o, x, y, n, Color.red);
        }
    } else {
        float[] x = new float[spots.length];
        float[] y = new float[x.length];
        for (int i = 0; i < spots.length; i++) {
            x[i] = spots[i].x + bounds.x + 0.5f;
            y[i] = spots[i].y + bounds.y + 0.5f;
        }
        PointRoi roi = new PointRoi(x, y);
        // Add options to configure colour and labels
        o.add(roi);
    }
    imp.setOverlay(o);
}
Also used : FloatProcessor(ij.process.FloatProcessor) Spot(gdsc.smlm.filters.Spot) BasePoint(gdsc.core.match.BasePoint) Rectangle(java.awt.Rectangle) ArrayList(java.util.ArrayList) ImageRoi(ij.gui.ImageRoi) MatchResult(gdsc.core.match.MatchResult) BasePoint(gdsc.core.match.BasePoint) Coordinate(gdsc.core.match.Coordinate) MaximaSpotFilter(gdsc.smlm.filters.MaximaSpotFilter) PointPair(gdsc.core.match.PointPair) Overlay(ij.gui.Overlay) PointRoi(ij.gui.PointRoi)

Example 3 with BasePoint

use of gdsc.core.match.BasePoint in project GDSC-SMLM by aherbert.

the class PSFCreator method getSpots.

/**
	 * @return Extract all the ROI points that are not within twice the box radius of any other spot
	 */
private BasePoint[] getSpots() {
    Roi roi = imp.getRoi();
    if (roi != null && roi.getType() == Roi.POINT) {
        Polygon p = ((PolygonRoi) roi).getNonSplineCoordinates();
        int n = p.npoints;
        Rectangle bounds = roi.getBounds();
        BasePoint[] roiPoints = new BasePoint[n];
        for (int i = 0; i < n; i++) {
            roiPoints[i] = new BasePoint(bounds.x + p.xpoints[i], bounds.y + p.ypoints[i], 0);
        }
        // All vs all distance matrix
        double[][] d = new double[n][n];
        for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++) d[i][j] = d[j][i] = roiPoints[i].distanceXY2(roiPoints[j]);
        // Spots must be twice as far apart to have no overlap of the extracted box region
        double d2 = boxRadius * boxRadius * 4;
        int ok = 0;
        for (int i = 0; i < n; i++) {
            if (noNeighbours(d, n, i, d2))
                roiPoints[ok++] = roiPoints[i];
        }
        return Arrays.copyOf(roiPoints, ok);
    }
    return new BasePoint[0];
}
Also used : PolygonRoi(ij.gui.PolygonRoi) BasePoint(gdsc.core.match.BasePoint) Rectangle(java.awt.Rectangle) Polygon(java.awt.Polygon) Roi(ij.gui.Roi) PolygonRoi(ij.gui.PolygonRoi) Point(java.awt.Point) BasePoint(gdsc.core.match.BasePoint)

Aggregations

BasePoint (gdsc.core.match.BasePoint)3 Rectangle (java.awt.Rectangle)3 Point (java.awt.Point)2 ArrayList (java.util.ArrayList)2 Coordinate (gdsc.core.match.Coordinate)1 MatchResult (gdsc.core.match.MatchResult)1 PointPair (gdsc.core.match.PointPair)1 ImageExtractor (gdsc.core.utils.ImageExtractor)1 Statistics (gdsc.core.utils.Statistics)1 StoredDataStatistics (gdsc.core.utils.StoredDataStatistics)1 MaximaSpotFilter (gdsc.smlm.filters.MaximaSpotFilter)1 Spot (gdsc.smlm.filters.Spot)1 PSFSettings (gdsc.smlm.ij.settings.PSFSettings)1 MemoryPeakResults (gdsc.smlm.results.MemoryPeakResults)1 PeakResult (gdsc.smlm.results.PeakResult)1 ImageStack (ij.ImageStack)1 ImageRoi (ij.gui.ImageRoi)1 Overlay (ij.gui.Overlay)1 Plot2 (ij.gui.Plot2)1 PointRoi (ij.gui.PointRoi)1